diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index ec76a1a42ef09..8612a40923a8d 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -27,3 +27,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8 84ac80f1921afc243d71fd0caaa4f2838c294102 # bless mir-opt tests to add `copy` 99cb0c6bc399fb94a0ddde7e9b38e9c00d523bad +# reformat with rustfmt edition 2024 +c682aa162b0d41e21cc6748f4fecfe01efb69d1f diff --git a/.gitmodules b/.gitmodules index b5250d493864e..33ea0f53cf132 100644 --- a/.gitmodules +++ b/.gitmodules @@ -33,7 +33,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/19.1-2024-07-30 + branch = rustc/19.1-2024-09-17 shallow = true [submodule "src/doc/embedded-book"] path = src/doc/embedded-book @@ -47,3 +47,11 @@ path = src/tools/rustc-perf url = https://github.com/rust-lang/rustc-perf.git shallow = true +[submodule "src/tools/enzyme"] + path = src/tools/enzyme + url = https://github.com/EnzymeAD/Enzyme.git + shallow = true +[submodule "src/gcc"] + path = src/gcc + url = https://github.com/rust-lang/gcc.git + shallow = true diff --git a/.mailmap b/.mailmap index 4d93792422c23..9ac7f1a9b494c 100644 --- a/.mailmap +++ b/.mailmap @@ -81,6 +81,7 @@ boolean_coercion Boris Egorov bors bors[bot] <26634292+bors[bot]@users.noreply.github.com> bors bors[bot] +Boxy Braden Nelson Brandon Sanderson Brandon Sanderson Brett Cannon Brett Cannon @@ -146,6 +147,7 @@ David Klein David Manescu David Ross David Wood +David Wood Deadbeef Deadbeef dependabot[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> diff --git a/Cargo.lock b/Cargo.lock index 7244ae14fb8da..5e9808c806884 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,15 +104,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anstream" version = "0.6.15" @@ -199,7 +190,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" dependencies = [ - "object 0.36.3", + "object 0.36.4", ] [[package]] @@ -533,7 +524,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clippy" -version = "0.1.82" +version = "0.1.83" dependencies = [ "anstream", "cargo_metadata 0.18.1", @@ -556,13 +547,13 @@ dependencies = [ "termize", "tokio", "toml 0.7.8", - "ui_test 0.25.0", + "ui_test", "walkdir", ] [[package]] name = "clippy_config" -version = "0.1.82" +version = "0.1.83" dependencies = [ "itertools", "serde", @@ -585,7 +576,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.82" +version = "0.1.83" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -609,7 +600,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.82" +version = "0.1.83" dependencies = [ "arrayvec", "clippy_config", @@ -714,7 +705,7 @@ dependencies = [ "miow", "miropt-test-tools", "regex", - "rustfix 0.8.1", + "rustfix", "serde", "serde_json", "tracing", @@ -911,7 +902,7 @@ dependencies = [ [[package]] name = "declare_clippy_lint" -version = "0.1.82" +version = "0.1.83" dependencies = [ "itertools", "quote", @@ -2186,9 +2177,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -2278,7 +2269,7 @@ dependencies = [ "rustc_version", "smallvec", "tempfile", - "ui_test 0.21.2", + "ui_test", "windows-sys 0.52.0", ] @@ -2453,9 +2444,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "crc32fast", "flate2", @@ -2463,7 +2454,7 @@ dependencies = [ "indexmap", "memchr", "ruzstd 0.7.0", - "wasmparser 0.215.0", + "wasmparser", ] [[package]] @@ -2807,16 +2798,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "prettydiff" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff1fec61082821f8236cf6c0c14e8172b62ce8a72a0eedc30d3b247bb68dc11" -dependencies = [ - "ansi_term", - "pad", -] - [[package]] name = "prettydiff" version = "0.7.0" @@ -3129,11 +3110,11 @@ dependencies = [ "build_helper", "gimli 0.31.0", "libc", - "object 0.36.3", + "object 0.36.4", "regex", "serde_json", "similar", - "wasmparser 0.216.0", + "wasmparser", ] [[package]] @@ -3408,7 +3389,7 @@ dependencies = [ "itertools", "libc", "measureme", - "object 0.36.3", + "object 0.36.4", "rustc-demangle", "rustc_ast", "rustc_attr", @@ -3447,7 +3428,7 @@ dependencies = [ "itertools", "jobserver", "libc", - "object 0.36.3", + "object 0.36.4", "pathdiff", "regex", "rustc_arena", @@ -3569,6 +3550,7 @@ dependencies = [ "rustc_hir_pretty", "rustc_hir_typeck", "rustc_incremental", + "rustc_index", "rustc_infer", "rustc_interface", "rustc_lint", @@ -4166,6 +4148,7 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_fluent_macro", + "rustc_index", "rustc_lexer", "rustc_macros", "rustc_session", @@ -4431,7 +4414,7 @@ name = "rustc_target" version = "0.0.0" dependencies = [ "bitflags 2.6.0", - "object 0.36.3", + "object 0.36.4", "rustc_abi", "rustc_data_structures", "rustc_feature", @@ -4623,18 +4606,6 @@ dependencies = [ "rustdoc", ] -[[package]] -name = "rustfix" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481" -dependencies = [ - "anyhow", - "log", - "serde", - "serde_json", -] - [[package]] name = "rustfix" version = "0.8.1" @@ -4659,7 +4630,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.7.1" +version = "1.8.0" dependencies = [ "annotate-snippets 0.9.2", "anyhow", @@ -5516,36 +5487,9 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "ui_test" -version = "0.21.2" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d" -dependencies = [ - "annotate-snippets 0.9.2", - "anyhow", - "bstr", - "cargo-platform", - "cargo_metadata 0.15.4", - "color-eyre", - "colored", - "comma", - "crossbeam-channel", - "indicatif", - "lazy_static", - "levenshtein", - "prettydiff 0.6.4", - "regex", - "rustc_version", - "rustfix 0.6.1", - "serde", - "serde_json", - "tempfile", -] - -[[package]] -name = "ui_test" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e4f339f62edc873975c47115f9e71c5454ddaa37c1142b42fc0b2672c8dacb" +checksum = "32ee4c40e5a5f9fa6864ff976473e5d6a6e9884b6ce68b40690d9f87e1994c83" dependencies = [ "annotate-snippets 0.11.4", "anyhow", @@ -5557,12 +5501,11 @@ dependencies = [ "comma", "crossbeam-channel", "indicatif", - "lazy_static", "levenshtein", - "prettydiff 0.7.0", + "prettydiff", "regex", "rustc_version", - "rustfix 0.8.1", + "rustfix", "serde", "serde_json", "spanned", @@ -5849,7 +5792,7 @@ dependencies = [ "lexopt", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.216.0", + "wasmparser", "wat", "wit-component", "wit-parser", @@ -5869,7 +5812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c23aebea22c8a75833ae08ed31ccc020835b12a41999e58c31464271b94a88" dependencies = [ "leb128", - "wasmparser 0.216.0", + "wasmparser", ] [[package]] @@ -5885,16 +5828,7 @@ dependencies = [ "serde_json", "spdx", "wasm-encoder", - "wasmparser 0.216.0", -] - -[[package]] -name = "wasmparser" -version = "0.215.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fbde0881f24199b81cf49b6ff8f9c145ac8eb1b7fc439adb5c099734f7d90e" -dependencies = [ - "bitflags 2.6.0", + "wasmparser", ] [[package]] @@ -6228,7 +6162,7 @@ dependencies = [ "serde_json", "wasm-encoder", "wasm-metadata", - "wasmparser 0.216.0", + "wasmparser", "wit-parser", ] @@ -6247,7 +6181,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.216.0", + "wasmparser", ] [[package]] diff --git a/LICENSES/GCC-exception-3.1.txt b/LICENSES/GCC-exception-3.1.txt new file mode 100644 index 0000000000000..eecede4d0707e --- /dev/null +++ b/LICENSES/GCC-exception-3.1.txt @@ -0,0 +1,30 @@ +GCC RUNTIME LIBRARY EXCEPTION + +Version 3.1, 31 March 2009 + +Copyright © 2009 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +This GCC Runtime Library Exception ("Exception") is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). It applies to a given file (the "Runtime Library") that bears a notice placed by the copyright holder of the file stating that the file is governed by GPLv3 along with this Exception. + +When you use GCC to compile a program, GCC may combine portions of certain GCC header files and runtime libraries with the compiled program. The purpose of this Exception is to allow compilation of non-GPL (including proprietary) programs to use, in this way, the header files and runtime libraries covered by this Exception. +0. Definitions. + +A file is an "Independent Module" if it either requires the Runtime Library for execution after a Compilation Process, or makes use of an interface provided by the Runtime Library, but is not otherwise based on the Runtime Library. + +"GCC" means a version of the GNU Compiler Collection, with or without modifications, governed by version 3 (or a specified later version) of the GNU General Public License (GPL) with the option of using any subsequent versions published by the FSF. + +"GPL-compatible Software" is software whose conditions of propagation, modification and use would permit combination with GCC in accord with the license of GCC. + +"Target Code" refers to output from any compiler for a real or virtual target processor architecture, in executable form or suitable for input to an assembler, loader, linker and/or execution phase. Notwithstanding that, Target Code does not include data in any format that is used as a compiler intermediate representation, or used for producing a compiler intermediate representation. + +The "Compilation Process" transforms code entirely represented in non-intermediate languages designed for human-written code, and/or in Java Virtual Machine byte code, into Target Code. Thus, for example, use of source code generators and preprocessors need not be considered part of the Compilation Process, since the Compilation Process can be understood as starting with the output of the generators or preprocessors. + +A Compilation Process is "Eligible" if it is done using GCC, alone or with other GPL-compatible software, or if it is done without using any work based on GCC. For example, using non-GPL-compatible Software to optimize any GCC intermediate representations would not qualify as an Eligible Compilation Process. +1. Grant of Additional Permission. + +You have permission to propagate a work of Target Code formed by combining the Runtime Library with Independent Modules, even if such propagation would otherwise violate the terms of GPLv3, provided that all Target Code was generated by Eligible Compilation Processes. You may then convey such a combination under terms of your choice, consistent with the licensing of the Independent Modules. +2. No Weakening of GCC Copyleft. + +The availability of this Exception does not imply any general presumption that third-party software is unaffected by the copyleft requirements of the license of GCC. diff --git a/LICENSES/GPL-2.0-only.txt b/LICENSES/GPL-2.0-only.txt new file mode 100644 index 0000000000000..492485e09b411 --- /dev/null +++ b/LICENSES/GPL-2.0-only.txt @@ -0,0 +1,133 @@ +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification follow. +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. + b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. + c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + +one line to give the program's name and an idea of what it does. +Copyright (C) yyyy name of author + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author +Gnomovision comes with ABSOLUTELY NO WARRANTY; for details +type `show w'. This is free software, and you are welcome +to redistribute it under certain conditions; type `show c' +for details. + +The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright +interest in the program `Gnomovision' +(which makes passes at compilers) written +by James Hacker. + +signature of Ty Coon, 1 April 1989 +Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff --git a/LICENSES/GPL-3.0-or-later.txt b/LICENSES/GPL-3.0-or-later.txt new file mode 100644 index 0000000000000..37b6b8e91b85e --- /dev/null +++ b/LICENSES/GPL-3.0-or-later.txt @@ -0,0 +1,202 @@ +GNU GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright © 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble + +The GNU General Public License is a free, copyleft license for software and other kinds of works. + +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. + +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based on the Program. + + To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. + 1. Source Code. + The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. + + A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. + + The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. + + The Corresponding Source for a work in source code form is that same work. + 2. Basic Permissions. + All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. + + When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. + 4. Conveying Verbatim Copies. + You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. + 5. Conveying Modified Source Versions. + You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: + a) The work must carry prominent notices stating that you modified it, and giving a relevant date. + b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". + c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. + d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. + + A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. + 6. Conveying Non-Source Forms. + You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: + a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. + b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. + c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. + d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. + e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. + + If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). + + The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. + 7. Additional Terms. + "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: + a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or + b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or + c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or + d) Limiting the use for publicity purposes of names of licensors or authors of the material; or + e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or + f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. + + All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. + 8. Termination. + You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). + + However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. + + Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. + 9. Acceptance Not Required for Having Copies. + You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. + 10. Automatic Licensing of Downstream Recipients. + Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. + 11. Patents. + A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. + + If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. + + A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. + 12. No Surrender of Others' Freedom. + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. + 13. Use with the GNU Affero General Public License. + Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. + 14. Revised Versions of this License. + The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. + + Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. + 15. Disclaimer of Warranty. + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + 16. Limitation of Liability. + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + +Copyright (C) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: + + Copyright (C) +This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. +This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". + +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . + +The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . diff --git a/LICENSES/ISC.txt b/LICENSES/ISC.txt new file mode 100644 index 0000000000000..6f41c8c63b96e --- /dev/null +++ b/LICENSES/ISC.txt @@ -0,0 +1,7 @@ +ISC License + + + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 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 THIS SOFTWARE. diff --git a/RELEASES.md b/RELEASES.md index 6aba476103e7f..b49470c307569 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -34,7 +34,6 @@ Compiler - [Add Tier 3 `std` Xtensa targets:](https://github.com/rust-lang/rust/pull/126380/) `xtensa-esp32-espidf`, `xtensa-esp32s2-espidf`, `xtensa-esp32s3-espidf` - [Add Tier 3 i686 Redox OS target:](https://github.com/rust-lang/rust/pull/126192/) `i686-unknown-redox` - [Promote `arm64ec-pc-windows-msvc` to Tier 2.](https://github.com/rust-lang/rust/pull/126039/) - - [Promote `wasm32-wasip2` to Tier 2.](https://github.com/rust-lang/rust/pull/126967/) - [Promote `loongarch64-unknown-linux-musl` to Tier 2 with host tools.](https://github.com/rust-lang/rust/pull/126298/) - [Enable full tools and profiler for LoongArch Linux targets.](https://github.com/rust-lang/rust/pull/127078/) - [Unconditionally warn on usage of `wasm32-wasi`.](https://github.com/rust-lang/rust/pull/126662/) (see compatibility note below) @@ -100,6 +99,9 @@ Compatibility Notes The reason is that these types have different roles: `std::panic::PanicHookInfo` is the argument to the [panic hook](https://doc.rust-lang.org/stable/std/panic/fn.set_hook.html) in std context (where panics can have an arbitrary payload), while `core::panic::PanicInfo` is the argument to the [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) in no_std context (where panics always carry a formatted *message*). Separating these types allows us to add more useful methods to these types, such as `std::panic::PanicHookInfo::payload_as_str()` and `core::panic::PanicInfo::message()`. * The new sort implementations may panic if a type's implementation of [`Ord`](https://doc.rust-lang.org/std/cmp/trait.Ord.html) (or the given comparison function) does not implement a [total order](https://en.wikipedia.org/wiki/Total_order) as the trait requires. `Ord`'s supertraits (`PartialOrd`, `Eq`, and `PartialEq`) must also be consistent. The previous implementations would not "notice" any problem, but the new implementations have a good chance of detecting inconsistencies, throwing a panic rather than returning knowingly unsorted data. +* [In very rare cases, a change in the internal evaluation order of the trait + solver may result in new fatal overflow errors.](https://github.com/rust-lang/rust/pull/126128) + @@ -112,6 +114,14 @@ tools. - [Add a Rust-for Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/) +Version 1.80.1 (2024-08-08) +=========================== + + + +- [Fix miscompilation in the jump threading MIR optimization when comparing floats](https://github.com/rust-lang/rust/pull/128271) +- [Revert changes to the `dead_code` lint from 1.80.0](https://github.com/rust-lang/rust/pull/128618) + Version 1.80.0 (2024-07-25) ========================== diff --git a/REUSE.toml b/REUSE.toml index efd705552478d..3005bb56609b5 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -168,3 +168,37 @@ SPDX-FileCopyrightText = [ "2003-2019 University of Illinois at Urbana-Champaign.", ] SPDX-License-Identifier = "NCSA AND Apache-2.0 WITH LLVM-exception" + +[[annotations]] +path = "src/gcc/**" +precedence = "override" +SPDX-FileCopyrightText = [ + "Copyright (C) 1997-2024 Free Software Foundation, Inc.", +] +SPDX-License-Identifier = "GPL-3.0-or-later" + +[[annotations]] +path = "src/gcc/gcc/testsuite/**" +precedence = "override" +SPDX-FileCopyrightText = [ + "Copyright (C) 2000-2024 Free Software Foundation, Inc.", +] +SPDX-License-Identifier = "GPL-2.0-only" + +[[annotations]] +path = "src/gcc/gcc/testsuite/c-c++-common/analyzer/*.c" +precedence = "override" +SPDX-FileCopyrightText = [ + "Copyright (c) 2007-2011 Atheros Communications Inc.", + "Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc.", + "Copyright (c) 2016-2017 Erik Stromdahl ", +] +SPDX-License-Identifier = "ISC" + +[[annotations]] +path = "src/gcc/libstdc++-v3/config/os/aix/os_defines.h" +precedence = "override" +SPDX-FileCopyrightText = [ + "Copyright (C) 2000-2024 Free Software Foundation, Inc.", +] +SPDX-License-Identifier = "GCC-exception-3.1" diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index 5008069542f1f..a2fc9d5c408e3 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -30,5 +30,6 @@ features = ['unprefixed_malloc_on_supported_platforms'] jemalloc = ['dep:jemalloc-sys'] llvm = ['rustc_driver_impl/llvm'] max_level_info = ['rustc_driver_impl/max_level_info'] +rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts'] rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler'] # tidy-alphabetical-end diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 5160b4ed0a2ac..620a051eeb7dd 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1,4 +1,3 @@ -use std::borrow::{Borrow, Cow}; use std::fmt::{self, Write}; use std::ops::{Bound, Deref}; use std::{cmp, iter}; @@ -7,8 +6,8 @@ use rustc_index::Idx; use tracing::debug; use crate::{ - Abi, AbiAndPrefAlign, Align, FieldsShape, IndexSlice, IndexVec, Integer, LayoutS, Niche, - NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, TargetDataLayout, + Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, + LayoutS, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; @@ -30,19 +29,48 @@ where uninhabited && is_1zst } -pub trait LayoutCalculator { - type TargetDataLayoutRef: Borrow; +/// Determines towards which end of a struct layout optimizations will try to place the best niches. +enum NicheBias { + Start, + End, +} - fn delayed_bug(&self, txt: impl Into>); - fn current_data_layout(&self) -> Self::TargetDataLayoutRef; +#[derive(Copy, Clone, Debug)] +pub enum LayoutCalculatorError { + /// An unsized type was found in a location where a sized type was expected. + /// + /// This is not always a compile error, for example if there is a `[T]: Sized` + /// bound in a where clause. + /// + /// Contains the field that was unexpectedly unsized. + UnexpectedUnsized(F), + + /// A type was too large for the target platform. + SizeOverflow, + + /// A union had no fields. + EmptyUnion, +} + +type LayoutCalculatorResult = + Result, LayoutCalculatorError>; + +#[derive(Clone, Copy, Debug)] +pub struct LayoutCalculator { + pub cx: Cx, +} + +impl LayoutCalculator { + pub fn new(cx: Cx) -> Self { + Self { cx } + } - fn scalar_pair( + pub fn scalar_pair( &self, a: Scalar, b: Scalar, ) -> LayoutS { - let dl = self.current_data_layout(); - let dl = dl.borrow(); + let dl = self.cx.data_layout(); let b_align = b.align(dl); let align = a.align(dl).max(b_align).max(dl.aggregate_align); let b_offset = a.size(dl).align_to(b_align.abi); @@ -70,25 +98,25 @@ pub trait LayoutCalculator { } } - fn univariant< + pub fn univariant< 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug + Copy, >( &self, - dl: &TargetDataLayout, fields: &IndexSlice, repr: &ReprOptions, kind: StructKind, - ) -> Option> { - let layout = univariant(self, dl, fields, repr, kind, NicheBias::Start); + ) -> LayoutCalculatorResult { + let dl = self.cx.data_layout(); + let layout = self.univariant_biased(fields, repr, kind, NicheBias::Start); // Enums prefer niches close to the beginning or the end of the variants so that other // (smaller) data-carrying variants can be packed into the space after/before the niche. // If the default field ordering does not give us a niche at the front then we do a second // run and bias niches to the right and then check which one is closer to one of the // struct's edges. - if let Some(layout) = &layout { + if let Ok(layout) = &layout { // Don't try to calculate an end-biased layout for unsizable structs, // otherwise we could end up with different layouts for // Foo and Foo which would break unsizing. @@ -102,7 +130,8 @@ pub trait LayoutCalculator { // field (e.g. a trailing bool) and there is tail padding. But it's non-trivial // to get the unpadded size so we try anyway. if fields.len() > 1 && head_space != 0 && tail_space > 0 { - let alt_layout = univariant(self, dl, fields, repr, kind, NicheBias::End) + let alt_layout = self + .univariant_biased(fields, repr, kind, NicheBias::End) .expect("alt layout should always work"); let alt_niche = alt_layout .largest_niche @@ -130,12 +159,12 @@ pub trait LayoutCalculator { alt_tail_space, layout.fields.count(), prefer_alt_layout, - format_field_niches(layout, fields, dl), - format_field_niches(&alt_layout, fields, dl), + self.format_field_niches(layout, fields), + self.format_field_niches(&alt_layout, fields), ); if prefer_alt_layout { - return Some(alt_layout); + return Ok(alt_layout); } } } @@ -144,11 +173,10 @@ pub trait LayoutCalculator { layout } - fn layout_of_never_type( + pub fn layout_of_never_type( &self, ) -> LayoutS { - let dl = self.current_data_layout(); - let dl = dl.borrow(); + let dl = self.cx.data_layout(); LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, @@ -161,11 +189,11 @@ pub trait LayoutCalculator { } } - fn layout_of_struct_or_enum< + pub fn layout_of_struct_or_enum< 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -177,10 +205,7 @@ pub trait LayoutCalculator { discriminants: impl Iterator, dont_niche_optimize_enum: bool, always_sized: bool, - ) -> Option> { - let dl = self.current_data_layout(); - let dl = dl.borrow(); - + ) -> LayoutCalculatorResult { let (present_first, present_second) = { let mut present_variants = variants .iter_enumerated() @@ -191,7 +216,7 @@ pub trait LayoutCalculator { Some(present_first) => present_first, // Uninhabited because it has no variants, or only absent ones. None if is_enum => { - return Some(self.layout_of_never_type()); + return Ok(self.layout_of_never_type()); } // If it's a struct, still compute a layout so that we can still compute the // field offsets. @@ -203,15 +228,13 @@ pub trait LayoutCalculator { // or for optimizing univariant enums (present_second.is_none() && !repr.inhibit_enum_layout_opt()) { - layout_of_struct( - self, + self.layout_of_struct( repr, variants, is_enum, is_unsafe_cell, scalar_valid_range, always_sized, - dl, present_first, ) } else { @@ -219,30 +242,27 @@ pub trait LayoutCalculator { // structs. (We have also handled univariant enums // that allow representation optimization.) assert!(is_enum); - layout_of_enum( - self, + self.layout_of_enum( repr, variants, discr_range_of_repr, discriminants, dont_niche_optimize_enum, - dl, ) } } - fn layout_of_union< + pub fn layout_of_union< 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, variants: &IndexSlice>, - ) -> Option> { - let dl = self.current_data_layout(); - let dl = dl.borrow(); + ) -> LayoutCalculatorResult { + let dl = self.cx.data_layout(); let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut max_repr_align = repr.align; @@ -257,10 +277,11 @@ pub trait LayoutCalculator { }; let mut size = Size::ZERO; - let only_variant = &variants[VariantIdx::new(0)]; + let only_variant_idx = VariantIdx::new(0); + let only_variant = &variants[only_variant_idx]; for field in only_variant { if field.is_unsized() { - self.delayed_bug("unsized field in union".to_string()); + return Err(LayoutCalculatorError::UnexpectedUnsized(*field)); } align = align.max(field.align); @@ -323,9 +344,13 @@ pub trait LayoutCalculator { } }; - Some(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?), + let Some(union_field_count) = NonZeroUsize::new(only_variant.len()) else { + return Err(LayoutCalculatorError::EmptyUnion); + }; + + Ok(LayoutS { + variants: Variants::Single { index: only_variant_idx }, + fields: FieldsShape::Union(union_field_count), abi, largest_niche: None, align, @@ -334,983 +359,988 @@ pub trait LayoutCalculator { unadjusted_abi_align, }) } -} -/// single-variant enums are just structs, if you think about it -fn layout_of_struct<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>( - layout_calc: &LC, - repr: &ReprOptions, - variants: &IndexSlice>, - is_enum: bool, - is_unsafe_cell: bool, - scalar_valid_range: (Bound, Bound), - always_sized: bool, - dl: &TargetDataLayout, - present_first: VariantIdx, -) -> Option> -where - LC: LayoutCalculator + ?Sized, - F: Deref> + fmt::Debug, -{ - // Struct, or univariant enum equivalent to a struct. - // (Typechecking will reject discriminant-sizing attrs.) - - let v = present_first; - let kind = if is_enum || variants[v].is_empty() || always_sized { - StructKind::AlwaysSized - } else { - StructKind::MaybeUnsized - }; - - let mut st = layout_calc.univariant(dl, &variants[v], repr, kind)?; - st.variants = Variants::Single { index: v }; - - if is_unsafe_cell { - let hide_niches = |scalar: &mut _| match scalar { - Scalar::Initialized { value, valid_range } => { - *valid_range = WrappingRange::full(value.size(dl)) - } - // Already doesn't have any niches - Scalar::Union { .. } => {} + /// single-variant enums are just structs, if you think about it + fn layout_of_struct< + 'a, + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + >( + &self, + repr: &ReprOptions, + variants: &IndexSlice>, + is_enum: bool, + is_unsafe_cell: bool, + scalar_valid_range: (Bound, Bound), + always_sized: bool, + present_first: VariantIdx, + ) -> LayoutCalculatorResult { + // Struct, or univariant enum equivalent to a struct. + // (Typechecking will reject discriminant-sizing attrs.) + + let dl = self.cx.data_layout(); + let v = present_first; + let kind = if is_enum || variants[v].is_empty() || always_sized { + StructKind::AlwaysSized + } else { + StructKind::MaybeUnsized }; - match &mut st.abi { - Abi::Uninhabited => {} - Abi::Scalar(scalar) => hide_niches(scalar), - Abi::ScalarPair(a, b) => { - hide_niches(a); - hide_niches(b); + + let mut st = self.univariant(&variants[v], repr, kind)?; + st.variants = Variants::Single { index: v }; + + if is_unsafe_cell { + let hide_niches = |scalar: &mut _| match scalar { + Scalar::Initialized { value, valid_range } => { + *valid_range = WrappingRange::full(value.size(dl)) + } + // Already doesn't have any niches + Scalar::Union { .. } => {} + }; + match &mut st.abi { + Abi::Uninhabited => {} + Abi::Scalar(scalar) => hide_niches(scalar), + Abi::ScalarPair(a, b) => { + hide_niches(a); + hide_niches(b); + } + Abi::Vector { element, count: _ } => hide_niches(element), + Abi::Aggregate { sized: _ } => {} } - Abi::Vector { element, count: _ } => hide_niches(element), - Abi::Aggregate { sized: _ } => {} + st.largest_niche = None; + return Ok(st); } - st.largest_niche = None; - return Some(st); - } - let (start, end) = scalar_valid_range; - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { - // Enlarging validity ranges would result in missed - // optimizations, *not* wrongly assuming the inner - // value is valid. e.g. unions already enlarge validity ranges, - // because the values may be uninitialized. - // - // Because of that we only check that the start and end - // of the range is representable with this scalar type. - - let max_value = scalar.size(dl).unsigned_int_max(); - if let Bound::Included(start) = start { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - assert!(start <= max_value, "{start} > {max_value}"); - scalar.valid_range_mut().start = start; - } - if let Bound::Included(end) = end { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - assert!(end <= max_value, "{end} > {max_value}"); - scalar.valid_range_mut().end = end; - } + let (start, end) = scalar_valid_range; + match st.abi { + Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { + // Enlarging validity ranges would result in missed + // optimizations, *not* wrongly assuming the inner + // value is valid. e.g. unions already enlarge validity ranges, + // because the values may be uninitialized. + // + // Because of that we only check that the start and end + // of the range is representable with this scalar type. + + let max_value = scalar.size(dl).unsigned_int_max(); + if let Bound::Included(start) = start { + // FIXME(eddyb) this might be incorrect - it doesn't + // account for wrap-around (end < start) ranges. + assert!(start <= max_value, "{start} > {max_value}"); + scalar.valid_range_mut().start = start; + } + if let Bound::Included(end) = end { + // FIXME(eddyb) this might be incorrect - it doesn't + // account for wrap-around (end < start) ranges. + assert!(end <= max_value, "{end} > {max_value}"); + scalar.valid_range_mut().end = end; + } - // Update `largest_niche` if we have introduced a larger niche. - let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); - if let Some(niche) = niche { - match st.largest_niche { - Some(largest_niche) => { - // Replace the existing niche even if they're equal, - // because this one is at a lower offset. - if largest_niche.available(dl) <= niche.available(dl) { - st.largest_niche = Some(niche); + // Update `largest_niche` if we have introduced a larger niche. + let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); + if let Some(niche) = niche { + match st.largest_niche { + Some(largest_niche) => { + // Replace the existing niche even if they're equal, + // because this one is at a lower offset. + if largest_niche.available(dl) <= niche.available(dl) { + st.largest_niche = Some(niche); + } } + None => st.largest_niche = Some(niche), } - None => st.largest_niche = Some(niche), } } + _ => assert!( + start == Bound::Unbounded && end == Bound::Unbounded, + "nonscalar layout for layout_scalar_valid_range type: {st:#?}", + ), } - _ => assert!( - start == Bound::Unbounded && end == Bound::Unbounded, - "nonscalar layout for layout_scalar_valid_range type: {st:#?}", - ), - } - - Some(st) -} -fn layout_of_enum<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>( - layout_calc: &LC, - repr: &ReprOptions, - variants: &IndexSlice>, - discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), - discriminants: impl Iterator, - dont_niche_optimize_enum: bool, - dl: &TargetDataLayout, -) -> Option> -where - LC: LayoutCalculator + ?Sized, - F: Deref> + fmt::Debug, -{ - // Until we've decided whether to use the tagged or - // niche filling LayoutS, we don't want to intern the - // variant layouts, so we can't store them in the - // overall LayoutS. Store the overall LayoutS - // and the variant LayoutSs here until then. - struct TmpLayout { - layout: LayoutS, - variants: IndexVec>, + Ok(st) } - let calculate_niche_filling_layout = || -> Option> { - if dont_niche_optimize_enum { - return None; + fn layout_of_enum< + 'a, + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + >( + &self, + repr: &ReprOptions, + variants: &IndexSlice>, + discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), + discriminants: impl Iterator, + dont_niche_optimize_enum: bool, + ) -> LayoutCalculatorResult { + // Until we've decided whether to use the tagged or + // niche filling LayoutS, we don't want to intern the + // variant layouts, so we can't store them in the + // overall LayoutS. Store the overall LayoutS + // and the variant LayoutSs here until then. + struct TmpLayout { + layout: LayoutS, + variants: IndexVec>, } - if variants.len() < 2 { - return None; - } + let dl = self.cx.data_layout(); - let mut align = dl.aggregate_align; - let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; + let calculate_niche_filling_layout = || -> Option> { + if dont_niche_optimize_enum { + return None; + } - let mut variant_layouts = variants - .iter_enumerated() - .map(|(j, v)| { - let mut st = layout_calc.univariant(dl, v, repr, StructKind::AlwaysSized)?; - st.variants = Variants::Single { index: j }; + if variants.len() < 2 { + return None; + } - align = align.max(st.align); - max_repr_align = max_repr_align.max(st.max_repr_align); - unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); + let mut align = dl.aggregate_align; + let mut max_repr_align = repr.align; + let mut unadjusted_abi_align = align.abi; - Some(st) - }) - .collect::>>()?; + let mut variant_layouts = variants + .iter_enumerated() + .map(|(j, v)| { + let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?; + st.variants = Variants::Single { index: j }; - let largest_variant_index = variant_layouts - .iter_enumerated() - .max_by_key(|(_i, layout)| layout.size.bytes()) - .map(|(i, _layout)| i)?; - - let all_indices = variants.indices(); - let needs_disc = - |index: VariantIdx| index != largest_variant_index && !absent(&variants[index]); - let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() - ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); - - let count = - (niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1; - - // Find the field with the largest niche - let (field_index, niche, (niche_start, niche_scalar)) = variants[largest_variant_index] - .iter() - .enumerate() - .filter_map(|(j, field)| Some((j, field.largest_niche?))) - .max_by_key(|(_, niche)| niche.available(dl)) - .and_then(|(j, niche)| Some((j, niche, niche.reserve(dl, count)?)))?; - let niche_offset = - niche.offset + variant_layouts[largest_variant_index].fields.offset(field_index); - let niche_size = niche.value.size(dl); - let size = variant_layouts[largest_variant_index].size.align_to(align.abi); - - let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| { - if i == largest_variant_index { - return true; - } + align = align.max(st.align); + max_repr_align = max_repr_align.max(st.max_repr_align); + unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - layout.largest_niche = None; + Some(st) + }) + .collect::>>()?; - if layout.size <= niche_offset { - // This variant will fit before the niche. - return true; - } + let largest_variant_index = variant_layouts + .iter_enumerated() + .max_by_key(|(_i, layout)| layout.size.bytes()) + .map(|(i, _layout)| i)?; + + let all_indices = variants.indices(); + let needs_disc = + |index: VariantIdx| index != largest_variant_index && !absent(&variants[index]); + let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() + ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); + + let count = + (niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1; + + // Use the largest niche in the largest variant. + let niche = variant_layouts[largest_variant_index].largest_niche?; + let (niche_start, niche_scalar) = niche.reserve(dl, count)?; + let niche_offset = niche.offset; + let niche_size = niche.value.size(dl); + let size = variant_layouts[largest_variant_index].size.align_to(align.abi); + + let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| { + if i == largest_variant_index { + return true; + } - // Determine if it'll fit after the niche. - let this_align = layout.align.abi; - let this_offset = (niche_offset + niche_size).align_to(this_align); + layout.largest_niche = None; - if this_offset + layout.size > size { - return false; - } + if layout.size <= niche_offset { + // This variant will fit before the niche. + return true; + } - // It'll fit, but we need to make some adjustments. - match layout.fields { - FieldsShape::Arbitrary { ref mut offsets, .. } => { - for offset in offsets.iter_mut() { - *offset += this_offset; - } + // Determine if it'll fit after the niche. + let this_align = layout.align.abi; + let this_offset = (niche_offset + niche_size).align_to(this_align); + + if this_offset + layout.size > size { + return false; } - FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { - panic!("Layout of fields should be Arbitrary for variants") + + // It'll fit, but we need to make some adjustments. + match layout.fields { + FieldsShape::Arbitrary { ref mut offsets, .. } => { + for offset in offsets.iter_mut() { + *offset += this_offset; + } + } + FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { + panic!("Layout of fields should be Arbitrary for variants") + } } - } - // It can't be a Scalar or ScalarPair because the offset isn't 0. - if !layout.abi.is_uninhabited() { - layout.abi = Abi::Aggregate { sized: true }; - } - layout.size += this_offset; + // It can't be a Scalar or ScalarPair because the offset isn't 0. + if !layout.abi.is_uninhabited() { + layout.abi = Abi::Aggregate { sized: true }; + } + layout.size += this_offset; - true - }); + true + }); - if !all_variants_fit { - return None; - } + if !all_variants_fit { + return None; + } - let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar); + let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar); - let others_zst = variant_layouts - .iter_enumerated() - .all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO); - let same_size = size == variant_layouts[largest_variant_index].size; - let same_align = align == variant_layouts[largest_variant_index].align; - - let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { - Abi::Uninhabited - } else if same_size && same_align && others_zst { - match variant_layouts[largest_variant_index].abi { - // When the total alignment and size match, we can use the - // same ABI as the scalar variant with the reserved niche. - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { - // Only the niche is guaranteed to be initialised, - // so use union layouts for the other primitive. - if niche_offset == Size::ZERO { - Abi::ScalarPair(niche_scalar, second.to_union()) - } else { - Abi::ScalarPair(first.to_union(), niche_scalar) + let others_zst = variant_layouts + .iter_enumerated() + .all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO); + let same_size = size == variant_layouts[largest_variant_index].size; + let same_align = align == variant_layouts[largest_variant_index].align; + + let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { + Abi::Uninhabited + } else if same_size && same_align && others_zst { + match variant_layouts[largest_variant_index].abi { + // When the total alignment and size match, we can use the + // same ABI as the scalar variant with the reserved niche. + Abi::Scalar(_) => Abi::Scalar(niche_scalar), + Abi::ScalarPair(first, second) => { + // Only the niche is guaranteed to be initialised, + // so use union layouts for the other primitive. + if niche_offset == Size::ZERO { + Abi::ScalarPair(niche_scalar, second.to_union()) + } else { + Abi::ScalarPair(first.to_union(), niche_scalar) + } } + _ => Abi::Aggregate { sized: true }, } - _ => Abi::Aggregate { sized: true }, - } - } else { - Abi::Aggregate { sized: true } - }; + } else { + Abi::Aggregate { sized: true } + }; - let layout = LayoutS { - variants: Variants::Multiple { - tag: niche_scalar, - tag_encoding: TagEncoding::Niche { - untagged_variant: largest_variant_index, - niche_variants, - niche_start, + let layout = LayoutS { + variants: Variants::Multiple { + tag: niche_scalar, + tag_encoding: TagEncoding::Niche { + untagged_variant: largest_variant_index, + niche_variants, + niche_start, + }, + tag_field: 0, + variants: IndexVec::new(), }, - tag_field: 0, - variants: IndexVec::new(), - }, - fields: FieldsShape::Arbitrary { - offsets: [niche_offset].into(), - memory_index: [0].into(), - }, - abi, - largest_niche, - size, - align, - max_repr_align, - unadjusted_abi_align, - }; + fields: FieldsShape::Arbitrary { + offsets: [niche_offset].into(), + memory_index: [0].into(), + }, + abi, + largest_niche, + size, + align, + max_repr_align, + unadjusted_abi_align, + }; - Some(TmpLayout { layout, variants: variant_layouts }) - }; + Some(TmpLayout { layout, variants: variant_layouts }) + }; - let niche_filling_layout = calculate_niche_filling_layout(); + let niche_filling_layout = calculate_niche_filling_layout(); - let (mut min, mut max) = (i128::MAX, i128::MIN); - let discr_type = repr.discr_type(); - let bits = Integer::from_attr(dl, discr_type).size().bits(); - for (i, mut val) in discriminants { - if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) { - continue; - } - if discr_type.is_signed() { - // sign extend the raw representation to be an i128 - val = (val << (128 - bits)) >> (128 - bits); - } - if val < min { - min = val; + let (mut min, mut max) = (i128::MAX, i128::MIN); + let discr_type = repr.discr_type(); + let bits = Integer::from_attr(dl, discr_type).size().bits(); + for (i, mut val) in discriminants { + if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) { + continue; + } + if discr_type.is_signed() { + // sign extend the raw representation to be an i128 + val = (val << (128 - bits)) >> (128 - bits); + } + if val < min { + min = val; + } + if val > max { + max = val; + } } - if val > max { - max = val; + // We might have no inhabited variants, so pretend there's at least one. + if (min, max) == (i128::MAX, i128::MIN) { + min = 0; + max = 0; } - } - // We might have no inhabited variants, so pretend there's at least one. - if (min, max) == (i128::MAX, i128::MIN) { - min = 0; - max = 0; - } - assert!(min <= max, "discriminant range is {min}...{max}"); - let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max); - - let mut align = dl.aggregate_align; - let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; - - let mut size = Size::ZERO; - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256).unwrap(); - assert_eq!(Integer::for_align(dl, start_align), None); - - // repr(C) on an enum tells us to make a (tag, union) layout, - // so we need to grow the prefix alignment to be at least - // the alignment of the union. (This value is used both for - // determining the alignment of the overall enum, and the - // determining the alignment of the payload after the tag.) - let mut prefix_align = min_ity.align(dl).abi; - if repr.c() { - for fields in variants { - for field in fields { - prefix_align = prefix_align.max(field.align.abi); + assert!(min <= max, "discriminant range is {min}...{max}"); + let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max); + + let mut align = dl.aggregate_align; + let mut max_repr_align = repr.align; + let mut unadjusted_abi_align = align.abi; + + let mut size = Size::ZERO; + + // We're interested in the smallest alignment, so start large. + let mut start_align = Align::from_bytes(256).unwrap(); + assert_eq!(Integer::for_align(dl, start_align), None); + + // repr(C) on an enum tells us to make a (tag, union) layout, + // so we need to grow the prefix alignment to be at least + // the alignment of the union. (This value is used both for + // determining the alignment of the overall enum, and the + // determining the alignment of the payload after the tag.) + let mut prefix_align = min_ity.align(dl).abi; + if repr.c() { + for fields in variants { + for field in fields { + prefix_align = prefix_align.max(field.align.abi); + } } } - } - // Create the set of structs that represent each variant. - let mut layout_variants = variants - .iter_enumerated() - .map(|(i, field_layouts)| { - let mut st = layout_calc.univariant( - dl, - field_layouts, - repr, - StructKind::Prefixed(min_ity.size(), prefix_align), - )?; - st.variants = Variants::Single { index: i }; - // Find the first field we can't move later - // to make room for a larger discriminant. - for field_idx in st.fields.index_by_increasing_offset() { - let field = &field_layouts[FieldIdx::new(field_idx)]; - if !field.is_1zst() { - start_align = start_align.min(field.align.abi); - break; + // Create the set of structs that represent each variant. + let mut layout_variants = variants + .iter_enumerated() + .map(|(i, field_layouts)| { + let mut st = self.univariant( + field_layouts, + repr, + StructKind::Prefixed(min_ity.size(), prefix_align), + )?; + st.variants = Variants::Single { index: i }; + // Find the first field we can't move later + // to make room for a larger discriminant. + for field_idx in st.fields.index_by_increasing_offset() { + let field = &field_layouts[FieldIdx::new(field_idx)]; + if !field.is_1zst() { + start_align = start_align.min(field.align.abi); + break; + } } - } - size = cmp::max(size, st.size); - align = align.max(st.align); - max_repr_align = max_repr_align.max(st.max_repr_align); - unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - Some(st) - }) - .collect::>>()?; + size = cmp::max(size, st.size); + align = align.max(st.align); + max_repr_align = max_repr_align.max(st.max_repr_align); + unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); + Ok(st) + }) + .collect::, _>>()?; - // Align the maximum variant size to the largest alignment. - size = size.align_to(align.abi); + // Align the maximum variant size to the largest alignment. + size = size.align_to(align.abi); - // FIXME(oli-obk): deduplicate and harden these checks - if size.bytes() >= dl.obj_size_bound() { - return None; - } + // FIXME(oli-obk): deduplicate and harden these checks + if size.bytes() >= dl.obj_size_bound() { + return Err(LayoutCalculatorError::SizeOverflow); + } - let typeck_ity = Integer::from_attr(dl, repr.discr_type()); - if typeck_ity < min_ity { - // It is a bug if Layout decided on a greater discriminant size than typeck for - // some reason at this point (based on values discriminant can take on). Mostly - // because this discriminant will be loaded, and then stored into variable of - // type calculated by typeck. Consider such case (a bug): typeck decided on - // byte-sized discriminant, but layout thinks we need a 16-bit to store all - // discriminant values. That would be a bug, because then, in codegen, in order - // to store this 16-bit discriminant into 8-bit sized temporary some of the - // space necessary to represent would have to be discarded (or layout is wrong - // on thinking it needs 16 bits) - panic!( - "layout decided on a larger discriminant type ({min_ity:?}) than typeck ({typeck_ity:?})" - ); - // However, it is fine to make discr type however large (as an optimisation) - // after this point – we’ll just truncate the value we load in codegen. - } + let typeck_ity = Integer::from_attr(dl, repr.discr_type()); + if typeck_ity < min_ity { + // It is a bug if Layout decided on a greater discriminant size than typeck for + // some reason at this point (based on values discriminant can take on). Mostly + // because this discriminant will be loaded, and then stored into variable of + // type calculated by typeck. Consider such case (a bug): typeck decided on + // byte-sized discriminant, but layout thinks we need a 16-bit to store all + // discriminant values. That would be a bug, because then, in codegen, in order + // to store this 16-bit discriminant into 8-bit sized temporary some of the + // space necessary to represent would have to be discarded (or layout is wrong + // on thinking it needs 16 bits) + panic!( + "layout decided on a larger discriminant type ({min_ity:?}) than typeck ({typeck_ity:?})" + ); + // However, it is fine to make discr type however large (as an optimisation) + // after this point – we’ll just truncate the value we load in codegen. + } + + // Check to see if we should use a different type for the + // discriminant. We can safely use a type with the same size + // as the alignment of the first field of each variant. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about its contents and + // won't be so conservative. + + // Use the initial field alignment + let mut ity = if repr.c() || repr.int.is_some() { + min_ity + } else { + Integer::for_align(dl, start_align).unwrap_or(min_ity) + }; - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about its contents and - // won't be so conservative. - - // Use the initial field alignment - let mut ity = if repr.c() || repr.int.is_some() { - min_ity - } else { - Integer::for_align(dl, start_align).unwrap_or(min_ity) - }; - - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = min_ity.size(); - let new_ity_size = ity.size(); - for variant in &mut layout_variants { - match variant.fields { - FieldsShape::Arbitrary { ref mut offsets, .. } => { - for i in offsets { - if *i <= old_ity_size { - assert_eq!(*i, old_ity_size); - *i = new_ity_size; + // If the alignment is not larger than the chosen discriminant size, + // don't use the alignment as the final size. + if ity <= min_ity { + ity = min_ity; + } else { + // Patch up the variants' first few fields. + let old_ity_size = min_ity.size(); + let new_ity_size = ity.size(); + for variant in &mut layout_variants { + match variant.fields { + FieldsShape::Arbitrary { ref mut offsets, .. } => { + for i in offsets { + if *i <= old_ity_size { + assert_eq!(*i, old_ity_size); + *i = new_ity_size; + } + } + // We might be making the struct larger. + if variant.size <= old_ity_size { + variant.size = new_ity_size; } } - // We might be making the struct larger. - if variant.size <= old_ity_size { - variant.size = new_ity_size; + FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { + panic!("encountered a non-arbitrary layout during enum layout") } } - FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { - panic!("encountered a non-arbitrary layout during enum layout") - } } } - } - let tag_mask = ity.size().unsigned_int_max(); - let tag = Scalar::Initialized { - value: Primitive::Int(ity, signed), - valid_range: WrappingRange { - start: (min as u128 & tag_mask), - end: (max as u128 & tag_mask), - }, - }; - let mut abi = Abi::Aggregate { sized: true }; - - if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } else if tag.size(dl) == size { - // Make sure we only use scalar layout when the enum is entirely its - // own tag (i.e. it has no padding nor any non-ZST variant fields). - abi = Abi::Scalar(tag); - } else { - // Try to use a ScalarPair for all tagged enums. - // That's possible only if we can find a common primitive type for all variants. - let mut common_prim = None; - let mut common_prim_initialized_in_all_variants = true; - for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) { - let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { - panic!("encountered a non-arbitrary layout during enum layout"); - }; - // We skip *all* ZST here and later check if we are good in terms of alignment. - // This lets us handle some cases involving aligned ZST. - let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst()); - let (field, offset) = match (fields.next(), fields.next()) { - (None, None) => { - common_prim_initialized_in_all_variants = false; - continue; - } - (Some(pair), None) => pair, - _ => { - common_prim = None; - break; - } - }; - let prim = match field.abi { - Abi::Scalar(scalar) => { - common_prim_initialized_in_all_variants &= - matches!(scalar, Scalar::Initialized { .. }); - scalar.primitive() - } - _ => { - common_prim = None; - break; - } - }; - if let Some((old_prim, common_offset)) = common_prim { - // All variants must be at the same offset - if offset != common_offset { - common_prim = None; - break; - } - // This is pretty conservative. We could go fancier - // by realising that (u8, u8) could just cohabit with - // u16 or even u32. - let new_prim = match (old_prim, prim) { - // Allow all identical primitives. - (x, y) if x == y => x, - // Allow integers of the same size with differing signedness. - // We arbitrarily choose the signedness of the first variant. - (p @ Primitive::Int(x, _), Primitive::Int(y, _)) if x == y => p, - // Allow integers mixed with pointers of the same layout. - // We must represent this using a pointer, to avoid - // roundtripping pointers through ptrtoint/inttoptr. - (p @ Primitive::Pointer(_), i @ Primitive::Int(..)) - | (i @ Primitive::Int(..), p @ Primitive::Pointer(_)) - if p.size(dl) == i.size(dl) && p.align(dl) == i.align(dl) => - { - p + let tag_mask = ity.size().unsigned_int_max(); + let tag = Scalar::Initialized { + value: Primitive::Int(ity, signed), + valid_range: WrappingRange { + start: (min as u128 & tag_mask), + end: (max as u128 & tag_mask), + }, + }; + let mut abi = Abi::Aggregate { sized: true }; + + if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { + abi = Abi::Uninhabited; + } else if tag.size(dl) == size { + // Make sure we only use scalar layout when the enum is entirely its + // own tag (i.e. it has no padding nor any non-ZST variant fields). + abi = Abi::Scalar(tag); + } else { + // Try to use a ScalarPair for all tagged enums. + // That's possible only if we can find a common primitive type for all variants. + let mut common_prim = None; + let mut common_prim_initialized_in_all_variants = true; + for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) { + let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { + panic!("encountered a non-arbitrary layout during enum layout"); + }; + // We skip *all* ZST here and later check if we are good in terms of alignment. + // This lets us handle some cases involving aligned ZST. + let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst()); + let (field, offset) = match (fields.next(), fields.next()) { + (None, None) => { + common_prim_initialized_in_all_variants = false; + continue; } + (Some(pair), None) => pair, _ => { common_prim = None; break; } }; - // We may be updating the primitive here, for example from int->ptr. - common_prim = Some((new_prim, common_offset)); - } else { - common_prim = Some((prim, offset)); + let prim = match field.abi { + Abi::Scalar(scalar) => { + common_prim_initialized_in_all_variants &= + matches!(scalar, Scalar::Initialized { .. }); + scalar.primitive() + } + _ => { + common_prim = None; + break; + } + }; + if let Some((old_prim, common_offset)) = common_prim { + // All variants must be at the same offset + if offset != common_offset { + common_prim = None; + break; + } + // This is pretty conservative. We could go fancier + // by realising that (u8, u8) could just cohabit with + // u16 or even u32. + let new_prim = match (old_prim, prim) { + // Allow all identical primitives. + (x, y) if x == y => x, + // Allow integers of the same size with differing signedness. + // We arbitrarily choose the signedness of the first variant. + (p @ Primitive::Int(x, _), Primitive::Int(y, _)) if x == y => p, + // Allow integers mixed with pointers of the same layout. + // We must represent this using a pointer, to avoid + // roundtripping pointers through ptrtoint/inttoptr. + (p @ Primitive::Pointer(_), i @ Primitive::Int(..)) + | (i @ Primitive::Int(..), p @ Primitive::Pointer(_)) + if p.size(dl) == i.size(dl) && p.align(dl) == i.align(dl) => + { + p + } + _ => { + common_prim = None; + break; + } + }; + // We may be updating the primitive here, for example from int->ptr. + common_prim = Some((new_prim, common_offset)); + } else { + common_prim = Some((prim, offset)); + } } - } - if let Some((prim, offset)) = common_prim { - let prim_scalar = if common_prim_initialized_in_all_variants { - let size = prim.size(dl); - assert!(size.bits() <= 128); - Scalar::Initialized { value: prim, valid_range: WrappingRange::full(size) } - } else { - // Common prim might be uninit. - Scalar::Union { value: prim } - }; - let pair = layout_calc.scalar_pair::(tag, prim_scalar); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index.raw, [0, 1]); - offsets + if let Some((prim, offset)) = common_prim { + let prim_scalar = if common_prim_initialized_in_all_variants { + let size = prim.size(dl); + assert!(size.bits() <= 128); + Scalar::Initialized { value: prim, valid_range: WrappingRange::full(size) } + } else { + // Common prim might be uninit. + Scalar::Union { value: prim } + }; + let pair = self.scalar_pair::(tag, prim_scalar); + let pair_offsets = match pair.fields { + FieldsShape::Arbitrary { ref offsets, ref memory_index } => { + assert_eq!(memory_index.raw, [0, 1]); + offsets + } + _ => panic!("encountered a non-arbitrary layout during enum layout"), + }; + if pair_offsets[FieldIdx::new(0)] == Size::ZERO + && pair_offsets[FieldIdx::new(1)] == *offset + && align == pair.align + && size == pair.size + { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; } - _ => panic!("encountered a non-arbitrary layout during enum layout"), - }; - if pair_offsets[FieldIdx::new(0)] == Size::ZERO - && pair_offsets[FieldIdx::new(1)] == *offset - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; } } - } - // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the - // variants to ensure they are consistent. This is because a downcast is - // semantically a NOP, and thus should not affect layout. - if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { - for variant in &mut layout_variants { - // We only do this for variants with fields; the others are not accessed anyway. - // Also do not overwrite any already existing "clever" ABIs. - if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) { - variant.abi = abi; - // Also need to bump up the size and alignment, so that the entire value fits - // in here. - variant.size = cmp::max(variant.size, size); - variant.align.abi = cmp::max(variant.align.abi, align.abi); + // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the + // variants to ensure they are consistent. This is because a downcast is + // semantically a NOP, and thus should not affect layout. + if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + for variant in &mut layout_variants { + // We only do this for variants with fields; the others are not accessed anyway. + // Also do not overwrite any already existing "clever" ABIs. + if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) { + variant.abi = abi; + // Also need to bump up the size and alignment, so that the entire value fits + // in here. + variant.size = cmp::max(variant.size, size); + variant.align.abi = cmp::max(variant.align.abi, align.abi); + } } } - } - let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - - let tagged_layout = LayoutS { - variants: Variants::Multiple { - tag, - tag_encoding: TagEncoding::Direct, - tag_field: 0, - variants: IndexVec::new(), - }, - fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() }, - largest_niche, - abi, - align, - size, - max_repr_align, - unadjusted_abi_align, - }; - - let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; - - let mut best_layout = match (tagged_layout, niche_filling_layout) { - (tl, Some(nl)) => { - // Pick the smaller layout; otherwise, - // pick the layout with the larger niche; otherwise, - // pick tagged as it has simpler codegen. - use cmp::Ordering::*; - let niche_size = |tmp_l: &TmpLayout| { - tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)) - }; - match (tl.layout.size.cmp(&nl.layout.size), niche_size(&tl).cmp(&niche_size(&nl))) { - (Greater, _) => nl, - (Equal, Less) => nl, - _ => tl, - } - } - (tl, None) => tl, - }; + let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - // Now we can intern the variant layouts and store them in the enum layout. - best_layout.layout.variants = match best_layout.layout.variants { - Variants::Multiple { tag, tag_encoding, tag_field, .. } => { - Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants } - } - Variants::Single { .. } => { - panic!("encountered a single-variant enum during multi-variant layout") - } - }; - Some(best_layout.layout) -} + let tagged_layout = LayoutS { + variants: Variants::Multiple { + tag, + tag_encoding: TagEncoding::Direct, + tag_field: 0, + variants: IndexVec::new(), + }, + fields: FieldsShape::Arbitrary { + offsets: [Size::ZERO].into(), + memory_index: [0].into(), + }, + largest_niche, + abi, + align, + size, + max_repr_align, + unadjusted_abi_align, + }; -/// Determines towards which end of a struct layout optimizations will try to place the best niches. -enum NicheBias { - Start, - End, -} + let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; -fn univariant< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, ->( - this: &(impl LayoutCalculator + ?Sized), - dl: &TargetDataLayout, - fields: &IndexSlice, - repr: &ReprOptions, - kind: StructKind, - niche_bias: NicheBias, -) -> Option> { - let pack = repr.pack; - let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - let mut max_repr_align = repr.align; - let mut inverse_memory_index: IndexVec = fields.indices().collect(); - let optimize = !repr.inhibit_struct_field_reordering(); - if optimize && fields.len() > 1 { - let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index.raw[..end]; - let fields_excluding_tail = &fields.raw[..end]; - - // If `-Z randomize-layout` was enabled for the type definition we can shuffle - // the field ordering to try and catch some code making assumptions about layouts - // we don't guarantee. - if repr.can_randomize_type_layout() && cfg!(feature = "randomize") { - #[cfg(feature = "randomize")] - { - use rand::seq::SliceRandom; - use rand::SeedableRng; - // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field - // ordering. - let mut rng = - rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); - - // Shuffle the ordering of the fields. - optimizing.shuffle(&mut rng); + let mut best_layout = match (tagged_layout, niche_filling_layout) { + (tl, Some(nl)) => { + // Pick the smaller layout; otherwise, + // pick the layout with the larger niche; otherwise, + // pick tagged as it has simpler codegen. + use cmp::Ordering::*; + let niche_size = |tmp_l: &TmpLayout| { + tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)) + }; + match (tl.layout.size.cmp(&nl.layout.size), niche_size(&tl).cmp(&niche_size(&nl))) { + (Greater, _) => nl, + (Equal, Less) => nl, + _ => tl, + } } - // Otherwise we just leave things alone and actually optimize the type's fields - } else { - // To allow unsizing `&Foo` -> `&Foo`, the layout of the struct must - // not depend on the layout of the tail. - let max_field_align = - fields_excluding_tail.iter().map(|f| f.align.abi.bytes()).max().unwrap_or(1); - let largest_niche_size = fields_excluding_tail - .iter() - .filter_map(|f| f.largest_niche) - .map(|n| n.available(dl)) - .max() - .unwrap_or(0); - - // Calculates a sort key to group fields by their alignment or possibly some - // size-derived pseudo-alignment. - let alignment_group_key = |layout: &F| { - // The two branches here return values that cannot be meaningfully compared with - // each other. However, we know that consistently for all executions of - // `alignment_group_key`, one or the other branch will be taken, so this is okay. - if let Some(pack) = pack { - // Return the packed alignment in bytes. - layout.align.abi.min(pack).bytes() - } else { - // Returns `log2(effective-align)`. The calculation assumes that size is an - // integer multiple of align, except for ZSTs. - let align = layout.align.abi.bytes(); - let size = layout.size.bytes(); - let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0); - // Group [u8; 4] with align-4 or [u8; 6] with align-2 fields. - let size_as_align = align.max(size).trailing_zeros(); - let size_as_align = if largest_niche_size > 0 { - match niche_bias { - // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the - // array to the front in the first case (for aligned loads) but keep - // the bool in front in the second case for its niches. - NicheBias::Start => max_field_align.trailing_zeros().min(size_as_align), - // When moving niches towards the end of the struct then for - // A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple - // in the align-1 group because its bool can be moved closer to the end. - NicheBias::End if niche_size == largest_niche_size => { - align.trailing_zeros() - } - NicheBias::End => size_as_align, - } + (tl, None) => tl, + }; + + // Now we can intern the variant layouts and store them in the enum layout. + best_layout.layout.variants = match best_layout.layout.variants { + Variants::Multiple { tag, tag_encoding, tag_field, .. } => { + Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants } + } + Variants::Single { .. } => { + panic!("encountered a single-variant enum during multi-variant layout") + } + }; + Ok(best_layout.layout) + } + + fn univariant_biased< + 'a, + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + >( + &self, + fields: &IndexSlice, + repr: &ReprOptions, + kind: StructKind, + niche_bias: NicheBias, + ) -> LayoutCalculatorResult { + let dl = self.cx.data_layout(); + let pack = repr.pack; + let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; + let mut max_repr_align = repr.align; + let mut inverse_memory_index: IndexVec = fields.indices().collect(); + let optimize_field_order = !repr.inhibit_struct_field_reordering(); + if optimize_field_order && fields.len() > 1 { + let end = + if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; + let optimizing = &mut inverse_memory_index.raw[..end]; + let fields_excluding_tail = &fields.raw[..end]; + + // If `-Z randomize-layout` was enabled for the type definition we can shuffle + // the field ordering to try and catch some code making assumptions about layouts + // we don't guarantee. + if repr.can_randomize_type_layout() && cfg!(feature = "randomize") { + #[cfg(feature = "randomize")] + { + use rand::SeedableRng; + use rand::seq::SliceRandom; + // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field + // ordering. + let mut rng = + rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); + + // Shuffle the ordering of the fields. + optimizing.shuffle(&mut rng); + } + // Otherwise we just leave things alone and actually optimize the type's fields + } else { + // To allow unsizing `&Foo` -> `&Foo`, the layout of the struct must + // not depend on the layout of the tail. + let max_field_align = + fields_excluding_tail.iter().map(|f| f.align.abi.bytes()).max().unwrap_or(1); + let largest_niche_size = fields_excluding_tail + .iter() + .filter_map(|f| f.largest_niche) + .map(|n| n.available(dl)) + .max() + .unwrap_or(0); + + // Calculates a sort key to group fields by their alignment or possibly some + // size-derived pseudo-alignment. + let alignment_group_key = |layout: &F| { + // The two branches here return values that cannot be meaningfully compared with + // each other. However, we know that consistently for all executions of + // `alignment_group_key`, one or the other branch will be taken, so this is okay. + if let Some(pack) = pack { + // Return the packed alignment in bytes. + layout.align.abi.min(pack).bytes() } else { - size_as_align - }; - size_as_align as u64 + // Returns `log2(effective-align)`. The calculation assumes that size is an + // integer multiple of align, except for ZSTs. + let align = layout.align.abi.bytes(); + let size = layout.size.bytes(); + let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0); + // Group [u8; 4] with align-4 or [u8; 6] with align-2 fields. + let size_as_align = align.max(size).trailing_zeros(); + let size_as_align = if largest_niche_size > 0 { + match niche_bias { + // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the + // array to the front in the first case (for aligned loads) but keep + // the bool in front in the second case for its niches. + NicheBias::Start => { + max_field_align.trailing_zeros().min(size_as_align) + } + // When moving niches towards the end of the struct then for + // A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple + // in the align-1 group because its bool can be moved closer to the end. + NicheBias::End if niche_size == largest_niche_size => { + align.trailing_zeros() + } + NicheBias::End => size_as_align, + } + } else { + size_as_align + }; + size_as_align as u64 + } + }; + + match kind { + StructKind::AlwaysSized | StructKind::MaybeUnsized => { + // Currently `LayoutS` only exposes a single niche so sorting is usually + // sufficient to get one niche into the preferred position. If it ever + // supported multiple niches then a more advanced pick-and-pack approach could + // provide better results. But even for the single-niche cache it's not + // optimal. E.g. for A(u32, (bool, u8), u16) it would be possible to move the + // bool to the front but it would require packing the tuple together with the + // u16 to build a 4-byte group so that the u32 can be placed after it without + // padding. This kind of packing can't be achieved by sorting. + optimizing.sort_by_key(|&x| { + let f = &fields[x]; + let field_size = f.size.bytes(); + let niche_size = f.largest_niche.map_or(0, |n| n.available(dl)); + let niche_size_key = match niche_bias { + // large niche first + NicheBias::Start => !niche_size, + // large niche last + NicheBias::End => niche_size, + }; + let inner_niche_offset_key = match niche_bias { + NicheBias::Start => f.largest_niche.map_or(0, |n| n.offset.bytes()), + NicheBias::End => f.largest_niche.map_or(0, |n| { + !(field_size - n.value.size(dl).bytes() - n.offset.bytes()) + }), + }; + + ( + // Then place largest alignments first. + cmp::Reverse(alignment_group_key(f)), + // Then prioritize niche placement within alignment group according to + // `niche_bias_start`. + niche_size_key, + // Then among fields with equally-sized niches prefer the ones + // closer to the start/end of the field. + inner_niche_offset_key, + ) + }); + } + + StructKind::Prefixed(..) => { + // Sort in ascending alignment so that the layout stays optimal + // regardless of the prefix. + // And put the largest niche in an alignment group at the end + // so it can be used as discriminant in jagged enums + optimizing.sort_by_key(|&x| { + let f = &fields[x]; + let niche_size = f.largest_niche.map_or(0, |n| n.available(dl)); + (alignment_group_key(f), niche_size) + }); + } } - }; - match kind { - StructKind::AlwaysSized | StructKind::MaybeUnsized => { - // Currently `LayoutS` only exposes a single niche so sorting is usually - // sufficient to get one niche into the preferred position. If it ever - // supported multiple niches then a more advanced pick-and-pack approach could - // provide better results. But even for the single-niche cache it's not - // optimal. E.g. for A(u32, (bool, u8), u16) it would be possible to move the - // bool to the front but it would require packing the tuple together with the - // u16 to build a 4-byte group so that the u32 can be placed after it without - // padding. This kind of packing can't be achieved by sorting. - optimizing.sort_by_key(|&x| { - let f = &fields[x]; - let field_size = f.size.bytes(); - let niche_size = f.largest_niche.map_or(0, |n| n.available(dl)); - let niche_size_key = match niche_bias { - // large niche first - NicheBias::Start => !niche_size, - // large niche last - NicheBias::End => niche_size, - }; - let inner_niche_offset_key = match niche_bias { - NicheBias::Start => f.largest_niche.map_or(0, |n| n.offset.bytes()), - NicheBias::End => f.largest_niche.map_or(0, |n| { - !(field_size - n.value.size(dl).bytes() - n.offset.bytes()) - }), - }; + // FIXME(Kixiron): We can always shuffle fields within a given alignment class + // regardless of the status of `-Z randomize-layout` + } + } + // inverse_memory_index holds field indices by increasing memory offset. + // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5. + // We now write field offsets to the corresponding offset slot; + // field 5 with offset 0 puts 0 in offsets[5]. + // At the bottom of this function, we invert `inverse_memory_index` to + // produce `memory_index` (see `invert_mapping`). + let mut unsized_field = None::<&F>; + let mut offsets = IndexVec::from_elem(Size::ZERO, fields); + let mut offset = Size::ZERO; + let mut largest_niche = None; + let mut largest_niche_available = 0; + if let StructKind::Prefixed(prefix_size, prefix_align) = kind { + let prefix_align = + if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align }; + align = align.max(AbiAndPrefAlign::new(prefix_align)); + offset = prefix_size.align_to(prefix_align); + } + for &i in &inverse_memory_index { + let field = &fields[i]; + if let Some(unsized_field) = unsized_field { + return Err(LayoutCalculatorError::UnexpectedUnsized(*unsized_field)); + } - ( - // Then place largest alignments first. - cmp::Reverse(alignment_group_key(f)), - // Then prioritize niche placement within alignment group according to - // `niche_bias_start`. - niche_size_key, - // Then among fields with equally-sized niches prefer the ones - // closer to the start/end of the field. - inner_niche_offset_key, - ) - }); + if field.is_unsized() { + if let StructKind::MaybeUnsized = kind { + unsized_field = Some(field); + } else { + return Err(LayoutCalculatorError::UnexpectedUnsized(*field)); } + } + + // Invariant: offset < dl.obj_size_bound() <= 1<<61 + let field_align = if let Some(pack) = pack { + field.align.min(AbiAndPrefAlign::new(pack)) + } else { + field.align + }; + offset = offset.align_to(field_align.abi); + align = align.max(field_align); + max_repr_align = max_repr_align.max(field.max_repr_align); + + debug!("univariant offset: {:?} field: {:#?}", offset, field); + offsets[i] = offset; - StructKind::Prefixed(..) => { - // Sort in ascending alignment so that the layout stays optimal - // regardless of the prefix. - // And put the largest niche in an alignment group at the end - // so it can be used as discriminant in jagged enums - optimizing.sort_by_key(|&x| { - let f = &fields[x]; - let niche_size = f.largest_niche.map_or(0, |n| n.available(dl)); - (alignment_group_key(f), niche_size) - }); + if let Some(mut niche) = field.largest_niche { + let available = niche.available(dl); + // Pick up larger niches. + let prefer_new_niche = match niche_bias { + NicheBias::Start => available > largest_niche_available, + // if there are several niches of the same size then pick the last one + NicheBias::End => available >= largest_niche_available, + }; + if prefer_new_niche { + largest_niche_available = available; + niche.offset += offset; + largest_niche = Some(niche); } } - // FIXME(Kixiron): We can always shuffle fields within a given alignment class - // regardless of the status of `-Z randomize-layout` - } - } - // inverse_memory_index holds field indices by increasing memory offset. - // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5. - // We now write field offsets to the corresponding offset slot; - // field 5 with offset 0 puts 0 in offsets[5]. - // At the bottom of this function, we invert `inverse_memory_index` to - // produce `memory_index` (see `invert_mapping`). - let mut sized = true; - let mut offsets = IndexVec::from_elem(Size::ZERO, fields); - let mut offset = Size::ZERO; - let mut largest_niche = None; - let mut largest_niche_available = 0; - if let StructKind::Prefixed(prefix_size, prefix_align) = kind { - let prefix_align = - if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align }; - align = align.max(AbiAndPrefAlign::new(prefix_align)); - offset = prefix_size.align_to(prefix_align); - } - for &i in &inverse_memory_index { - let field = &fields[i]; - if !sized { - this.delayed_bug(format!( - "univariant: field #{} comes after unsized field", - offsets.len(), - )); + offset = + offset.checked_add(field.size, dl).ok_or(LayoutCalculatorError::SizeOverflow)?; } - if field.is_unsized() { - sized = false; + // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). + // See documentation on `LayoutS::unadjusted_abi_align`. + let unadjusted_abi_align = align.abi; + if let Some(repr_align) = repr.align { + align = align.max(AbiAndPrefAlign::new(repr_align)); } + // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate. + let align = align; - // Invariant: offset < dl.obj_size_bound() <= 1<<61 - let field_align = if let Some(pack) = pack { - field.align.min(AbiAndPrefAlign::new(pack)) + debug!("univariant min_size: {:?}", offset); + let min_size = offset; + // As stated above, inverse_memory_index holds field indices by increasing offset. + // This makes it an already-sorted view of the offsets vec. + // To invert it, consider: + // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0. + // Field 5 would be the first element, so memory_index is i: + // Note: if we didn't optimize, it's already right. + let memory_index = if optimize_field_order { + inverse_memory_index.invert_bijective_mapping() } else { - field.align + debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices())); + inverse_memory_index.into_iter().map(|it| it.index() as u32).collect() }; - offset = offset.align_to(field_align.abi); - align = align.max(field_align); - max_repr_align = max_repr_align.max(field.max_repr_align); - - debug!("univariant offset: {:?} field: {:#?}", offset, field); - offsets[i] = offset; - - if let Some(mut niche) = field.largest_niche { - let available = niche.available(dl); - // Pick up larger niches. - let prefer_new_niche = match niche_bias { - NicheBias::Start => available > largest_niche_available, - // if there are several niches of the same size then pick the last one - NicheBias::End => available >= largest_niche_available, - }; - if prefer_new_niche { - largest_niche_available = available; - niche.offset += offset; - largest_niche = Some(niche); - } + let size = min_size.align_to(align.abi); + // FIXME(oli-obk): deduplicate and harden these checks + if size.bytes() >= dl.obj_size_bound() { + return Err(LayoutCalculatorError::SizeOverflow); } + let mut layout_of_single_non_zst_field = None; + let sized = unsized_field.is_none(); + let mut abi = Abi::Aggregate { sized }; - offset = offset.checked_add(field.size, dl)?; - } + let optimize_abi = !repr.inhibit_newtype_abi_optimization(); - // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). - // See documentation on `LayoutS::unadjusted_abi_align`. - let unadjusted_abi_align = align.abi; - if let Some(repr_align) = repr.align { - align = align.max(AbiAndPrefAlign::new(repr_align)); - } - // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate. - let align = align; - - debug!("univariant min_size: {:?}", offset); - let min_size = offset; - // As stated above, inverse_memory_index holds field indices by increasing offset. - // This makes it an already-sorted view of the offsets vec. - // To invert it, consider: - // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0. - // Field 5 would be the first element, so memory_index is i: - // Note: if we didn't optimize, it's already right. - let memory_index = if optimize { - inverse_memory_index.invert_bijective_mapping() - } else { - debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices())); - inverse_memory_index.into_iter().map(|it| it.index() as u32).collect() - }; - let size = min_size.align_to(align.abi); - // FIXME(oli-obk): deduplicate and harden these checks - if size.bytes() >= dl.obj_size_bound() { - return None; - } - let mut layout_of_single_non_zst_field = None; - let mut abi = Abi::Aggregate { sized }; - // Try to make this a Scalar/ScalarPair. - if sized && size.bytes() > 0 { - // We skip *all* ZST here and later check if we are good in terms of alignment. - // This lets us handle some cases involving aligned ZST. - let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.is_zst()); - - match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { - // We have exactly one non-ZST field. - (Some((i, field)), None, None) => { - layout_of_single_non_zst_field = Some(field); - - // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size { - match field.abi { - // For plain scalars, or vectors of them, we can't unpack - // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize => { - abi = field.abi; - } - // But scalar pairs are Rust-specific and get - // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi; + // Try to make this a Scalar/ScalarPair. + if sized && size.bytes() > 0 { + // We skip *all* ZST here and later check if we are good in terms of alignment. + // This lets us handle some cases involving aligned ZST. + let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.is_zst()); + + match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { + // We have exactly one non-ZST field. + (Some((i, field)), None, None) => { + layout_of_single_non_zst_field = Some(field); + + // Field fills the struct and it has a scalar or scalar pair ABI. + if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size + { + match field.abi { + // For plain scalars, or vectors of them, we can't unpack + // newtypes for `#[repr(C)]`, as that affects C ABIs. + Abi::Scalar(_) | Abi::Vector { .. } if optimize_abi => { + abi = field.abi; + } + // But scalar pairs are Rust-specific and get + // treated as aggregates by C ABIs anyway. + Abi::ScalarPair(..) => { + abi = field.abi; + } + _ => {} } - _ => {} } } - } - // Two non-ZST fields, and they're both scalars. - (Some((i, a)), Some((j, b)), None) => { - match (a.abi, b.abi) { - (Abi::Scalar(a), Abi::Scalar(b)) => { - // Order by the memory placement, not source order. - let ((i, a), (j, b)) = if offsets[i] < offsets[j] { - ((i, a), (j, b)) - } else { - ((j, b), (i, a)) - }; - let pair = this.scalar_pair::(a, b); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index.raw, [0, 1]); - offsets + // Two non-ZST fields, and they're both scalars. + (Some((i, a)), Some((j, b)), None) => { + match (a.abi, b.abi) { + (Abi::Scalar(a), Abi::Scalar(b)) => { + // Order by the memory placement, not source order. + let ((i, a), (j, b)) = if offsets[i] < offsets[j] { + ((i, a), (j, b)) + } else { + ((j, b), (i, a)) + }; + let pair = self.scalar_pair::(a, b); + let pair_offsets = match pair.fields { + FieldsShape::Arbitrary { ref offsets, ref memory_index } => { + assert_eq!(memory_index.raw, [0, 1]); + offsets + } + FieldsShape::Primitive + | FieldsShape::Array { .. } + | FieldsShape::Union(..) => { + panic!("encountered a non-arbitrary layout during enum layout") + } + }; + if offsets[i] == pair_offsets[FieldIdx::new(0)] + && offsets[j] == pair_offsets[FieldIdx::new(1)] + && align == pair.align + && size == pair.size + { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; } - FieldsShape::Primitive - | FieldsShape::Array { .. } - | FieldsShape::Union(..) => { - panic!("encountered a non-arbitrary layout during enum layout") - } - }; - if offsets[i] == pair_offsets[FieldIdx::new(0)] - && offsets[j] == pair_offsets[FieldIdx::new(1)] - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; } + _ => {} } - _ => {} } - } - _ => {} + _ => {} + } + } + if fields.iter().any(|f| f.abi.is_uninhabited()) { + abi = Abi::Uninhabited; } - } - if fields.iter().any(|f| f.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } - let unadjusted_abi_align = if repr.transparent() { - match layout_of_single_non_zst_field { - Some(l) => l.unadjusted_abi_align, - None => { - // `repr(transparent)` with all ZST fields. - align.abi + let unadjusted_abi_align = if repr.transparent() { + match layout_of_single_non_zst_field { + Some(l) => l.unadjusted_abi_align, + None => { + // `repr(transparent)` with all ZST fields. + align.abi + } } - } - } else { - unadjusted_abi_align - }; - - Some(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Arbitrary { offsets, memory_index }, - abi, - largest_niche, - align, - size, - max_repr_align, - unadjusted_abi_align, - }) -} + } else { + unadjusted_abi_align + }; -fn format_field_niches< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, ->( - layout: &LayoutS, - fields: &IndexSlice, - dl: &TargetDataLayout, -) -> String { - let mut s = String::new(); - for i in layout.fields.index_by_increasing_offset() { - let offset = layout.fields.offset(i); - let f = &fields[FieldIdx::new(i)]; - write!(s, "[o{}a{}s{}", offset.bytes(), f.align.abi.bytes(), f.size.bytes()).unwrap(); - if let Some(n) = f.largest_niche { - write!( - s, - " n{}b{}s{}", - n.offset.bytes(), - n.available(dl).ilog2(), - n.value.size(dl).bytes() - ) - .unwrap(); + Ok(LayoutS { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Arbitrary { offsets, memory_index }, + abi, + largest_niche, + align, + size, + max_repr_align, + unadjusted_abi_align, + }) + } + + fn format_field_niches< + 'a, + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug, + >( + &self, + layout: &LayoutS, + fields: &IndexSlice, + ) -> String { + let dl = self.cx.data_layout(); + let mut s = String::new(); + for i in layout.fields.index_by_increasing_offset() { + let offset = layout.fields.offset(i); + let f = &fields[FieldIdx::new(i)]; + write!(s, "[o{}a{}s{}", offset.bytes(), f.align.abi.bytes(), f.size.bytes()).unwrap(); + if let Some(n) = f.largest_niche { + write!( + s, + " n{}b{}s{}", + n.offset.bytes(), + n.available(dl).ilog2(), + n.value.size(dl).bytes() + ) + .unwrap(); + } + write!(s, "] ").unwrap(); } - write!(s, "] ").unwrap(); + s } - s } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index df29b3d54f0fb..fa7c98a7fa0cc 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -26,7 +26,7 @@ mod layout; #[cfg(test)] mod tests; -pub use layout::LayoutCalculator; +pub use layout::{LayoutCalculator, LayoutCalculatorError}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro @@ -43,14 +43,17 @@ bitflags! { const IS_SIMD = 1 << 1; const IS_TRANSPARENT = 1 << 2; // Internal only for now. If true, don't reorder fields. + // On its own it does not prevent ABI optimizations. const IS_LINEAR = 1 << 3; - // If true, the type's layout can be randomized using - // the seed stored in `ReprOptions.field_shuffle_seed` + // If true, the type's crate has opted into layout randomization. + // Other flags can still inhibit reordering and thus randomization. + // The seed stored in `ReprOptions.field_shuffle_seed`. const RANDOMIZE_LAYOUT = 1 << 4; // Any of these flags being set prevent field reordering optimisation. - const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits() + const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits() | ReprFlags::IS_LINEAR.bits(); + const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits(); } } @@ -139,10 +142,14 @@ impl ReprOptions { self.c() || self.int.is_some() } + pub fn inhibit_newtype_abi_optimization(&self) -> bool { + self.flags.intersects(ReprFlags::ABI_UNOPTIMIZABLE) + } + /// Returns `true` if this `#[repr()]` guarantees a fixed field order, /// e.g. `repr(C)` or `repr()`. pub fn inhibit_struct_field_reordering(&self) -> bool { - self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some() + self.flags.intersects(ReprFlags::FIELD_ORDER_UNOPTIMIZABLE) || self.int.is_some() } /// Returns `true` if this type is valid for reordering and `-Z randomize-layout` @@ -330,23 +337,21 @@ impl TargetDataLayout { Ok(dl) } - /// Returns exclusive upper bound on object size. + /// Returns **exclusive** upper bound on object size in bytes. /// /// The theoretical maximum object size is defined as the maximum positive `isize` value. /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly /// index every address within an object along with one byte past the end, along with allowing /// `isize` to store the difference between any two pointers into an object. /// - /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer - /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is - /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable - /// address space on 64-bit ARMv8 and x86_64. + /// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes, + /// so we adopt such a more-constrained size bound due to its technical limitations. #[inline] pub fn obj_size_bound(&self) -> u64 { match self.pointer_size.bits() { 16 => 1 << 15, 32 => 1 << 31, - 64 => 1 << 47, + 64 => 1 << 61, bits => panic!("obj_size_bound: unknown pointer bit size {bits}"), } } @@ -386,6 +391,14 @@ impl HasDataLayout for TargetDataLayout { } } +// used by rust-analyzer +impl HasDataLayout for &TargetDataLayout { + #[inline] + fn data_layout(&self) -> &TargetDataLayout { + (**self).data_layout() + } +} + /// Endianness of the target, which must match cfg(target-endian). #[derive(Copy, Clone, PartialEq, Eq)] pub enum Endian { @@ -774,6 +787,14 @@ impl Align { } /// A pair of alignments, ABI-mandated and preferred. +/// +/// The "preferred" alignment is an LLVM concept that is virtually meaningless to Rust code: +/// it is not exposed semantically to programmers nor can they meaningfully affect it. +/// The only concern for us is that preferred alignment must not be less than the mandated alignment +/// and thus in practice the two values are almost always identical. +/// +/// An example of a rare thing actually affected by preferred alignment is aligning of statics. +/// It is of effectively no consequence for layout in structs and on the stack. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] pub struct AbiAndPrefAlign { @@ -810,6 +831,28 @@ pub enum Integer { } impl Integer { + pub fn int_ty_str(self) -> &'static str { + use Integer::*; + match self { + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + I128 => "i128", + } + } + + pub fn uint_ty_str(self) -> &'static str { + use Integer::*; + match self { + I8 => "u8", + I16 => "u16", + I32 => "u32", + I64 => "u64", + I128 => "u128", + } + } + #[inline] pub fn size(self) -> Size { use Integer::*; @@ -1095,13 +1138,10 @@ impl Scalar { #[inline] pub fn is_bool(&self) -> bool { use Integer::*; - matches!( - self, - Scalar::Initialized { - value: Primitive::Int(I8, false), - valid_range: WrappingRange { start: 0, end: 1 } - } - ) + matches!(self, Scalar::Initialized { + value: Primitive::Int(I8, false), + valid_range: WrappingRange { start: 0, end: 1 } + }) } /// Get the primitive representation of this type, ignoring the valid range and whether the diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 260c9fe44ba80..cecf223b96193 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -614,34 +614,34 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized { #[allow(clippy::mut_from_ref)] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; + fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self; #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, + fn allocate_from_iter( + arena: &'tcx Arena<'tcx>, iter: impl ::std::iter::IntoIterator, - ) -> &'a mut [Self]; + ) -> &'tcx mut [Self]; } // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`. impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T { #[inline] #[allow(clippy::mut_from_ref)] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { + fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self { arena.dropless.alloc(self) } #[inline] #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, + fn allocate_from_iter( + arena: &'tcx Arena<'tcx>, iter: impl ::std::iter::IntoIterator, - ) -> &'a mut [Self] { + ) -> &'tcx mut [Self] { arena.dropless.alloc_from_iter(iter) } } $( impl<'tcx> ArenaAllocatable<'tcx, rustc_arena::IsNotCopy> for $ty { #[inline] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { + fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self { if !::std::mem::needs_drop::() { arena.dropless.alloc(self) } else { @@ -651,10 +651,10 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { #[inline] #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, + fn allocate_from_iter( + arena: &'tcx Arena<'tcx>, iter: impl ::std::iter::IntoIterator, - ) -> &'a mut [Self] { + ) -> &'tcx mut [Self] { if !::std::mem::needs_drop::() { arena.dropless.alloc_from_iter(iter) } else { @@ -667,7 +667,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { impl<'tcx> Arena<'tcx> { #[inline] #[allow(clippy::mut_from_ref)] - pub fn alloc, C>(&self, value: T) -> &mut T { + pub fn alloc, C>(&'tcx self, value: T) -> &mut T { value.allocate_on(self) } @@ -691,7 +691,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { #[allow(clippy::mut_from_ref)] pub fn alloc_from_iter, C>( - &self, + &'tcx self, iter: impl ::std::iter::IntoIterator, ) -> &mut [T] { T::allocate_from_iter(self, iter) diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index d33f9666b484c..34c612dac692b 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -4,10 +4,9 @@ version = "0.0.0" edition = "2021" [dependencies] -# FIXME: bumping memchr to 2.7.1 causes linker errors in MSVC thin-lto # tidy-alphabetical-start bitflags = "2.4.1" -memchr = "=2.5.0" +memchr = "2.7.4" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 85d38a0e28b0f..37f429cce44d7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -21,19 +21,19 @@ use std::borrow::Cow; use std::{cmp, fmt, mem}; +pub use GenericArgs::*; +pub use UnsafeSource::*; pub use rustc_ast_ir::{Movability, Mutability}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; -use rustc_span::source_map::{respan, Spanned}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; pub use rustc_span::AttrId; -use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; -use thin_vec::{thin_vec, ThinVec}; -pub use GenericArgs::*; -pub use UnsafeSource::*; +use rustc_span::source_map::{Spanned, respan}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; +use thin_vec::{ThinVec, thin_vec}; pub use crate::format::*; use crate::ptr::P; @@ -288,7 +288,7 @@ impl ParenthesizedArgs { } } -pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; +pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId}; /// Modifiers on a trait bound like `~const`, `?` and `!`. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] @@ -1187,15 +1187,8 @@ impl Expr { /// `min_const_generics` as more complex expressions are not supported. /// /// Does not ensure that the path resolves to a const param, the caller should check this. - pub fn is_potential_trivial_const_arg(&self) -> bool { - let this = if let ExprKind::Block(block, None) = &self.kind - && let [stmt] = block.stmts.as_slice() - && let StmtKind::Expr(expr) = &stmt.kind - { - expr - } else { - self - }; + pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool { + let this = if strip_identity_block { self.maybe_unwrap_block().1 } else { self }; if let ExprKind::Path(None, path) = &this.kind && path.is_potential_trivial_const_arg() @@ -1206,6 +1199,18 @@ impl Expr { } } + /// Returns an expression with (when possible) *one* outter brace removed + pub fn maybe_unwrap_block(&self) -> (bool, &Expr) { + if let ExprKind::Block(block, None) = &self.kind + && let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind + { + (true, expr) + } else { + (false, self) + } + } + pub fn to_bound(&self) -> Option { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( @@ -1289,7 +1294,7 @@ impl Expr { ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node), ExprKind::Unary(..) => ExprPrecedence::Unary, ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit, - ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, + ExprKind::Cast(..) => ExprPrecedence::Cast, ExprKind::Let(..) => ExprPrecedence::Let, ExprKind::If(..) => ExprPrecedence::If, ExprKind::While(..) => ExprPrecedence::While, @@ -1313,17 +1318,18 @@ impl Expr { ExprKind::Break(..) => ExprPrecedence::Break, ExprKind::Continue(..) => ExprPrecedence::Continue, ExprKind::Ret(..) => ExprPrecedence::Ret, - ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm, - ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf, - ExprKind::MacCall(..) => ExprPrecedence::Mac, ExprKind::Struct(..) => ExprPrecedence::Struct, ExprKind::Repeat(..) => ExprPrecedence::Repeat, ExprKind::Paren(..) => ExprPrecedence::Paren, ExprKind::Try(..) => ExprPrecedence::Try, ExprKind::Yield(..) => ExprPrecedence::Yield, ExprKind::Yeet(..) => ExprPrecedence::Yeet, - ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs, ExprKind::Become(..) => ExprPrecedence::Become, + ExprKind::InlineAsm(..) + | ExprKind::Type(..) + | ExprKind::OffsetOf(..) + | ExprKind::FormatArgs(..) + | ExprKind::MacCall(..) => ExprPrecedence::Mac, ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err, } } @@ -2418,11 +2424,22 @@ impl InlineAsmOperand { } } +#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic)] +pub enum AsmMacro { + /// The `asm!` macro + Asm, + /// The `global_asm!` macro + GlobalAsm, + /// The `naked_asm!` macro + NakedAsm, +} + /// Inline assembly. /// /// E.g., `asm!("NOP");`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct InlineAsm { + pub asm_macro: AsmMacro, pub template: Vec, pub template_strs: Box<[(Symbol, Option, Span)]>, pub operands: Vec<(InlineAsmOperand, Span)>, @@ -2591,12 +2608,12 @@ impl CoroutineKind { } } - pub fn is_async(self) -> bool { - matches!(self, CoroutineKind::Async { .. }) - } - - pub fn is_gen(self) -> bool { - matches!(self, CoroutineKind::Gen { .. }) + pub fn as_str(self) -> &'static str { + match self { + CoroutineKind::Async { .. } => "async", + CoroutineKind::Gen { .. } => "gen", + CoroutineKind::AsyncGen { .. } => "async gen", + } } pub fn closure_id(self) -> NodeId { @@ -3475,7 +3492,7 @@ impl From for ItemKind { fn from(foreign_item_kind: ForeignItemKind) -> ItemKind { match foreign_item_kind { ForeignItemKind::Static(box static_foreign_item) => { - ItemKind::Static(Box::new(static_foreign_item.into())) + ItemKind::Static(Box::new(static_foreign_item)) } ForeignItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind), ForeignItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), @@ -3489,9 +3506,7 @@ impl TryFrom for ForeignItemKind { fn try_from(item_kind: ItemKind) -> Result { Ok(match item_kind { - ItemKind::Static(box static_item) => { - ForeignItemKind::Static(Box::new(static_item.into())) - } + ItemKind::Static(box static_item) => ForeignItemKind::Static(Box::new(static_item)), ItemKind::Fn(fn_kind) => ForeignItemKind::Fn(fn_kind), ItemKind::TyAlias(ty_alias_kind) => ForeignItemKind::TyAlias(ty_alias_kind), ItemKind::MacCall(a) => ForeignItemKind::MacCall(a), diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 6b95fb7dd36b8..60f8c6e10481b 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -153,7 +153,7 @@ impl HasTokens for StmtKind { StmtKind::Let(local) => local.tokens.as_ref(), StmtKind::Item(item) => item.tokens(), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(), - StmtKind::Empty => return None, + StmtKind::Empty => None, StmtKind::MacCall(mac) => mac.tokens.as_ref(), } } @@ -162,7 +162,7 @@ impl HasTokens for StmtKind { StmtKind::Let(local) => Some(&mut local.tokens), StmtKind::Item(item) => item.tokens_mut(), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(), - StmtKind::Empty => return None, + StmtKind::Empty => None, StmtKind::MacCall(mac) => Some(&mut mac.tokens), } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 94a00ab1a047e..124d0acfa4912 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -4,15 +4,15 @@ use std::iter; use std::sync::atomic::{AtomicU32, Ordering}; use rustc_index::bit_set::GrowableBitSet; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use smallvec::{smallvec, SmallVec}; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, Symbol, sym}; +use smallvec::{SmallVec, smallvec}; +use thin_vec::{ThinVec, thin_vec}; use crate::ast::{ - AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DelimArgs, - Expr, ExprKind, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NormalAttr, Path, - PathSegment, Safety, DUMMY_NODE_ID, + AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, + DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, + NormalAttr, Path, PathSegment, Safety, }; use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter, Token}; diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index 60a12614f06e8..45c4caca6e9ee 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -1,7 +1,7 @@ -use rustc_span::symbol::sym; use rustc_span::Symbol; +use rustc_span::symbol::sym; -use crate::{attr, Attribute}; +use crate::{Attribute, attr}; #[derive(Debug)] pub enum EntryPointType { @@ -45,18 +45,16 @@ pub fn entry_point_type( EntryPointType::Start } else if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr - } else { - if let Some(name) = name - && name == sym::main - { - if at_root { - // This is a top-level function so it can be `main`. - EntryPointType::MainNamed - } else { - EntryPointType::OtherMain - } + } else if let Some(name) = name + && name == sym::main + { + if at_root { + // This is a top-level function so it can be `main`. + EntryPointType::MainNamed } else { - EntryPointType::None + EntryPointType::OtherMain } + } else { + EntryPointType::None } } diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index 1723501d0fec0..bee7dfb61da87 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -1,5 +1,5 @@ use rustc_macros::HashStable_Generic; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; #[derive(Clone, Debug, Copy, Eq, PartialEq, HashStable_Generic)] pub enum AllocatorKind { diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index e72d32d9b752d..d5900d83e4d1a 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -1,10 +1,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_macros::{Decodable, Encodable}; -use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol}; -use crate::ptr::P; use crate::Expr; +use crate::ptr::P; // Definitions: // diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 8a66894a35603..104f84f26e0af 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -13,10 +13,10 @@ use std::panic; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; +use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::Span; -use smallvec::{smallvec, Array, SmallVec}; +use smallvec::{Array, SmallVec, smallvec}; use thin_vec::ThinVec; use crate::ast::*; @@ -752,7 +752,7 @@ fn visit_lazy_tts(vis: &mut T, lazy_tts: &mut Option(vis: &mut T, t: &mut Token) { let Token { kind, span } = t; match kind { - token::Ident(name, _ /*raw*/) | token::Lifetime(name) => { + token::Ident(name, _is_raw) | token::Lifetime(name, _is_raw) => { let mut ident = Ident::new(*name, *span); vis.visit_ident(&mut ident); *name = ident.name; @@ -762,7 +762,7 @@ pub fn visit_token(vis: &mut T, t: &mut Token) { token::NtIdent(ident, _is_raw) => { vis.visit_ident(ident); } - token::NtLifetime(ident) => { + token::NtLifetime(ident, _is_raw) => { vis.visit_ident(ident); } token::Interpolated(nt) => { @@ -1388,6 +1388,7 @@ fn walk_anon_const(vis: &mut T, AnonConst { id, value }: &mut Ano fn walk_inline_asm(vis: &mut T, asm: &mut InlineAsm) { // FIXME: Visit spans inside all this currently ignored stuff. let InlineAsm { + asm_macro: _, template: _, template_strs: _, operands, diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index f1dddb3acacaa..1d6abbef06c95 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1,21 +1,21 @@ use std::borrow::Cow; use std::fmt; +pub use BinOpToken::*; +pub use LitKind::*; +pub use Nonterminal::*; +pub use NtExprKind::*; +pub use NtPatKind::*; +pub use TokenKind::*; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; -use rustc_span::symbol::{kw, sym}; #[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint. #[allow(hidden_glob_reexports)] use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; -pub use BinOpToken::*; -pub use LitKind::*; -pub use Nonterminal::*; -pub use NtExprKind::*; -pub use NtPatKind::*; -pub use TokenKind::*; +use rustc_span::symbol::{kw, sym}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use crate::ast; use crate::ptr::P; @@ -331,11 +331,11 @@ pub enum TokenKind { /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to /// treat regular and interpolated lifetime identifiers in the same way. - Lifetime(Symbol), + Lifetime(Symbol, IdentIsRaw), /// This identifier (and its span) is the lifetime passed to the /// declarative macro. The span in the surrounding `Token` is the span of /// the `lifetime` metavariable in the macro's RHS. - NtLifetime(Ident), + NtLifetime(Ident, IdentIsRaw), /// An embedded AST node, as produced by a macro. This only exists for /// historical reasons. We'd like to get rid of it, for multiple reasons. @@ -385,35 +385,41 @@ impl TokenKind { Literal(Lit::new(kind, symbol, suffix)) } - /// An approximation to proc-macro-style single-character operators used by rustc parser. - /// If the operator token can be broken into two tokens, the first of which is single-character, - /// then this function performs that operation, otherwise it returns `None`. - pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> { - Some(match *self { - Le => (Lt, Eq), - EqEq => (Eq, Eq), - Ne => (Not, Eq), - Ge => (Gt, Eq), - AndAnd => (BinOp(And), BinOp(And)), - OrOr => (BinOp(Or), BinOp(Or)), - BinOp(Shl) => (Lt, Lt), - BinOp(Shr) => (Gt, Gt), - BinOpEq(Plus) => (BinOp(Plus), Eq), - BinOpEq(Minus) => (BinOp(Minus), Eq), - BinOpEq(Star) => (BinOp(Star), Eq), - BinOpEq(Slash) => (BinOp(Slash), Eq), - BinOpEq(Percent) => (BinOp(Percent), Eq), - BinOpEq(Caret) => (BinOp(Caret), Eq), - BinOpEq(And) => (BinOp(And), Eq), - BinOpEq(Or) => (BinOp(Or), Eq), - BinOpEq(Shl) => (Lt, Le), - BinOpEq(Shr) => (Gt, Ge), - DotDot => (Dot, Dot), - DotDotDot => (Dot, DotDot), - PathSep => (Colon, Colon), - RArrow => (BinOp(Minus), Gt), - LArrow => (Lt, BinOp(Minus)), - FatArrow => (Eq, Gt), + /// An approximation to proc-macro-style single-character operators used by + /// rustc parser. If the operator token can be broken into two tokens, the + /// first of which has `n` (1 or 2) chars, then this function performs that + /// operation, otherwise it returns `None`. + pub fn break_two_token_op(&self, n: u32) -> Option<(TokenKind, TokenKind)> { + assert!(n == 1 || n == 2); + Some(match (self, n) { + (Le, 1) => (Lt, Eq), + (EqEq, 1) => (Eq, Eq), + (Ne, 1) => (Not, Eq), + (Ge, 1) => (Gt, Eq), + (AndAnd, 1) => (BinOp(And), BinOp(And)), + (OrOr, 1) => (BinOp(Or), BinOp(Or)), + (BinOp(Shl), 1) => (Lt, Lt), + (BinOp(Shr), 1) => (Gt, Gt), + (BinOpEq(Plus), 1) => (BinOp(Plus), Eq), + (BinOpEq(Minus), 1) => (BinOp(Minus), Eq), + (BinOpEq(Star), 1) => (BinOp(Star), Eq), + (BinOpEq(Slash), 1) => (BinOp(Slash), Eq), + (BinOpEq(Percent), 1) => (BinOp(Percent), Eq), + (BinOpEq(Caret), 1) => (BinOp(Caret), Eq), + (BinOpEq(And), 1) => (BinOp(And), Eq), + (BinOpEq(Or), 1) => (BinOp(Or), Eq), + (BinOpEq(Shl), 1) => (Lt, Le), // `<` + `<=` + (BinOpEq(Shl), 2) => (BinOp(Shl), Eq), // `<<` + `=` + (BinOpEq(Shr), 1) => (Gt, Ge), // `>` + `>=` + (BinOpEq(Shr), 2) => (BinOp(Shr), Eq), // `>>` + `=` + (DotDot, 1) => (Dot, Dot), + (DotDotDot, 1) => (Dot, DotDot), // `.` + `..` + (DotDotDot, 2) => (DotDot, Dot), // `..` + `.` + (DotDotEq, 2) => (DotDot, Eq), + (PathSep, 1) => (Colon, Colon), + (RArrow, 1) => (BinOp(Minus), Gt), + (LArrow, 1) => (Lt, BinOp(Minus)), + (FatArrow, 1) => (Eq, Gt), _ => return None, }) } @@ -458,7 +464,7 @@ impl Token { /// if they keep spans or perform edition checks. pub fn uninterpolated_span(&self) -> Span { match self.kind { - NtIdent(ident, _) | NtLifetime(ident) => ident.span, + NtIdent(ident, _) | NtLifetime(ident, _) => ident.span, Interpolated(ref nt) => nt.use_span(), _ => self.span, } @@ -661,7 +667,9 @@ impl Token { pub fn uninterpolate(&self) -> Cow<'_, Token> { match self.kind { NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)), - NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)), + NtLifetime(ident, is_raw) => { + Cow::Owned(Token::new(Lifetime(ident.name, is_raw), ident.span)) + } _ => Cow::Borrowed(self), } } @@ -679,11 +687,11 @@ impl Token { /// Returns a lifetime identifier if this token is a lifetime. #[inline] - pub fn lifetime(&self) -> Option { + pub fn lifetime(&self) -> Option<(Ident, IdentIsRaw)> { // We avoid using `Token::uninterpolate` here because it's slow. match self.kind { - Lifetime(name) => Some(Ident::new(name, self.span)), - NtLifetime(ident) => Some(ident), + Lifetime(name, is_raw) => Some((Ident::new(name, self.span), is_raw)), + NtLifetime(ident, is_raw) => Some((ident, is_raw)), _ => None, } } @@ -865,7 +873,7 @@ impl Token { _ => return None, }, SingleQuote => match joint.kind { - Ident(name, IdentIsRaw::No) => Lifetime(Symbol::intern(&format!("'{name}"))), + Ident(name, is_raw) => Lifetime(Symbol::intern(&format!("'{name}")), is_raw), _ => return None, }, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 057b4455dca89..d5c2bc1c7f63c 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -20,7 +20,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{self, Lrc}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; -use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym}; use crate::ast::{AttrStyle, StmtKind}; use crate::ast_traits::{HasAttrs, HasTokens}; @@ -482,11 +482,11 @@ impl TokenStream { token::NtIdent(ident, is_raw) => { TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing) } - token::NtLifetime(ident) => TokenTree::Delimited( + token::NtLifetime(ident, is_raw) => TokenTree::Delimited( DelimSpan::from_single(token.span), DelimSpacing::new(Spacing::JointHidden, spacing), Delimiter::Invisible, - TokenStream::token_alone(token::Lifetime(ident.name), ident.span), + TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), ), token::Interpolated(ref nt) => TokenTree::Delimited( DelimSpan::from_single(token.span), diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 3bd2a80d361ee..498df5a71441b 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -3,10 +3,10 @@ use std::{ascii, fmt, str}; use rustc_lexer::unescape::{ - byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode, + MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, }; -use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, kw, sym}; use tracing::debug; use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 8436c760d1642..d8dad4550c0c5 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -265,10 +265,7 @@ pub enum ExprPrecedence { Field, Index, Try, - InlineAsm, - OffsetOf, Mac, - FormatArgs, Array, Repeat, @@ -333,17 +330,14 @@ impl ExprPrecedence { | ExprPrecedence::ConstBlock | ExprPrecedence::Field | ExprPrecedence::ForLoop - | ExprPrecedence::FormatArgs | ExprPrecedence::Gen | ExprPrecedence::If | ExprPrecedence::Index - | ExprPrecedence::InlineAsm | ExprPrecedence::Lit | ExprPrecedence::Loop | ExprPrecedence::Mac | ExprPrecedence::Match | ExprPrecedence::MethodCall - | ExprPrecedence::OffsetOf | ExprPrecedence::Paren | ExprPrecedence::Path | ExprPrecedence::PostfixMatch diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 7b041768983e6..9f9c3d8c39239 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -15,8 +15,8 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; use crate::ast::*; use crate::ptr::P; @@ -976,6 +976,7 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) -> V::Result { let InlineAsm { + asm_macro: _, template: _, template_strs: _, operands, diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index e077c54496586..88cdb2ec36397 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -8,9 +8,10 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_session::parse::feature_err; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::asm; +use super::LoweringContext; use super::errors::{ AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported, InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, @@ -18,10 +19,9 @@ use super::errors::{ InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict, }; -use super::LoweringContext; use crate::{ - fluent_generated as fluent, ImplTraitContext, ImplTraitPosition, ParamMode, - ResolverAstLoweringExt, + AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, + ResolverAstLoweringExt, fluent_generated as fluent, }; impl<'a, 'hir> LoweringContext<'a, 'hir> { @@ -201,6 +201,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &sym.qself, &sym.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -220,9 +221,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let parent_def_id = self.current_def_id_parent; let node_id = self.next_node_id(); // HACK(min_generic_const_args): see lower_anon_const - if !self.tcx.features().const_arg_path - || !expr.is_potential_trivial_const_arg() - { + if !expr.is_potential_trivial_const_arg(true) { self.create_def( parent_def_id, node_id, @@ -474,8 +473,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); let line_spans = self.arena.alloc_from_iter(asm.line_spans.iter().map(|span| self.lower_span(*span))); - let hir_asm = - hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans }; + let hir_asm = hir::InlineAsm { + asm_macro: asm.asm_macro, + template, + template_strs, + operands, + options: asm.options, + line_spans, + }; self.arena.alloc(hir_asm) } } diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 800773482041a..3b85f1737bdd9 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -46,13 +46,13 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_middle::ty::{Asyncness, ResolverAstLowering}; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; use rustc_target::spec::abi; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; -use crate::{ImplTraitPosition, ResolverAstLoweringExt}; +use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt}; pub(crate) struct DelegationResults<'hir> { pub body_id: hir::BodyId, @@ -72,7 +72,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn has_self(&self, def_id: DefId, span: Span) -> bool { if let Some(local_sig_id) = def_id.as_local() { // The value may be missing due to recursive delegation. - // Error will be emmited later during HIR ty lowering. + // Error will be emitted later during HIR ty lowering. self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self) } else { match self.tcx.def_kind(def_id) { @@ -139,7 +139,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) { if let Some(local_sig_id) = sig_id.as_local() { // Map may be filled incorrectly due to recursive delegation. - // Error will be emmited later during HIR ty lowering. + // Error will be emitted later during HIR ty lowering. match self.resolver.delegation_fn_sigs.get(&local_sig_id) { Some(sig) => (sig.param_count, sig.c_variadic), None => (0, false), @@ -340,6 +340,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &delegation.qself, &delegation.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a6c7714a182bf..52372bbf991c9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -4,14 +4,14 @@ use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::HirId; +use rustc_hir::def::{DefKind, Res}; use rustc_middle::span_bug; use rustc_session::errors::report_lit_error; -use rustc_span::source_map::{respan, Spanned}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{DesugaringKind, Span, DUMMY_SP}; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::source_map::{Spanned, respan}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Span}; +use thin_vec::{ThinVec, thin_vec}; use super::errors::{ AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, @@ -23,7 +23,7 @@ use super::{ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, }; use crate::errors::YieldInClosure; -use crate::{fluent_generated, FnDeclKind, ImplTraitPosition}; +use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated}; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP]) -> &'hir [hir::Expr<'hir>] { @@ -281,6 +281,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -328,6 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, )), @@ -387,7 +389,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let node_id = self.next_node_id(); // HACK(min_generic_const_args): see lower_anon_const - if !self.tcx.features().const_arg_path || !arg.is_potential_trivial_const_arg() { + if !arg.is_potential_trivial_const_arg(true) { // Add a definition for the in-band const def. self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); } @@ -723,18 +725,15 @@ impl<'hir> LoweringContext<'_, 'hir> { span, Some(self.allow_gen_future.clone()), ); - self.lower_attrs( - inner_hir_id, - &[Attribute { - kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( - sym::track_caller, - span, - )))), - id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(), - style: AttrStyle::Outer, - span: unstable_span, - }], - ); + self.lower_attrs(inner_hir_id, &[Attribute { + kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( + sym::track_caller, + span, + )))), + id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(), + style: AttrStyle::Outer, + span: unstable_span, + }]); } } @@ -1291,6 +1290,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -1311,6 +1311,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -1336,6 +1337,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -1837,7 +1839,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Safety::Default, sym::allow, sym::unreachable_code, - self.lower_span(span), + try_span, ); let attrs: AttrVec = thin_vec![attr]; diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 8c742d2aaf436..653116e1fe00d 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -6,8 +6,8 @@ use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_session::config::FmtDebug; -use rustc_span::symbol::{kw, Ident}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::symbol::{Ident, kw}; +use rustc_span::{Span, Symbol, sym}; use super::LoweringContext; @@ -363,16 +363,13 @@ fn make_format_spec<'hir>( debug_hex, } = &placeholder.format_options; let fill = ctx.expr_char(sp, fill.unwrap_or(' ')); - let align = ctx.expr_lang_item_type_relative( - sp, - hir::LangItem::FormatAlignment, - match alignment { + let align = + ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatAlignment, match alignment { Some(FormatAlignment::Left) => sym::Left, Some(FormatAlignment::Right) => sym::Right, Some(FormatAlignment::Center) => sym::Center, None => sym::Unknown, - }, - ); + }); // This needs to match `Flag` in library/core/src/fmt/rt.rs. let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) | ((sign == Some(FormatSign::Minus)) as u32) << 1 diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 23729124e21a9..e77c0fb3a3ed3 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -6,7 +6,7 @@ use rustc_hir::*; use rustc_index::IndexVec; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; /// A visitor that walks over the HIR and collects `Node`s into a HIR map. @@ -78,26 +78,24 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // Make sure that the DepNode of some node coincides with the HirId // owner of that node. - if cfg!(debug_assertions) { - if hir_id.owner != self.owner { - span_bug!( - span, - "inconsistent HirId at `{:?}` for `{:?}`: \ + if cfg!(debug_assertions) && hir_id.owner != self.owner { + span_bug!( + span, + "inconsistent HirId at `{:?}` for `{:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", - self.tcx.sess.source_map().span_to_diagnostic_string(span), - node, - self.tcx - .definitions_untracked() - .def_path(self.owner.def_id) - .to_string_no_crate_verbose(), - self.owner, - self.tcx - .definitions_untracked() - .def_path(hir_id.owner.def_id) - .to_string_no_crate_verbose(), - hir_id.owner, - ) - } + self.tcx.sess.source_map().span_to_diagnostic_string(span), + node, + self.tcx + .definitions_untracked() + .def_path(self.owner.def_id) + .to_string_no_crate_verbose(), + self.owner, + self.tcx + .definitions_untracked() + .def_path(hir_id.owner.def_id) + .to_string_no_crate_verbose(), + hir_id.owner, + ) } self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node }; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c8ec8f308a8aa..7bb3b2fa29095 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -3,17 +3,17 @@ use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::PredicateOrigin; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{DesugaringKind, Span, Symbol}; use rustc_target::spec::abi; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::instrument; @@ -281,16 +281,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ); this.arena.alloc(this.ty(span, hir::TyKind::Err(guar))) } - Some(ty) => this.lower_ty( - ty, - ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(id), - in_assoc_ty: false, - }, - fn_kind: None, + Some(ty) => this.lower_ty(ty, ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(id), + in_assoc_ty: false, }, - ), + fn_kind: None, + }), }, ); hir::ItemKind::TyAlias(ty, generics) @@ -628,13 +625,11 @@ impl<'hir> LoweringContext<'_, 'hir> { .map_or(Const::No, |attr| Const::Yes(attr.span)), _ => Const::No, } + } else if self.tcx.is_const_trait(def_id) { + // FIXME(effects) span + Const::Yes(self.tcx.def_ident_span(def_id).unwrap()) } else { - if self.tcx.is_const_trait(def_id) { - // FIXME(effects) span - Const::Yes(self.tcx.def_ident_span(def_id).unwrap()) - } else { - Const::No - } + Const::No } } else { Const::No @@ -983,16 +978,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Type(ty) } Some(ty) => { - let ty = this.lower_ty( - ty, - ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(i.id), - in_assoc_ty: true, - }, - fn_kind: None, + let ty = this.lower_ty(ty, ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(i.id), + in_assoc_ty: true, }, - ); + fn_kind: None, + }); hir::ImplItemKind::Type(ty) } }, @@ -1131,13 +1123,10 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { self.lower_body(|this| { - ( - &[], - match expr { - Some(expr) => this.lower_expr_mut(expr), - None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), - }, - ) + (&[], match expr { + Some(expr) => this.lower_expr_mut(expr), + None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), + }) }) } @@ -1517,10 +1506,10 @@ impl<'hir> LoweringContext<'_, 'hir> { for bound in &bound_pred.bounds { if !matches!( *bound, - GenericBound::Trait( - _, - TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. } - ) + GenericBound::Trait(_, TraitBoundModifiers { + polarity: BoundPolarity::Maybe(_), + .. + }) ) { continue; } @@ -1621,16 +1610,13 @@ impl<'hir> LoweringContext<'_, 'hir> { self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id))); let const_body = self.lower_body(|this| { - ( - &[], - hir::Expr { - hir_id: const_expr_id, - kind: hir::ExprKind::Lit( - this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), - ), - span, - }, - ) + (&[], hir::Expr { + hir_id: const_expr_id, + kind: hir::ExprKind::Lit( + this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), + ), + span, + }) }); let default_ac = self.arena.alloc(hir::AnonConst { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 754fbae4d023f..c6cb7aa7dd5c2 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -53,7 +53,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::{ self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate, @@ -63,9 +63,9 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::{add_feature_diagnostics, feature_err}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{DesugaringKind, Span, DUMMY_SP}; -use smallvec::{smallvec, SmallVec}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Span}; +use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -485,9 +485,23 @@ enum ParamMode { Optional, } +#[derive(Copy, Clone, Debug)] +enum AllowReturnTypeNotation { + /// Only in types, since RTN is denied later during HIR lowering. + Yes, + /// All other positions (path expr, method, use tree). + No, +} + enum GenericArgsMode { + /// Allow paren sugar, don't allow RTN. ParenSugar, + /// Allow RTN, don't allow paren sugar. + ReturnTypeNotation, + // Error if parenthesized generics or RTN are encountered. Err, + /// Silence errors when lowering generics. Only used with `Res::Err`. + Silence, } impl<'a, 'hir> LoweringContext<'a, 'hir> { @@ -1226,7 +1240,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let id = self.lower_node_id(t.id); - let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx, None); + let qpath = self.lower_qpath( + t.id, + qself, + path, + param_mode, + AllowReturnTypeNotation::Yes, + itctx, + None, + ); self.ty_path(id, t.span, qpath) } @@ -2203,6 +2225,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &None, &p.path, ParamMode::Explicit, + AllowReturnTypeNotation::No, itctx, Some(modifiers), ) { @@ -2335,12 +2358,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, ) -> &'hir hir::ConstArg<'hir> { let ct_kind = match res { - Res::Def(DefKind::ConstParam, _) if self.tcx.features().const_arg_path => { + Res::Def(DefKind::ConstParam, _) => { let qpath = self.lower_qpath( ty_id, &None, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -2410,8 +2434,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); debug!("res={:?}", maybe_res); // FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path - if self.tcx.features().const_arg_path - && let Some(res) = maybe_res + if let Some(res) = maybe_res && let Res::Def(DefKind::ConstParam, _) = res && let ExprKind::Path(qself, path) = &expr.kind { @@ -2420,6 +2443,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -2442,7 +2466,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_const_arg`]. fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst { - if self.tcx.features().const_arg_path && c.value.is_potential_trivial_const_arg() { + if c.value.is_potential_trivial_const_arg(true) { // HACK(min_generic_const_args): see DefCollector::visit_anon_const // Over there, we guess if this is a bare param and only create a def if // we think it's not. However we may can guess wrong (see there for example) diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index 76c957afa5461..1e82ba5db8a2a 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -4,8 +4,8 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::{DefKind, LifetimeRes, Res}; use rustc_middle::span_bug; use rustc_middle::ty::ResolverAstLowering; -use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, kw}; use super::ResolverAstLoweringExt; diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index d82bdd526b707..760f84564f1a2 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -3,15 +3,15 @@ use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::Res; +use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::Span; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, }; use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt}; -use crate::ImplTraitPosition; +use crate::{AllowReturnTypeNotation, ImplTraitPosition}; impl<'a, 'hir> LoweringContext<'a, 'hir> { pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> { @@ -38,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -55,6 +56,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -66,6 +68,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 2ab30eff6d864..e60488fdc8c74 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,13 +1,14 @@ use rustc_ast::{self as ast, *}; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; +use rustc_hir::GenericArg; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::GenericArg; use rustc_middle::span_bug; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP}; -use smallvec::{smallvec, SmallVec}; +use rustc_session::parse::add_feature_diagnostics; +use rustc_span::symbol::{Ident, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span, Symbol}; +use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; use super::errors::{ @@ -15,10 +16,9 @@ use super::errors::{ GenericTypeWithParentheses, UseAngleBrackets, }; use super::{ - GenericArgsCtor, GenericArgsMode, ImplTraitContext, LifetimeRes, LoweringContext, ParamMode, - ResolverAstLoweringExt, + AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition, + LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::ImplTraitPosition; impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "trace", skip(self))] @@ -28,6 +28,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option>, p: &Path, param_mode: ParamMode, + allow_return_type_notation: AllowReturnTypeNotation, itctx: ImplTraitContext, // modifiers of the impl/bound if this is a trait path modifiers: Option, @@ -103,8 +104,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { GenericArgsMode::ParenSugar } + Res::Def(DefKind::AssocFn, _) if i + 1 == proj_start => { + match allow_return_type_notation { + AllowReturnTypeNotation::Yes => GenericArgsMode::ReturnTypeNotation, + AllowReturnTypeNotation::No => GenericArgsMode::Err, + } + } // Avoid duplicated errors. - Res::Err => GenericArgsMode::ParenSugar, + Res::Err => GenericArgsMode::Silence, // An error _ => GenericArgsMode::Err, }; @@ -164,11 +171,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // 3. `<>::IntoIter>::Item` // * final path is `<<>::IntoIter>::Item>::clone` for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { + // If this is a type-dependent `T::method(..)`. + let generic_args_mode = if i + 1 == p.segments.len() + && matches!(allow_return_type_notation, AllowReturnTypeNotation::Yes) + { + GenericArgsMode::ReturnTypeNotation + } else { + GenericArgsMode::Err + }; + let hir_segment = self.arena.alloc(self.lower_path_segment( p.span, segment, param_mode, - GenericArgsMode::Err, + generic_args_mode, itctx, None, )); @@ -238,11 +254,46 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) } GenericArgs::Parenthesized(data) => match generic_args_mode { - GenericArgsMode::ParenSugar => self.lower_parenthesized_parameter_data( - data, - itctx, - bound_modifier_allowed_features, - ), + GenericArgsMode::ReturnTypeNotation => { + let mut err = if !data.inputs.is_empty() { + self.dcx().create_err(BadReturnTypeNotation::Inputs { + span: data.inputs_span, + }) + } else if let FnRetTy::Ty(ty) = &data.output { + self.dcx().create_err(BadReturnTypeNotation::Output { + span: data.inputs_span.shrink_to_hi().to(ty.span), + }) + } else { + self.dcx().create_err(BadReturnTypeNotation::NeedsDots { + span: data.inputs_span, + }) + }; + if !self.tcx.features().return_type_notation + && self.tcx.sess.is_nightly_build() + { + add_feature_diagnostics( + &mut err, + &self.tcx.sess, + sym::return_type_notation, + ); + } + err.emit(); + ( + GenericArgsCtor { + args: Default::default(), + constraints: &[], + parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation, + span: path_span, + }, + false, + ) + } + GenericArgsMode::ParenSugar | GenericArgsMode::Silence => self + .lower_parenthesized_parameter_data( + data, + itctx, + bound_modifier_allowed_features, + ), GenericArgsMode::Err => { // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait` let sub = if !data.inputs.is_empty() { @@ -279,7 +330,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }, GenericArgs::ParenthesizedElided(span) => { - self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span }); + match generic_args_mode { + GenericArgsMode::ReturnTypeNotation | GenericArgsMode::Silence => { + // Ok + } + GenericArgsMode::ParenSugar | GenericArgsMode::Err => { + self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span }); + } + } ( GenericArgsCtor { args: Default::default(), diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index df5c639382f04..c361c35b723d8 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -40,15 +40,15 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect -ast_passes_const_and_async = functions cannot be both `const` and `async` - .const = `const` because of this - .async = `async` because of this - .label = {""} - ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic .const = `const` because of this .variadic = C-variadic because of this +ast_passes_const_and_coroutine = functions cannot be both `const` and `{$coroutine_kind}` + .const = `const` because of this + .coroutine = `{$coroutine_kind}` because of this + .label = {""} + ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types ast_passes_const_without_body = diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ed9672a9e79b3..229d04f8de2fd 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -21,21 +21,21 @@ use std::ops::{Deref, DerefMut}; use itertools::{Either, Itertools}; use rustc_ast::ptr::P; -use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; +use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list}; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::DiagCtxtHandle; use rustc_feature::Features; use rustc_parse::validate_attr; +use rustc_session::Session; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, PATTERNS_IN_FNS_WITHOUT_BODY, }; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; -use rustc_session::Session; -use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, kw, sym}; use rustc_target::spec::abi; use thin_vec::thin_vec; @@ -447,13 +447,13 @@ impl<'a> AstValidator<'a> { fn check_item_safety(&self, span: Span, safety: Safety) { match self.extern_mod_safety { Some(extern_safety) => { - if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) { - if extern_safety == Safety::Default { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { - item_span: span, - block: Some(self.current_extern_span().shrink_to_lo()), - }); - } + if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) + && extern_safety == Safety::Default + { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span: span, + block: Some(self.current_extern_span().shrink_to_lo()), + }); } } None => { @@ -1418,21 +1418,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Functions cannot both be `const async` or `const gen` if let Some(&FnHeader { - constness: Const::Yes(cspan), + constness: Const::Yes(const_span), coroutine_kind: Some(coroutine_kind), .. }) = fk.header() { - let aspan = match coroutine_kind { - CoroutineKind::Async { span: aspan, .. } - | CoroutineKind::Gen { span: aspan, .. } - | CoroutineKind::AsyncGen { span: aspan, .. } => aspan, - }; - // FIXME(gen_blocks): Report a different error for `const gen` - self.dcx().emit_err(errors::ConstAndAsync { - spans: vec![cspan, aspan], - cspan, - aspan, + self.dcx().emit_err(errors::ConstAndCoroutine { + spans: vec![coroutine_kind.span(), const_span], + const_span, + coroutine_span: coroutine_kind.span(), + coroutine_kind: coroutine_kind.as_str(), span, }); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 67c0396333c4b..5cce47ce7bd21 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -657,16 +657,17 @@ pub(crate) enum TildeConstReason { } #[derive(Diagnostic)] -#[diag(ast_passes_const_and_async)] -pub(crate) struct ConstAndAsync { +#[diag(ast_passes_const_and_coroutine)] +pub(crate) struct ConstAndCoroutine { #[primary_span] pub spans: Vec, #[label(ast_passes_const)] - pub cspan: Span, - #[label(ast_passes_async)] - pub aspan: Span, + pub const_span: Span, + #[label(ast_passes_coroutine)] + pub coroutine_span: Span, #[label] pub span: Span, + pub coroutine_kind: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 45e397a58c098..83931a8c1a960 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,12 +1,12 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{attr, token, NodeId, PatKind}; -use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; -use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; +use rustc_ast::{NodeId, PatKind, attr, token}; +use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features, GateIssue}; use rustc_session::Session; +use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use rustc_target::spec::abi; use thin_vec::ThinVec; @@ -75,22 +75,9 @@ struct PostExpansionVisitor<'a> { impl<'a> PostExpansionVisitor<'a> { #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) { + fn check_abi(&self, abi: ast::StrLit) { let ast::StrLit { symbol_unescaped, span, .. } = abi; - if let ast::Const::Yes(_) = constness { - match symbol_unescaped { - // Stable - sym::Rust | sym::C => {} - abi => gate!( - &self, - const_extern_fn, - span, - format!("`{}` as a `const fn` ABI is unstable", abi) - ), - } - } - match abi::is_enabled(self.features, span, symbol_unescaped.as_str()) { Ok(()) => (), Err(abi::AbiDisabled::Unstable { feature, explain }) => { @@ -110,9 +97,9 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn check_extern(&self, ext: ast::Extern, constness: ast::Const) { + fn check_extern(&self, ext: ast::Extern) { if let ast::Extern::Explicit(abi, _) = ext { - self.check_abi(abi, constness); + self.check_abi(abi); } } @@ -239,7 +226,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match &i.kind { ast::ItemKind::ForeignMod(foreign_module) => { if let Some(abi) = foreign_module.abi { - self.check_abi(abi, ast::Const::No); + self.check_abi(abi); } } @@ -341,7 +328,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match &ty.kind { ast::TyKind::BareFn(bare_fn_ty) => { // Function pointers cannot be `const` - self.check_extern(bare_fn_ty.ext, ast::Const::No); + self.check_extern(bare_fn_ty.ext); self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params); } ast::TyKind::Never => { @@ -446,7 +433,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { if let Some(header) = fn_kind.header() { // Stability of const fn methods are covered in `visit_assoc_item` below. - self.check_extern(header.ext, header.constness); + self.check_extern(header.ext); } if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind { @@ -496,6 +483,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { maybe_stage_features(sess, features, krate); check_incompatible_features(sess, features); + check_new_solver_banned_features(sess, features); + let mut visitor = PostExpansionVisitor { sess, features }; let spans = sess.psess.gated_spans.spans.borrow(); @@ -675,3 +664,22 @@ fn check_incompatible_features(sess: &Session, features: &Features) { } } } + +fn check_new_solver_banned_features(sess: &Session, features: &Features) { + if !sess.opts.unstable_opts.next_solver.is_some_and(|n| n.globally) { + return; + } + + // Ban GCE with the new solver, because it does not implement GCE correctly. + if let Some(&(_, gce_span, _)) = features + .declared_lang_features + .iter() + .find(|&&(feat, _, _)| feat == sym::generic_const_exprs) + { + sess.dcx().emit_err(errors::IncompatibleFeatures { + spans: vec![gce_span], + f1: Symbol::intern("-Znext-solver=globally"), + f2: sym::generic_const_exprs, + }); + } +} diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index c61640de6f799..e22e99f6e4d65 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -2,8 +2,8 @@ use rustc_ast::visit::*; use rustc_ast::*; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; pub struct NodeCounter { pub count: usize, diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs index 7559b181f7d41..a1c07bb07e42a 100644 --- a/compiler/rustc_ast_pretty/src/pp/convenience.rs +++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, Token, SIZE_INFINITY}; +use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, SIZE_INFINITY, Token}; impl Printer { /// "raw box" diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index cfcc28ba76fdd..726ceebe3c524 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -7,7 +7,7 @@ use std::borrow::Cow; use rustc_ast as ast; use rustc_ast::token::{Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State}; +pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate}; pub fn nonterminal_to_string(nt: &Nonterminal) -> String { State::new().nonterminal_to_string(nt) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c7ff39d23ed26..7e07ccf28a0cb 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,19 +11,21 @@ use std::borrow::Cow; use ast::TraitBoundModifiers; use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{ + self, BinOpToken, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind, +}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; use rustc_ast::{ - self as ast, attr, AttrArgs, AttrArgsEq, BindingMode, BlockCheckMode, ByRef, DelimArgs, - GenericArg, GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, - InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term, + self as ast, AttrArgs, AttrArgsEq, BindingMode, BlockCheckMode, ByRef, DelimArgs, GenericArg, + GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, + InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr, }; use rustc_span::edition::Edition; use rustc_span::source_map::{SourceMap, Spanned}; -use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol}; -use rustc_span::{BytePos, CharPos, FileName, Pos, Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, IdentPrinter, Symbol, kw, sym}; +use rustc_span::{BytePos, CharPos, DUMMY_SP, FileName, Pos, Span}; use thin_vec::ThinVec; use crate::pp::Breaks::{Consistent, Inconsistent}; @@ -290,9 +292,9 @@ pub fn print_crate<'a>( /// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]` /// fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { - use token::*; use Delimiter::*; use TokenTree::{Delimited as Del, Token as Tok}; + use token::*; fn is_punct(tt: &TokenTree) -> bool { matches!(tt, TokenTree::Token(tok, _) if tok.is_punct()) @@ -947,8 +949,13 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::NtIdent(ident, is_raw) => { IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into() } - token::Lifetime(name) => name.to_string().into(), - token::NtLifetime(ident) => ident.name.to_string().into(), + + token::Lifetime(name, IdentIsRaw::No) + | token::NtLifetime(Ident { name, .. }, IdentIsRaw::No) => name.to_string().into(), + token::Lifetime(name, IdentIsRaw::Yes) + | token::NtLifetime(Ident { name, .. }, IdentIsRaw::Yes) => { + format!("'r#{}", &name.as_str()[1..]).into() + } /* Other */ token::DocComment(comment_kind, attr_style, data) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index b13c89c435da7..893bfaf8f712e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -7,13 +7,13 @@ use rustc_ast::util::classify; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::{ - self as ast, token, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, - FormatCount, FormatDebugHex, FormatSign, FormatTrait, + self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, + FormatDebugHex, FormatSign, FormatTrait, token, }; use crate::pp::Breaks::Inconsistent; use crate::pprust::state::fixup::FixupContext; -use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; +use crate::pprust::state::{AnnNode, INDENT_UNIT, PrintState, State}; impl<'a> State<'a> { fn print_else(&mut self, els: Option<&ast::Expr>) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs index c9baca72485ef..50fd12a4e8b68 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs @@ -1,5 +1,5 @@ -use rustc_ast::util::{classify, parser}; use rustc_ast::Expr; +use rustc_ast::util::{classify, parser}; #[derive(Copy, Clone, Debug)] pub(crate) struct FixupContext { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 85a0b3b202292..8217b6df5b470 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,13 +1,13 @@ use ast::StaticItem; use itertools::{Itertools, Position}; use rustc_ast as ast; -use rustc_ast::ptr::P; use rustc_ast::ModKind; +use rustc_ast::ptr::P; use rustc_span::symbol::Ident; use crate::pp::Breaks::Inconsistent; use crate::pprust::state::fixup::FixupContext; -use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; +use crate::pprust::state::{AnnNode, INDENT_UNIT, PrintState, State}; enum DelegationKind<'a> { Single, diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs index 3fefc523f8883..01e5dff34b7a6 100644 --- a/compiler/rustc_ast_pretty/src/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_span::symbol::Ident; -use rustc_span::{create_default_session_globals_then, DUMMY_SP}; +use rustc_span::{DUMMY_SP, create_default_session_globals_then}; use thin_vec::ThinVec; use super::*; diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index e46dabc7a6e22..762ebc47ca9d0 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -4,21 +4,21 @@ use std::num::NonZero; use rustc_abi::Align; use rustc_ast::{ - self as ast, attr, Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, - NodeId, + self as ast, Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId, + attr, }; use rustc_ast_pretty::pprust; use rustc_errors::ErrorGuaranteed; -use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; +use rustc_feature::{Features, GatedCfg, find_gated_cfg, is_builtin_attr_name}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_session::config::ExpectedValues; -use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::lint::BuiltinLintDiag; +use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::feature_err; use rustc_session::{RustcVersion, Session}; -use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::hygiene::Transparency; +use rustc_span::symbol::{Symbol, sym}; use crate::fluent_generated; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -153,7 +153,7 @@ pub enum StabilityLevel { } /// Rust release in which a feature is stabilized. -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] +#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] #[derive(HashStable_Generic)] pub enum StableSince { Version(RustcVersion), @@ -1240,5 +1240,5 @@ pub fn parse_confusables(attr: &Attribute) -> Option> { candidates.push(meta_lit.symbol); } - return Some(candidates); + Some(candidates) } diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index 0dad637238982..bb207c5c9526c 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -15,11 +15,11 @@ mod builtin; mod session_diagnostics; -pub use builtin::*; -pub use rustc_ast::attr::*; -pub(crate) use rustc_session::HashStableContext; pub use IntType::*; pub use ReprAttr::*; pub use StabilityLevel::*; +pub use builtin::*; +pub use rustc_ast::attr::*; +pub(crate) use rustc_session::HashStableContext; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 234a0ef28a269..959a5a4bba752 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -6,7 +6,7 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuar use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; -use crate::{fluent_generated as fluent, UnsupportedLiteralReason}; +use crate::{UnsupportedLiteralReason, fluent_generated as fluent}; #[derive(Diagnostic)] #[diag(attr_expected_one_cfg_pattern, code = E0536)] @@ -203,20 +203,16 @@ pub(crate) struct UnsupportedLiteral { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new( - dcx, - level, - match self.reason { - UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic, - UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string, - UnsupportedLiteralReason::DeprecatedString => { - fluent::attr_unsupported_literal_deprecated_string - } - UnsupportedLiteralReason::DeprecatedKvPair => { - fluent::attr_unsupported_literal_deprecated_kv_pair - } - }, - ); + let mut diag = Diag::new(dcx, level, match self.reason { + UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic, + UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string, + UnsupportedLiteralReason::DeprecatedString => { + fluent::attr_unsupported_literal_deprecated_string + } + UnsupportedLiteralReason::DeprecatedKvPair => { + fluent::attr_unsupported_literal_deprecated_kv_pair + } + }); diag.span(self.span); diag.code(E0565); if self.is_bytestr { diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index edb25e12864bc..ee4b2f95cb151 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -207,7 +207,7 @@ borrowck_simd_intrinsic_arg_const = *[other] {$arg}th } argument of `{$intrinsic}` is required to be a `const` item -borrowck_suggest_create_freash_reborrow = +borrowck_suggest_create_fresh_reborrow = consider reborrowing the `Pin` instead of moving it borrowck_suggest_iterate_over_slice = diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index fbda44550a19c..a8ade54732f85 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -4,15 +4,15 @@ use std::ops::Index; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, traversal, Body, Local, Location}; +use rustc_middle::mir::{self, Body, Local, Location, traversal}; use rustc_middle::span_bug; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::move_paths::MoveData; use tracing::debug; +use crate::BorrowIndex; use crate::path_utils::allow_two_phase_borrow; use crate::place_ext::PlaceExt; -use crate::BorrowIndex; pub struct BorrowSet<'tcx> { /// The fundamental map relating bitvector indexes to the borrows diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 2c672dbf8c4ae..30e94b0bec708 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -2,13 +2,13 @@ #![allow(rustc::untranslatable_diagnostic)] use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, Applicability, Diag, DiagCtxtHandle}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, struct_span_code_err}; use rustc_hir as hir; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; -impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { +impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn dcx(&self) -> DiagCtxtHandle<'infcx> { self.infcx.dcx() } diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 0ae837898b9c0..9d500586f084c 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -97,11 +97,11 @@ impl ConstraintGraph { /// Given the constraint set from which this graph was built /// creates a region graph so that you can iterate over *regions* /// and not constraints. - pub(crate) fn region_graph<'rg, 'tcx>( - &'rg self, - set: &'rg OutlivesConstraintSet<'tcx>, + pub(crate) fn region_graph<'a, 'tcx>( + &'a self, + set: &'a OutlivesConstraintSet<'tcx>, static_region: RegionVid, - ) -> RegionGraph<'rg, 'tcx, D> { + ) -> RegionGraph<'a, 'tcx, D> { RegionGraph::new(set, self, static_region) } @@ -130,15 +130,15 @@ impl ConstraintGraph { } } -pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirection> { - graph: &'s ConstraintGraph, - constraints: &'s OutlivesConstraintSet<'tcx>, +pub(crate) struct Edges<'a, 'tcx, D: ConstraintGraphDirection> { + graph: &'a ConstraintGraph, + constraints: &'a OutlivesConstraintSet<'tcx>, pointer: Option, next_static_idx: Option, static_region: RegionVid, } -impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'a, 'tcx, D> { type Item = OutlivesConstraint<'tcx>; fn next(&mut self) -> Option { @@ -171,20 +171,20 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> { /// This struct brings together a constraint set and a (normal, not /// reverse) constraint graph. It implements the graph traits and is /// usd for doing the SCC computation. -pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirection> { - set: &'s OutlivesConstraintSet<'tcx>, - constraint_graph: &'s ConstraintGraph, +pub(crate) struct RegionGraph<'a, 'tcx, D: ConstraintGraphDirection> { + set: &'a OutlivesConstraintSet<'tcx>, + constraint_graph: &'a ConstraintGraph, static_region: RegionVid, } -impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> RegionGraph<'a, 'tcx, D> { /// Creates a "dependency graph" where each region constraint `R1: /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error /// reporting. pub(crate) fn new( - set: &'s OutlivesConstraintSet<'tcx>, - constraint_graph: &'s ConstraintGraph, + set: &'a OutlivesConstraintSet<'tcx>, + constraint_graph: &'a ConstraintGraph, static_region: RegionVid, ) -> Self { Self { set, constraint_graph, static_region } @@ -192,18 +192,18 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> { /// Given a region `R`, iterate over all regions `R1` such that /// there exists a constraint `R: R1`. - pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> { + pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'a, 'tcx, D> { Successors { edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), } } } -pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirection> { - edges: Edges<'s, 'tcx, D>, +pub(crate) struct Successors<'a, 'tcx, D: ConstraintGraphDirection> { + edges: Edges<'a, 'tcx, D>, } -impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'a, 'tcx, D> { type Item = RegionVid; fn next(&mut self) -> Option { @@ -211,7 +211,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> } } -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'a, 'tcx, D> { type Node = RegionVid; fn num_nodes(&self) -> usize { @@ -219,7 +219,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph } } -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'a, 'tcx, D> { fn successors(&self, node: Self::Node) -> impl Iterator { self.outgoing_regions(node) } diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 8f560635cb339..c994c4dc1e484 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -8,12 +8,12 @@ use rustc_middle::mir::{Body, Promoted}; use rustc_middle::ty::TyCtxt; pub use super::constraints::OutlivesConstraint; -pub use super::dataflow::{calculate_borrows_out_of_scope_at_location, BorrowIndex, Borrows}; +pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_at_location}; pub use super::facts::{AllFacts as PoloniusInput, RustcFacts}; pub use super::location::{LocationTable, RichLocation}; pub use super::nll::PoloniusOutput; pub use super::place_ext::PlaceExt; -pub use super::places_conflict::{places_conflict, PlaceConflictBias}; +pub use super::places_conflict::{PlaceConflictBias, places_conflict}; pub use super::region_infer::RegionInferenceContext; use crate::borrow_set::BorrowSet; diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 9bb6109e66d95..4af5a10f5812d 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -9,40 +9,39 @@ use rustc_middle::mir::{ use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; -use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, Results, ResultsVisitable}; +use rustc_mir_dataflow::{Analysis, AnalysisDomain, Forward, GenKill, Results, ResultsVisitable}; use tracing::debug; -use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext}; +use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict}; /// The results of the dataflow analyses used by the borrow checker. -pub(crate) struct BorrowckResults<'a, 'mir, 'tcx> { - pub(crate) borrows: Results<'tcx, Borrows<'a, 'mir, 'tcx>>, - pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'mir, 'tcx>>, - pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'mir, 'tcx>>, +pub(crate) struct BorrowckResults<'a, 'tcx> { + pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>, + pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>, + pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>, } /// The transient state of the dataflow analyses used by the borrow checker. #[derive(Debug)] -pub(crate) struct BorrowckFlowState<'a, 'mir, 'tcx> { - pub(crate) borrows: as AnalysisDomain<'tcx>>::Domain, - pub(crate) uninits: as AnalysisDomain<'tcx>>::Domain, - pub(crate) ever_inits: as AnalysisDomain<'tcx>>::Domain, +pub(crate) struct BorrowckDomain<'a, 'tcx> { + pub(crate) borrows: as AnalysisDomain<'tcx>>::Domain, + pub(crate) uninits: as AnalysisDomain<'tcx>>::Domain, + pub(crate) ever_inits: as AnalysisDomain<'tcx>>::Domain, } -impl<'a, 'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'mir, 'tcx> { - // All three analyses are forward, but we have to use just one here. - type Direction = as AnalysisDomain<'tcx>>::Direction; - type FlowState = BorrowckFlowState<'a, 'mir, 'tcx>; +impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { + type Direction = Forward; + type Domain = BorrowckDomain<'a, 'tcx>; - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { - BorrowckFlowState { + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + BorrowckDomain { borrows: self.borrows.analysis.bottom_value(body), uninits: self.uninits.analysis.bottom_value(body), ever_inits: self.ever_inits.analysis.bottom_value(body), } } - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { state.borrows.clone_from(self.borrows.entry_set_for_block(block)); state.uninits.clone_from(self.uninits.entry_set_for_block(block)); state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block)); @@ -50,7 +49,7 @@ impl<'a, 'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'mir, 'tcx> fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -61,7 +60,7 @@ impl<'a, 'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'mir, 'tcx> fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -72,7 +71,7 @@ impl<'a, 'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'mir, 'tcx> fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { @@ -83,7 +82,7 @@ impl<'a, 'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'mir, 'tcx> fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { @@ -106,24 +105,23 @@ rustc_index::newtype_index! { /// `BorrowIndex`, and maps each such index to a `BorrowData` /// describing the borrow. These indexes are used for representing the /// borrows in compact bitvectors. -pub struct Borrows<'a, 'mir, 'tcx> { +pub struct Borrows<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, - + body: &'a Body<'tcx>, borrow_set: &'a BorrowSet<'tcx>, borrows_out_of_scope_at_location: FxIndexMap>, } -struct OutOfScopePrecomputer<'mir, 'tcx> { +struct OutOfScopePrecomputer<'a, 'tcx> { visited: BitSet, visit_stack: Vec, - body: &'mir Body<'tcx>, - regioncx: &'mir RegionInferenceContext<'tcx>, + body: &'a Body<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, borrows_out_of_scope_at_location: FxIndexMap>, } -impl<'mir, 'tcx> OutOfScopePrecomputer<'mir, 'tcx> { - fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self { +impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> { + fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self { OutOfScopePrecomputer { visited: BitSet::new_empty(body.basic_blocks.len()), visit_stack: vec![], @@ -226,17 +224,17 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>( prec.borrows_out_of_scope_at_location } -struct PoloniusOutOfScopePrecomputer<'mir, 'tcx> { +struct PoloniusOutOfScopePrecomputer<'a, 'tcx> { visited: BitSet, visit_stack: Vec, - body: &'mir Body<'tcx>, - regioncx: &'mir RegionInferenceContext<'tcx>, + body: &'a Body<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, loans_out_of_scope_at_location: FxIndexMap>, } -impl<'mir, 'tcx> PoloniusOutOfScopePrecomputer<'mir, 'tcx> { - fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self { +impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> { + fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self { Self { visited: BitSet::new_empty(body.basic_blocks.len()), visit_stack: vec![], @@ -389,10 +387,10 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> { } } -impl<'a, 'mir, 'tcx> Borrows<'a, 'mir, 'tcx> { +impl<'a, 'tcx> Borrows<'a, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, + body: &'a Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, borrow_set: &'a BorrowSet<'tcx>, ) -> Self { @@ -494,7 +492,7 @@ impl<'a, 'mir, 'tcx> Borrows<'a, 'mir, 'tcx> { } } -impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, '_, 'tcx> { +impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { type Domain = BitSet; const NAME: &'static str = "borrows"; @@ -517,7 +515,7 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, '_, 'tcx> { /// region stops containing the CFG points reachable from the issuing location. /// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of /// `a.b.c` when `a` is overwritten. -impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, '_, 'tcx> { +impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { type Idx = BorrowIndex; fn domain_size(&self, _: &mir::Body<'tcx>) -> usize { @@ -617,8 +615,8 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, '_, 'tcx> { } } -impl DebugWithContext> for BorrowIndex { - fn fmt_with(&self, ctxt: &Borrows<'_, '_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl DebugWithContext> for BorrowIndex { + fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", ctxt.location(*self)) } } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 8a4e89d47bdc0..40a6d506ffa63 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -14,18 +14,18 @@ use rustc_middle::ty::{ self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, }; use rustc_span::Span; -use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; -use rustc_trait_selection::traits::query::type_op; +use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError; use rustc_trait_selection::traits::ObligationCtxt; +use rustc_trait_selection::traits::query::type_op; use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use tracing::{debug, instrument}; +use crate::MirBorrowckCtxt; use crate::region_infer::values::RegionElement; use crate::session_diagnostics::{ HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError, }; -use crate::MirBorrowckCtxt; #[derive(Clone)] pub(crate) struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>); @@ -52,7 +52,7 @@ impl<'tcx> UniverseInfo<'tcx> { pub(crate) fn report_error( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion, error_element: RegionElement, cause: ObligationCause<'tcx>, @@ -151,7 +151,7 @@ trait TypeOpInfo<'tcx> { fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, @@ -160,7 +160,7 @@ trait TypeOpInfo<'tcx> { #[instrument(level = "debug", skip(self, mbcx))] fn report_error( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion, error_element: RegionElement, cause: ObligationCause<'tcx>, @@ -176,25 +176,24 @@ trait TypeOpInfo<'tcx> { return; }; - let placeholder_region = ty::Region::new_placeholder( - tcx, - ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound }, - ); - - let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) = - error_element - { - let adjusted_universe = - error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); - adjusted_universe.map(|adjusted| { - ty::Region::new_placeholder( - tcx, - ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound }, - ) - }) - } else { - None - }; + let placeholder_region = ty::Region::new_placeholder(tcx, ty::Placeholder { + universe: adjusted_universe.into(), + bound: placeholder.bound, + }); + + let error_region = + if let RegionElement::PlaceholderRegion(error_placeholder) = error_element { + let adjusted_universe = + error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); + adjusted_universe.map(|adjusted| { + ty::Region::new_placeholder(tcx, ty::Placeholder { + universe: adjusted.into(), + bound: error_placeholder.bound, + }) + }) + } else { + None + }; debug!(?placeholder_region); @@ -233,7 +232,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, @@ -277,7 +276,7 @@ where fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, @@ -324,7 +323,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, @@ -357,7 +356,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>, _cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 9951f9fcda69c..60ea0d1edbf4e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -11,10 +11,10 @@ use hir::{ClosureKind, Path}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_block, walk_expr, Map, Visitor}; +use rustc_hir::intravisit::{Map, Visitor, walk_block, walk_expr}; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField}; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; @@ -27,17 +27,17 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ - self, suggest_constraining_type_params, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitor, Upcast, + self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast, + suggest_constraining_type_params, }; use rustc_middle::util::CallKind; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::hygiene::DesugaringKind; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{BytePos, Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use tracing::{debug, instrument}; @@ -46,9 +46,9 @@ use super::explain_borrow::{BorrowExplanation, LaterUseKind}; use super::{DescribePlaceOpt, RegionName, RegionNameSource, UseSpans}; use crate::borrow_set::{BorrowData, TwoPhaseActivation}; use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead; -use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt, Instance}; +use crate::diagnostics::{CapturedMessageOpt, Instance, find_all_local_uses}; use crate::prefixes::IsPrefixOf; -use crate::{borrowck_errors, InitializationRequiringAction, MirBorrowckCtxt, WriteKind}; +use crate::{InitializationRequiringAction, MirBorrowckCtxt, WriteKind, borrowck_errors}; #[derive(Debug)] struct MoveSite { @@ -69,7 +69,7 @@ enum StorageDeadOrDrop<'tcx> { Destructor(Ty<'tcx>), } -impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn report_use_of_moved_or_uninitialized( &mut self, location: Location, @@ -145,10 +145,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { span, desired_action.as_noun(), partially_str, - self.describe_place_with_options( - moved_place, - DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, - ), + self.describe_place_with_options(moved_place, DescribePlaceOpt { + including_downcast: true, + including_tuple_field: true, + }), ); let reinit_spans = maybe_reinitialized_locations @@ -266,10 +266,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } } - let opt_name = self.describe_place_with_options( - place.as_ref(), - DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, - ); + let opt_name = self.describe_place_with_options(place.as_ref(), DescribePlaceOpt { + including_downcast: true, + including_tuple_field: true, + }); let note_msg = match opt_name { Some(name) => format!("`{name}`"), None => "value".to_owned(), @@ -689,17 +689,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } let spans: Vec<_> = spans_set.into_iter().collect(); - let (name, desc) = match self.describe_place_with_options( - moved_place, - DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, - ) { + let (name, desc) = match self.describe_place_with_options(moved_place, DescribePlaceOpt { + including_downcast: true, + including_tuple_field: true, + }) { Some(name) => (format!("`{name}`"), format!("`{name}` ")), None => ("the variable".to_string(), String::new()), }; - let path = match self.describe_place_with_options( - used_place, - DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, - ) { + let path = match self.describe_place_with_options(used_place, DescribePlaceOpt { + including_downcast: true, + including_tuple_field: true, + }) { Some(name) => format!("`{name}`"), None => "value".to_string(), }; @@ -1179,7 +1179,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { for field in &variant.fields { // In practice unless there are more than one field with the same type, we'll be // suggesting a single field at a type, because we don't aggregate multiple borrow - // checker errors involving the functional record update sytnax into a single one. + // checker errors involving the functional record update syntax into a single one. let field_ty = field.ty(self.infcx.tcx, args); let ident = field.ident(self.infcx.tcx); if field_ty == ty && fields.iter().all(|field| field.ident.name != ident.name) { @@ -1999,19 +1999,32 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { ) { let used_in_call = matches!( explanation, - BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _) + BorrowExplanation::UsedLater( + _, + LaterUseKind::Call | LaterUseKind::Other, + _call_span, + _ + ) ); if !used_in_call { debug!("not later used in call"); return; } + if matches!( + self.body.local_decls[issued_borrow.borrowed_place.local].local_info(), + LocalInfo::IfThenRescopeTemp { .. } + ) { + // A better suggestion will be issued by the `if_let_rescope` lint + return; + } - let use_span = - if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation { - Some(use_span) - } else { - None - }; + let use_span = if let BorrowExplanation::UsedLater(_, LaterUseKind::Other, use_span, _) = + explanation + { + Some(use_span) + } else { + None + }; let outer_call_loc = if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { @@ -2574,33 +2587,31 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { - if e.span.contains(self.capture_span) { - if let hir::ExprKind::Closure(&hir::Closure { + if e.span.contains(self.capture_span) + && let hir::ExprKind::Closure(&hir::Closure { kind: hir::ClosureKind::Closure, body, fn_arg_span, fn_decl: hir::FnDecl { inputs, .. }, .. }) = e.kind - && let hir::Node::Expr(body) = self.tcx.hir_node(body.hir_id) - { - self.suggest_arg = "this: &Self".to_string(); - if inputs.len() > 0 { - self.suggest_arg.push_str(", "); - } - self.in_closure = true; - self.closure_arg_span = fn_arg_span; - self.visit_expr(body); - self.in_closure = false; + && let hir::Node::Expr(body) = self.tcx.hir_node(body.hir_id) + { + self.suggest_arg = "this: &Self".to_string(); + if inputs.len() > 0 { + self.suggest_arg.push_str(", "); } + self.in_closure = true; + self.closure_arg_span = fn_arg_span; + self.visit_expr(body); + self.in_closure = false; } - if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e { - if let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path - && seg.ident.name == kw::SelfLower - && self.in_closure - { - self.closure_change_spans.push(e.span); - } + if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e + && let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path + && seg.ident.name == kw::SelfLower + && self.in_closure + { + self.closure_change_spans.push(e.span); } hir::intravisit::walk_expr(self, e); } @@ -2609,8 +2620,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat && let Some(init) = local.init - { - if let hir::Expr { + && let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { kind: hir::ClosureKind::Closure, @@ -2618,11 +2628,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { }), .. } = init - && init.span.contains(self.capture_span) - { - self.closure_local_id = Some(*hir_id); - } + && init.span.contains(self.capture_span) + { + self.closure_local_id = Some(*hir_id); } + hir::intravisit::walk_local(self, local); } @@ -2862,7 +2872,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { // and `move` will not help here. ( Some(name), - BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _), + BorrowExplanation::UsedLater(_, LaterUseKind::ClosureCapture, var_or_use_span, _), ) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self .report_escaping_closure_capture( borrow_spans, @@ -3543,7 +3553,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { location: Location, mpi: MovePathIndex, ) -> (Vec, Vec) { - fn predecessor_locations<'tcx, 'a>( + fn predecessor_locations<'a, 'tcx>( body: &'a mir::Body<'tcx>, location: Location, ) -> impl Iterator + Captures<'tcx> + 'a { @@ -3669,7 +3679,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { reinits.push(location); return true; } - return false; + false }; while let Some(location) = stack.pop() { @@ -4358,11 +4368,7 @@ enum AnnotatedBorrowFnSignature<'tcx> { impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { /// Annotate the provided diagnostic with information about borrow from the fn signature that /// helps explain. - pub(crate) fn emit( - &self, - cx: &MirBorrowckCtxt<'_, '_, '_, 'tcx>, - diag: &mut Diag<'_>, - ) -> String { + pub(crate) fn emit(&self, cx: &MirBorrowckCtxt<'_, '_, 'tcx>, diag: &mut Diag<'_>) -> String { match self { &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => { diag.span_label( diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 91b02a36d0046..31a5d451ff6b6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -17,12 +17,12 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{sym, DesugaringKind, Span}; +use rustc_span::symbol::{Symbol, kw}; +use rustc_span::{DesugaringKind, Span, sym}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use tracing::{debug, instrument}; -use super::{find_use, RegionName, UseSpans}; +use super::{RegionName, UseSpans, find_use}; use crate::borrow_set::BorrowData; use crate::nll::ConstraintDescription; use crate::region_infer::{BlameConstraint, Cause, ExtraConstraintInfo}; @@ -30,7 +30,7 @@ use crate::{MirBorrowckCtxt, WriteKind}; #[derive(Debug)] pub(crate) enum BorrowExplanation<'tcx> { - UsedLater(LaterUseKind, Span, Option), + UsedLater(Local, LaterUseKind, Span, Option), UsedLaterInLoop(LaterUseKind, Span, Option), UsedLaterWhenDropped { drop_loc: Location, @@ -99,7 +99,12 @@ impl<'tcx> BorrowExplanation<'tcx> { } } match *self { - BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { + BorrowExplanation::UsedLater( + dropped_local, + later_use_kind, + var_or_use_span, + path_span, + ) => { let message = match later_use_kind { LaterUseKind::TraitCapture => "captured here by trait object", LaterUseKind::ClosureCapture => "captured here by closure", @@ -107,9 +112,26 @@ impl<'tcx> BorrowExplanation<'tcx> { LaterUseKind::FakeLetRead => "stored here", LaterUseKind::Other => "used here", }; - // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same - if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { + let local_decl = &body.local_decls[dropped_local]; + + if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info() + && let Some((_, hir::Node::Expr(expr))) = tcx.hir().parent_iter(if_then).next() + && let hir::ExprKind::If(cond, conseq, alt) = expr.kind + && let hir::ExprKind::Let(&hir::LetExpr { + span: _, + pat, + init, + // FIXME(#101728): enable rewrite when type ascription is stabilized again + ty: None, + recovered: _, + }) = cond.kind + && pat.span.can_be_used_for_suggestions() + && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) + { + suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err); + } else if path_span.map_or(true, |path_span| path_span == var_or_use_span) { + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) { err.span_label( var_or_use_span, format!("{borrow_desc}borrow later {message}"), @@ -255,6 +277,22 @@ impl<'tcx> BorrowExplanation<'tcx> { Applicability::MaybeIncorrect, ); }; + } else if let &LocalInfo::IfThenRescopeTemp { if_then } = + local_decl.local_info() + && let hir::Node::Expr(expr) = tcx.hir_node(if_then) + && let hir::ExprKind::If(cond, conseq, alt) = expr.kind + && let hir::ExprKind::Let(&hir::LetExpr { + span: _, + pat, + init, + // FIXME(#101728): enable rewrite when type ascription is stabilized again + ty: None, + recovered: _, + }) = cond.kind + && pat.span.can_be_used_for_suggestions() + && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) + { + suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err); } } } @@ -295,7 +333,11 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - if let ConstraintCategory::Cast { unsize_to: Some(unsize_ty) } = category { + if let ConstraintCategory::Cast { + is_implicit_coercion: true, + unsize_to: Some(unsize_ty), + } = category + { self.add_object_lifetime_default_note(tcx, err, unsize_ty); } self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); @@ -390,7 +432,54 @@ impl<'tcx> BorrowExplanation<'tcx> { } } -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +fn suggest_rewrite_if_let( + tcx: TyCtxt<'_>, + expr: &hir::Expr<'_>, + pat: &str, + init: &hir::Expr<'_>, + conseq: &hir::Expr<'_>, + alt: Option<&hir::Expr<'_>>, + err: &mut Diag<'_>, +) { + let source_map = tcx.sess.source_map(); + err.span_note( + source_map.end_point(conseq.span), + "lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead", + ); + if expr.span.can_be_used_for_suggestions() && conseq.span.can_be_used_for_suggestions() { + let needs_block = if let Some(hir::Node::Expr(expr)) = + alt.and_then(|alt| tcx.hir().parent_iter(alt.hir_id).next()).map(|(_, node)| node) + { + matches!(expr.kind, hir::ExprKind::If(..)) + } else { + false + }; + let mut sugg = vec![ + ( + expr.span.shrink_to_lo().between(init.span), + if needs_block { "{ match ".into() } else { "match ".into() }, + ), + (conseq.span.shrink_to_lo(), format!(" {{ {pat} => ")), + ]; + let expr_end = expr.span.shrink_to_hi(); + let mut expr_end_code; + if let Some(alt) = alt { + sugg.push((conseq.span.between(alt.span), " _ => ".into())); + expr_end_code = "}".to_string(); + } else { + expr_end_code = " _ => {} }".into(); + } + expr_end_code.push('}'); + sugg.push((expr_end, expr_end_code)); + err.multipart_suggestion( + "consider rewriting the `if` into `match` which preserves the extended lifetime", + sugg, + Applicability::MaybeIncorrect, + ); + } +} + +impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { fn free_region_constraint_info( &self, borrow_region: RegionVid, @@ -465,14 +554,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { .or_else(|| self.borrow_spans(span, location)); if use_in_later_iteration_of_loop { - let later_use = self.later_use_kind(borrow, spans, use_location); - BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2) + let (later_use_kind, var_or_use_span, path_span) = + self.later_use_kind(borrow, spans, use_location); + BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) } else { // Check if the location represents a `FakeRead`, and adapt the error // message to the `FakeReadCause` it is from: in particular, // the ones inserted in optimized `let var = ` patterns. - let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2) + let (later_use_kind, var_or_use_span, path_span) = + self.later_use_kind(borrow, spans, location); + BorrowExplanation::UsedLater( + borrow.borrowed_place.local, + later_use_kind, + var_or_use_span, + path_span, + ) } } @@ -648,7 +744,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { // If we see an unsized cast, then if it is our data we should check // whether it is being cast to a trait object. Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize), + CastKind::PointerCoercion(PointerCoercion::Unsize, _), operand, ty, ) => { @@ -662,9 +758,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { // `&dyn Trait` ty::Ref(_, ty, _) if ty.is_trait() => true, // `Box` - _ if ty.is_box() && ty.boxed_ty().is_trait() => { + _ if ty.boxed_ty().is_some_and(Ty::is_trait) => { true } + // `dyn Trait` _ if ty.is_trait() => true, // Anything else. diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index bea8d3bfdfbb1..d8fa5506a9919 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -21,15 +21,15 @@ pub(crate) fn find<'tcx>( uf.find() } -struct UseFinder<'cx, 'tcx> { - body: &'cx Body<'tcx>, - regioncx: &'cx Rc>, +struct UseFinder<'a, 'tcx> { + body: &'a Body<'tcx>, + regioncx: &'a Rc>, tcx: TyCtxt<'tcx>, region_vid: RegionVid, start_point: Location, } -impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { +impl<'a, 'tcx> UseFinder<'a, 'tcx> { fn find(&mut self) -> Option { let mut queue = VecDeque::new(); let mut visited = FxIndexSet::default(); @@ -93,8 +93,8 @@ impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { } } -struct DefUseVisitor<'cx, 'tcx> { - body: &'cx Body<'tcx>, +struct DefUseVisitor<'a, 'tcx> { + body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, region_vid: RegionVid, def_use_result: Option, @@ -106,7 +106,7 @@ enum DefUseResult { UseDrop { local: Local }, } -impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for DefUseVisitor<'a, 'tcx> { fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { let local_ty = self.body.local_decls[local].ty; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 5ab66963409a8..801c7af2de701 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -15,22 +15,22 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_middle::util::{call_kind, CallDesugaringKind}; +use rustc_middle::util::{CallDesugaringKind, call_kind}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ - type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode, + FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions, }; use tracing::debug; -use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; +use super::borrow_set::BorrowData; use crate::fluent_generated as fluent; use crate::session_diagnostics::{ CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause, @@ -68,7 +68,7 @@ pub(super) struct DescribePlaceOpt { pub(super) struct IncludingTupleField(pub(super) bool); -impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure /// is moved after being invoked. /// @@ -177,10 +177,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { /// End-user visible description of `place` if one can be found. /// If the place is a temporary for instance, `None` will be returned. pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option { - self.describe_place_with_options( - place_ref, - DescribePlaceOpt { including_downcast: false, including_tuple_field: true }, - ) + self.describe_place_with_options(place_ref, DescribePlaceOpt { + including_downcast: false, + including_tuple_field: true, + }) } /// End-user visible description of `place` if one can be found. If the place is a temporary @@ -345,9 +345,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { variant_index: Option, including_tuple_field: IncludingTupleField, ) -> Option { - if ty.is_box() { + if let Some(boxed_ty) = ty.boxed_ty() { // If the type is a box, the field is described from the boxed type - self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field) + self.describe_field_from_ty(boxed_ty, field, variant_index, including_tuple_field) } else { match *ty.kind() { ty::Adt(def, _) => { @@ -772,7 +772,7 @@ struct CapturedMessageOpt { maybe_reinitialized_locations_is_empty: bool, } -impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Finds the spans associated to a move or copy of move_place at location. pub(super) fn move_spans( &self, diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 3dab027bff057..98417e8c7a3f4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -12,9 +12,9 @@ use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use tracing::debug; +use crate::MirBorrowckCtxt; use crate::diagnostics::{CapturedMessageOpt, DescribePlaceOpt, UseSpans}; use crate::prefixes::PrefixSet; -use crate::MirBorrowckCtxt; #[derive(Debug)] pub(crate) enum IllegalMoveOriginKind<'tcx> { @@ -93,7 +93,7 @@ enum GroupedMoveError<'tcx> { }, } -impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn report_move_errors(&mut self) { let grouped_errors = self.group_move_errors(); for error in grouped_errors { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 337125f5ecc11..20ecc665b1eed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -14,8 +14,8 @@ use rustc_middle::mir::{ PlaceRef, ProjectionElem, }; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast}; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{sym, BytePos, DesugaringKind, Span}; +use rustc_span::symbol::{Symbol, kw}; +use rustc_span::{BytePos, DesugaringKind, Span, sym}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; @@ -24,7 +24,7 @@ use tracing::debug; use crate::diagnostics::BorrowedContentSource; use crate::util::FindAssignments; -use crate::{session_diagnostics, MirBorrowckCtxt}; +use crate::{MirBorrowckCtxt, session_diagnostics}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { @@ -32,7 +32,7 @@ pub(crate) enum AccessKind { Mutate, } -impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn report_mutability_error( &mut self, access_place: Place<'tcx>, @@ -558,7 +558,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { ty: Ty<'tcx>, suggested: bool, } - impl<'a, 'cx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'cx, 'tcx> { + impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { hir::intravisit::walk_stmt(self, stmt); let expr = match stmt.kind { diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index b205dc9ff4922..bd0cf3578c2bb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -76,7 +76,7 @@ impl OutlivesSuggestionBuilder { /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`. fn region_vid_to_name( &self, - mbcx: &MirBorrowckCtxt<'_, '_, '_, '_>, + mbcx: &MirBorrowckCtxt<'_, '_, '_>, region: RegionVid, ) -> Option { mbcx.give_region_a_name(region).filter(Self::region_name_is_suggestable) @@ -85,7 +85,7 @@ impl OutlivesSuggestionBuilder { /// Compiles a list of all suggestions to be printed in the final big suggestion. fn compile_all_suggestions( &self, - mbcx: &MirBorrowckCtxt<'_, '_, '_, '_>, + mbcx: &MirBorrowckCtxt<'_, '_, '_>, ) -> SmallVec<[SuggestedConstraint; 2]> { let mut suggested = SmallVec::new(); @@ -161,7 +161,7 @@ impl OutlivesSuggestionBuilder { /// Emit an intermediate note on the given `Diag` if the involved regions are suggestable. pub(crate) fn intermediate_suggestion( &mut self, - mbcx: &MirBorrowckCtxt<'_, '_, '_, '_>, + mbcx: &MirBorrowckCtxt<'_, '_, '_>, errci: &ErrorConstraintInfo<'_>, diag: &mut Diag<'_>, ) { @@ -180,7 +180,7 @@ impl OutlivesSuggestionBuilder { /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final /// suggestion including all collected constraints. - pub(crate) fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_, '_, '_>) { + pub(crate) fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_, '_>) { // No constraints to add? Done. if self.constraints_to_add.is_empty() { debug!("No constraints to suggest."); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index d49d36dedafc1..39175b406a4aa 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -3,26 +3,26 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; -use rustc_hir::def::Res::Def; -use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::Visitor; use rustc_hir::GenericBound::Trait; use rustc_hir::QPath::Resolved; use rustc_hir::WherePredicate::BoundPredicate; +use rustc_hir::def::Res::Def; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor}; -use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, kw}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::nice_region_error::{ - self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, - HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, + self, HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, find_anon_type, + find_param_with_region, suggest_adding_lifetime_params, }; use rustc_trait_selection::error_reporting::infer::region::unexpected_hidden_region_diagnostic; -use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{Obligation, ObligationCtxt}; use tracing::{debug, instrument, trace}; @@ -36,7 +36,7 @@ use crate::session_diagnostics::{ LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote, }; use crate::universal_regions::DefiningTy; -use crate::{borrowck_errors, fluent_generated as fluent, MirBorrowckCtxt}; +use crate::{MirBorrowckCtxt, borrowck_errors, fluent_generated as fluent}; impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { fn description(&self) -> &'static str { @@ -47,7 +47,8 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { ConstraintCategory::Yield => "yielding this value ", ConstraintCategory::UseAsConst => "using this value as a constant ", ConstraintCategory::UseAsStatic => "using this value as a static ", - ConstraintCategory::Cast { .. } => "cast ", + ConstraintCategory::Cast { is_implicit_coercion: false, .. } => "cast ", + ConstraintCategory::Cast { is_implicit_coercion: true, .. } => "coercion ", ConstraintCategory::CallArgument(_) => "argument ", ConstraintCategory::TypeAnnotation => "type annotation ", ConstraintCategory::ClosureBounds => "closure body ", @@ -156,7 +157,7 @@ pub(crate) struct ErrorConstraintInfo<'tcx> { pub(super) span: Span, } -impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Converts a region inference variable into a `ty::Region` that /// we can use for error reporting. If `r` is universally bound, /// then we use the name that we have on record for it. If `r` is @@ -1108,15 +1109,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { let closure_ty = Ty::new_closure( tcx, closure_def_id.to_def_id(), - ty::ClosureArgs::new( - tcx, - ty::ClosureArgsParts { - parent_args: args.parent_args(), - closure_kind_ty: args.kind_ty(), - tupled_upvars_ty: args.tupled_upvars_ty(), - closure_sig_as_fn_ptr_ty, - }, - ) + ty::ClosureArgs::new(tcx, ty::ClosureArgsParts { + parent_args: args.parent_args(), + closure_kind_ty: args.kind_ty(), + tupled_upvars_ty: args.tupled_upvars_ty(), + closure_sig_as_fn_ptr_ty, + }) .args, ); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index cb05812ec7b5c..2f22e1532c196 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -11,13 +11,13 @@ use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, RegionVid, Ty}; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use tracing::{debug, instrument}; -use crate::universal_regions::DefiningTy; use crate::MirBorrowckCtxt; +use crate::universal_regions::DefiningTy; /// A name for a particular region used in emitting diagnostics. This name could be a generated /// name like `'1`, a name used by the user like `'a`, or a name like `'static`. @@ -200,7 +200,7 @@ impl rustc_errors::IntoDiagArg for RegionName { } } -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId { self.body.source.def_id().expect_local() } diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 2a4fa1e00191c..bda7024126732 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -1,8 +1,8 @@ use rustc_index::IndexSlice; use rustc_middle::mir::{Body, Local}; use rustc_middle::ty::{self, RegionVid, TyCtxt}; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use tracing::debug; use crate::region_infer::RegionInferenceContext; diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 94b5044857689..ef8e757a54780 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -1,7 +1,7 @@ use std::error::Error; use std::fmt::Debug; use std::fs::{self, File}; -use std::io::{BufWriter, Write}; +use std::io::Write; use std::path::Path; use polonius_engine::{AllFacts as PoloniusFacts, Atom}; @@ -10,8 +10,8 @@ use rustc_middle::mir::Local; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::move_paths::MovePathIndex; -use crate::location::{LocationIndex, LocationTable}; use crate::BorrowIndex; +use crate::location::{LocationIndex, LocationTable}; #[derive(Copy, Clone, Debug)] pub struct RustcFacts; @@ -127,7 +127,7 @@ impl<'w> FactWriter<'w> { T: FactRow, { let file = &self.dir.join(file_name); - let mut file = BufWriter::new(File::create(file)?); + let mut file = File::create_buffered(file)?; for row in rows { row.write(&mut file, self.location_table)?; } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index ffb350b1d1f0f..a11eca0b9c746 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -6,6 +6,7 @@ #![feature(assert_matches)] #![feature(box_patterns)] #![feature(control_flow_enum)] +#![feature(file_buffered)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustc_attrs)] @@ -37,13 +38,13 @@ use rustc_middle::mir::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; use rustc_middle::{bug, span_bug}; +use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::{ EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, }; use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex, }; -use rustc_mir_dataflow::Analysis; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; use rustc_target::abi::FieldIdx; @@ -83,10 +84,10 @@ mod util; pub mod consumers; use borrow_set::{BorrowData, BorrowSet}; -use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows}; +use dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows}; use nll::PoloniusOutput; use place_ext::PlaceExt; -use places_conflict::{places_conflict, PlaceConflictBias}; +use places_conflict::{PlaceConflictBias, places_conflict}; use region_infer::RegionInferenceContext; use renumber::RegionCtxt; @@ -304,11 +305,11 @@ fn do_mir_borrowck<'tcx>( promoted_mbcx.report_move_errors(); diags = promoted_mbcx.diags; - struct MoveVisitor<'a, 'b, 'mir, 'infcx, 'tcx> { - ctxt: &'a mut MirBorrowckCtxt<'b, 'mir, 'infcx, 'tcx>, + struct MoveVisitor<'a, 'b, 'infcx, 'tcx> { + ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>, } - impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, '_, 'tcx> { + impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { if let Operand::Move(place) = operand { self.ctxt.check_movable_place(location, *place); @@ -522,10 +523,10 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { } } -struct MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx> { +struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { infcx: &'infcx BorrowckInferCtxt<'tcx>, param_env: ParamEnv<'tcx>, - body: &'mir Body<'tcx>, + body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>, /// Map from MIR `Location` to `LocationIndex`; created @@ -599,28 +600,28 @@ struct MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx> { // 2. loans made in overlapping scopes do not conflict // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> - for MirBorrowckCtxt<'a, 'mir, '_, 'tcx> +impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> + for MirBorrowckCtxt<'a, '_, 'tcx> { - type FlowState = Flows<'a, 'mir, 'tcx>; + type Domain = BorrowckDomain<'a, 'tcx>; fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'_, 'mir, 'tcx>, - stmt: &'mir Statement<'tcx>, + state: &BorrowckDomain<'a, 'tcx>, + stmt: &'a Statement<'tcx>, location: Location, ) { - debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, flow_state); + debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state); let span = stmt.source_info.span; - self.check_activations(location, span, flow_state); + self.check_activations(location, span, state); match &stmt.kind { StatementKind::Assign(box (lhs, rhs)) => { - self.consume_rvalue(location, (rhs, span), flow_state); + self.consume_rvalue(location, (rhs, span), state); - self.mutate_place(location, (*lhs, span), Shallow(None), flow_state); + self.mutate_place(location, (*lhs, span), Shallow(None), state); } StatementKind::FakeRead(box (_, place)) => { // Read for match doesn't access any memory and is used to @@ -637,11 +638,11 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } StatementKind::Intrinsic(box kind) => match kind { - NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state), + NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), state), NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( span, "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", @@ -662,7 +663,7 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> (Place::from(*local), span), (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); } StatementKind::Nop @@ -677,18 +678,18 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'_, 'mir, 'tcx>, - term: &'mir Terminator<'tcx>, + state: &BorrowckDomain<'a, 'tcx>, + term: &'a Terminator<'tcx>, loc: Location, ) { - debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, flow_state); + debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state); let span = term.source_info.span; - self.check_activations(loc, span, flow_state); + self.check_activations(loc, span, state); match &term.kind { TerminatorKind::SwitchInt { discr, targets: _ } => { - self.consume_operand(loc, (discr, span), flow_state); + self.consume_operand(loc, (discr, span), state); } TerminatorKind::Drop { place, target: _, unwind: _, replace } => { debug!( @@ -704,7 +705,7 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> (*place, span), (AccessDepth::Drop, Write(write_kind)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); } TerminatorKind::Call { @@ -716,29 +717,29 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> call_source: _, fn_span: _, } => { - self.consume_operand(loc, (func, span), flow_state); + self.consume_operand(loc, (func, span), state); for arg in args { - self.consume_operand(loc, (&arg.node, arg.span), flow_state); + self.consume_operand(loc, (&arg.node, arg.span), state); } - self.mutate_place(loc, (*destination, span), Deep, flow_state); + self.mutate_place(loc, (*destination, span), Deep, state); } TerminatorKind::TailCall { func, args, fn_span: _ } => { - self.consume_operand(loc, (func, span), flow_state); + self.consume_operand(loc, (func, span), state); for arg in args { - self.consume_operand(loc, (&arg.node, arg.span), flow_state); + self.consume_operand(loc, (&arg.node, arg.span), state); } } TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { - self.consume_operand(loc, (cond, span), flow_state); + self.consume_operand(loc, (cond, span), state); if let AssertKind::BoundsCheck { len, index } = &**msg { - self.consume_operand(loc, (len, span), flow_state); - self.consume_operand(loc, (index, span), flow_state); + self.consume_operand(loc, (len, span), state); + self.consume_operand(loc, (index, span), state); } } TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { - self.consume_operand(loc, (value, span), flow_state); - self.mutate_place(loc, (*resume_arg, span), Deep, flow_state); + self.consume_operand(loc, (value, span), state); + self.mutate_place(loc, (*resume_arg, span), Deep, state); } TerminatorKind::InlineAsm { @@ -752,22 +753,17 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> for op in operands { match op { InlineAsmOperand::In { reg: _, value } => { - self.consume_operand(loc, (value, span), flow_state); + self.consume_operand(loc, (value, span), state); } InlineAsmOperand::Out { reg: _, late: _, place, .. } => { if let Some(place) = place { - self.mutate_place(loc, (*place, span), Shallow(None), flow_state); + self.mutate_place(loc, (*place, span), Shallow(None), state); } } InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => { - self.consume_operand(loc, (in_value, span), flow_state); + self.consume_operand(loc, (in_value, span), state); if let &Some(out_place) = out_place { - self.mutate_place( - loc, - (out_place, span), - Shallow(None), - flow_state, - ); + self.mutate_place(loc, (out_place, span), Shallow(None), state); } } InlineAsmOperand::Const { value: _ } @@ -794,8 +790,8 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'_, 'mir, 'tcx>, - term: &'mir Terminator<'tcx>, + state: &BorrowckDomain<'a, 'tcx>, + term: &'a Terminator<'tcx>, loc: Location, ) { let span = term.source_info.span; @@ -805,7 +801,7 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> if self.movable_coroutine { // Look for any active borrows to locals let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { + for i in state.borrows.iter() { let borrow = &borrow_set[i]; self.check_for_local_borrow(borrow, span); } @@ -821,7 +817,7 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> // StorageDead, but we don't always emit those (notably on unwind paths), // so this "extra check" serves as a kind of backup. let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { + for i in state.borrows.iter() { let borrow = &borrow_set[i]; self.check_for_invalidation_at_exit(loc, borrow, span); } @@ -972,8 +968,8 @@ impl InitializationRequiringAction { } } -impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { - fn body(&self) -> &'mir Body<'tcx> { +impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { + fn body(&self) -> &'a Body<'tcx> { self.body } @@ -989,7 +985,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { place_span: (Place<'tcx>, Span), kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { let (sd, rw) = kind; @@ -1020,11 +1016,10 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { place_span, rw, is_local_mutation_allowed, - flow_state, + state, location, ); - let conflict_error = - self.check_access_for_conflict(location, place_span, sd, rw, flow_state); + let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state); if conflict_error || mutability_error { debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind); @@ -1032,14 +1027,14 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { } } - #[instrument(level = "debug", skip(self, flow_state))] + #[instrument(level = "debug", skip(self, state))] fn check_access_for_conflict( &mut self, location: Location, place_span: (Place<'tcx>, Span), sd: AccessDepth, rw: ReadOrWrite, - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) -> bool { let mut error_reported = false; let borrow_set = Rc::clone(&self.borrow_set); @@ -1054,7 +1049,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { } &polonius_output } else { - &flow_state.borrows + &state.borrows }; each_borrow_involving_path( @@ -1180,25 +1175,25 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location: Location, place_span: (Place<'tcx>, Span), kind: AccessDepth, - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { // Write of P[i] or *P requires P init'd. - self.check_if_assigned_path_is_moved(location, place_span, flow_state); + self.check_if_assigned_path_is_moved(location, place_span, state); self.access_place( location, place_span, (kind, Write(WriteKind::Mutate)), LocalMutationIsAllowed::No, - flow_state, + state, ); } fn consume_rvalue( &mut self, location: Location, - (rvalue, span): (&'mir Rvalue<'tcx>, Span), - flow_state: &Flows<'_, 'mir, 'tcx>, + (rvalue, span): (&'a Rvalue<'tcx>, Span), + state: &BorrowckDomain<'a, 'tcx>, ) { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { @@ -1224,7 +1219,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (place, span), access_kind, LocalMutationIsAllowed::No, - flow_state, + state, ); let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) { @@ -1237,7 +1232,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location, action, (place.as_ref(), span), - flow_state, + state, ); } @@ -1257,14 +1252,14 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (place, span), access_kind, LocalMutationIsAllowed::No, - flow_state, + state, ); self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Borrow, (place.as_ref(), span), - flow_state, + state, ); } @@ -1275,7 +1270,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { | Rvalue::UnaryOp(_ /*un_op*/, operand) | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) | Rvalue::ShallowInitBox(operand, _ /*ty*/) => { - self.consume_operand(location, (operand, span), flow_state) + self.consume_operand(location, (operand, span), state) } &Rvalue::CopyForDeref(place) => { @@ -1284,7 +1279,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (place, span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1292,7 +1287,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } @@ -1307,19 +1302,19 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (place, span), (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => { - self.consume_operand(location, (operand1, span), flow_state); - self.consume_operand(location, (operand2, span), flow_state); + self.consume_operand(location, (operand1, span), state); + self.consume_operand(location, (operand2, span), state); } Rvalue::NullaryOp(_op, _ty) => { @@ -1349,7 +1344,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { } for operand in operands { - self.consume_operand(location, (operand, span), flow_state); + self.consume_operand(location, (operand, span), state); } } } @@ -1455,8 +1450,8 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { fn consume_operand( &mut self, location: Location, - (operand, span): (&'mir Operand<'tcx>, Span), - flow_state: &Flows<'_, 'mir, 'tcx>, + (operand, span): (&'a Operand<'tcx>, Span), + state: &BorrowckDomain<'a, 'tcx>, ) { match *operand { Operand::Copy(place) => { @@ -1467,7 +1462,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (place, span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1475,7 +1470,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Operand::Move(place) => { @@ -1488,7 +1483,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (place, span), (Deep, Write(WriteKind::Move)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1496,7 +1491,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Operand::Constant(_) => {} @@ -1580,7 +1575,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { &mut self, location: Location, span: Span, - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with @@ -1600,7 +1595,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (borrow.borrowed_place, span), (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), LocalMutationIsAllowed::No, - flow_state, + state, ); // We do not need to call `check_if_path_or_subpath_is_moved` // again, as we already called it when we made the @@ -1618,13 +1613,9 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { match elem { ProjectionElem::Deref => match place_ty.ty.kind() { ty::Ref(..) | ty::RawPtr(..) => { - self.move_errors.push(MoveError::new( - place, - location, - BorrowedContent { - target_place: place_ref.project_deeper(&[elem], tcx), - }, - )); + self.move_errors.push(MoveError::new(place, location, BorrowedContent { + target_place: place_ref.project_deeper(&[elem], tcx), + })); return; } ty::Adt(adt, _) => { @@ -1744,9 +1735,9 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Bad scenarios: // @@ -1849,9 +1840,9 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Bad scenarios: // @@ -1868,7 +1859,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { // must have been initialized for the use to be sound. // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); + self.check_if_full_path_is_moved(location, desired_action, place_span, state); if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) = place_span.0.last_projection() @@ -1948,7 +1939,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { &mut self, location: Location, (place, span): (Place<'tcx>, Span), - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { debug!("check_if_assigned_path_is_moved place: {:?}", place); @@ -1970,7 +1961,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { ProjectionElem::Deref => { self.check_if_full_path_is_moved( location, InitializationRequiringAction::Use, - (place_base, span), flow_state); + (place_base, span), state); // (base initialized; no need to // recur further) break; @@ -1990,7 +1981,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Assignment, - (place_base, span), flow_state); + (place_base, span), state); // (base initialized; no need to // recur further) @@ -2000,7 +1991,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { // Once `let s; s.x = V; read(s.x);`, // is allowed, remove this match arm. ty::Adt(..) | ty::Tuple(..) => { - check_parent_of_field(self, location, place_base, span, flow_state); + check_parent_of_field(self, location, place_base, span, state); } _ => {} @@ -2009,12 +2000,12 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { } } - fn check_parent_of_field<'mir, 'tcx>( - this: &mut MirBorrowckCtxt<'_, 'mir, '_, 'tcx>, + fn check_parent_of_field<'a, 'tcx>( + this: &mut MirBorrowckCtxt<'a, '_, 'tcx>, location: Location, base: PlaceRef<'tcx>, span: Span, - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { // rust-lang/rust#21232: Until Rust allows reads from the // initialized parts of partially initialized structs, we @@ -2047,7 +2038,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { // Shallow so that we'll stop at any dereference; we'll // report errors about issues with such bases elsewhere. - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Find the shortest uninitialized prefix you can reach // without going over a Deref. @@ -2074,12 +2065,12 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if base.ty(this.body(), tcx).ty.is_union() { - if this.move_data.path_map[mpi].iter().any(|moi| { + if base.ty(this.body(), tcx).ty.is_union() + && this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) - }) { - return; - } + }) + { + return; } this.report_use_of_moved_or_uninitialized( @@ -2105,7 +2096,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (place, span): (Place<'tcx>, Span), kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, location: Location, ) -> bool { debug!( @@ -2129,7 +2120,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { }; match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { - self.add_used_mut(root_place, flow_state); + self.add_used_mut(root_place, state); return false; } Err(place_err) => { @@ -2141,7 +2132,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { - self.add_used_mut(root_place, flow_state); + self.add_used_mut(root_place, state); return false; } Err(place_err) => { @@ -2199,7 +2190,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { // partial initialization, do not complain about mutability // errors except for actual mutation (as opposed to an attempt // to do a partial initialization). - let previously_initialized = self.is_local_ever_initialized(place.local, flow_state); + let previously_initialized = self.is_local_ever_initialized(place.local, state); // at this point, we have set up the error reporting state. if let Some(init_index) = previously_initialized { @@ -2221,22 +2212,22 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { fn is_local_ever_initialized( &self, local: Local, - flow_state: &Flows<'_, 'mir, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) -> Option { let mpi = self.move_data.rev_lookup.find_local(local)?; let ii = &self.move_data.init_path_map[mpi]; - ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied() + ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied() } /// Adds the place into the used mutable variables set - fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'_, 'mir, 'tcx>) { + fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) { match root_place { RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { // If the local may have been initialized, and it is now currently being // mutated, then it is justified to be annotated with the `mut` // keyword, since the mutation may be a possible reassignment. if is_local_mutation_allowed != LocalMutationIsAllowed::Yes - && self.is_local_ever_initialized(local, flow_state).is_some() + && self.is_local_ever_initialized(local, state).is_some() { self.used_mut.insert(local); } @@ -2484,7 +2475,7 @@ mod diags { } } - impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { + impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) { self.diags.buffer_error(diag); } @@ -2522,7 +2513,7 @@ mod diags { } pub(crate) fn emit_errors(&mut self) -> Option { - let mut res = None; + let mut res = self.infcx.tainted_by_errors(); // Buffer any move errors that we collected and de-duplicated. for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 6525befc13b99..d85af52b01e36 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -9,17 +9,17 @@ use polonius_engine::{Algorithm, Output}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::LocalDefId; use rustc_index::IndexSlice; -use rustc_middle::mir::pretty::{dump_mir_with_options, PrettyPrintMirOptions}; +use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; use rustc_middle::mir::{ - create_dump_file, dump_enabled, dump_mir, Body, ClosureOutlivesSubject, - ClosureRegionRequirements, PassWhere, Promoted, + Body, ClosureOutlivesSubject, ClosureRegionRequirements, PassWhere, Promoted, create_dump_file, + dump_enabled, dump_mir, }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; +use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::ResultsCursor; use rustc_session::config::MirIncludeSpans; use rustc_span::symbol::sym; use tracing::{debug, instrument}; @@ -32,7 +32,7 @@ use crate::location::LocationTable; use crate::region_infer::RegionInferenceContext; use crate::type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}; use crate::universal_regions::UniversalRegions; -use crate::{polonius, renumber, BorrowckInferCtxt}; +use crate::{BorrowckInferCtxt, polonius, renumber}; pub type PoloniusOutput = Output; @@ -75,14 +75,14 @@ pub(crate) fn replace_regions_in_mir<'tcx>( /// Computes the (non-lexical) regions from the input MIR. /// /// This may result in errors being reported. -pub(crate) fn compute_regions<'cx, 'tcx>( +pub(crate) fn compute_regions<'a, 'tcx>( infcx: &BorrowckInferCtxt<'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, location_table: &LocationTable, param_env: ty::ParamEnv<'tcx>, - flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'_, 'cx, 'tcx>>, + flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, upvars: &[&ty::CapturedPlace<'tcx>], @@ -301,13 +301,13 @@ pub(super) fn dump_nll_mir<'tcx>( #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] -pub(super) fn dump_annotation<'tcx, 'cx>( - infcx: &'cx BorrowckInferCtxt<'tcx>, +pub(super) fn dump_annotation<'tcx, 'infcx>( + infcx: &'infcx BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, opaque_type_values: &FxIndexMap>, - diags: &mut crate::diags::BorrowckDiags<'cx, 'tcx>, + diags: &mut crate::diags::BorrowckDiags<'infcx, 'tcx>, ) { let tcx = infcx.tcx; let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index f387d5cfedcb9..1ba41cd524455 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -5,7 +5,7 @@ use rustc_target::abi::FieldIdx; use tracing::debug; use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; -use crate::{places_conflict, AccessDepth, BorrowIndex}; +use crate::{AccessDepth, BorrowIndex, places_conflict}; /// Returns `true` if the borrow represented by `kind` is /// allowed to be split into separate Reservation and diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index 0b9b8768b5600..afd811a0efb43 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -32,18 +32,18 @@ pub(super) fn emit_loan_invalidations<'tcx>( visitor.visit_body(body); } -struct LoanInvalidationsGenerator<'cx, 'tcx> { +struct LoanInvalidationsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, - all_facts: &'cx mut AllFacts, - location_table: &'cx LocationTable, - body: &'cx Body<'tcx>, - dominators: &'cx Dominators, - borrow_set: &'cx BorrowSet<'tcx>, + all_facts: &'a mut AllFacts, + location_table: &'a LocationTable, + body: &'a Body<'tcx>, + dominators: &'a Dominators, + borrow_set: &'a BorrowSet<'tcx>, } /// Visits the whole MIR and generates `invalidates()` facts. /// Most of the code implementing this was stolen from `borrow_check/mod.rs`. -impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { self.check_activations(location); @@ -212,7 +212,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> { } } -impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> { +impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { /// Simulates mutation of a place. fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) { self.access_place( diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/loan_kills.rs index ed9f714e50062..68e0865ab82c9 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_kills.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_kills.rs @@ -25,15 +25,15 @@ pub(super) fn emit_loan_kills<'tcx>( } } -struct LoanKillsGenerator<'cx, 'tcx> { +struct LoanKillsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, - all_facts: &'cx mut AllFacts, - location_table: &'cx LocationTable, - borrow_set: &'cx BorrowSet<'tcx>, - body: &'cx Body<'tcx>, + all_facts: &'a mut AllFacts, + location_table: &'a LocationTable, + borrow_set: &'a BorrowSet<'tcx>, + body: &'a Body<'tcx>, } -impl<'cx, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'cx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'a, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { // Also record CFG facts here. self.all_facts.cfg_edge.push(( diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 39d831378cde6..aeb8a6c014a4f 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -34,7 +34,7 @@ pub(super) enum PrefixSet { Shallow, } -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// Returns an iterator over the prefixes of `place` /// (inclusive) from longest to smallest, potentially /// terminating the iteration early based on `kind`. diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index d6bb006cd7e00..c62ea870acfe9 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -23,6 +23,7 @@ use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::Span; use tracing::{debug, instrument, trace}; +use crate::BorrowckInferCtxt; use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet}; use crate::dataflow::BorrowIndex; @@ -33,10 +34,9 @@ use crate::region_infer::reverse_sccs::ReverseSccGraph; use crate::region_infer::values::{ LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex, }; -use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::type_check::Locations; +use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::universal_regions::UniversalRegions; -use crate::BorrowckInferCtxt; mod dump_mir; mod graphviz; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index f97f3dfe29f6a..3cf21d4a36b83 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; +use rustc_hir::OpaqueTyOrigin; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _}; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_macros::extension; @@ -165,10 +165,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. prev.span = prev.span.substitute_dummy(concrete_type.span); } else { - result.insert( - opaque_type_key.def_id, - OpaqueHiddenType { ty, span: concrete_type.span }, - ); + result.insert(opaque_type_key.def_id, OpaqueHiddenType { + ty, + span: concrete_type.span, + }); } // Check that all opaque types have the same region parameters if they have the same diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index 3cc5fa4404e35..cfd5a92787ed2 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -5,8 +5,8 @@ use rustc_data_structures::graph; use rustc_data_structures::graph::vec_graph::VecGraph; use rustc_middle::ty::RegionVid; -use crate::constraints::ConstraintSccIndex; use crate::RegionInferenceContext; +use crate::constraints::ConstraintSccIndex; pub(crate) struct ReverseSccGraph { graph: VecGraph, diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index d62f2067729df..b95fe5b50282e 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -2,9 +2,9 @@ use std::fmt::Debug; use std::rc::Rc; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_index::Idx; use rustc_index::bit_set::SparseBitMatrix; use rustc_index::interval::{IntervalSet, SparseIntervalMatrix}; -use rustc_index::Idx; use rustc_middle::mir::{BasicBlock, Location}; use rustc_middle::ty::{self, RegionVid}; use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; @@ -118,10 +118,8 @@ impl LivenessValues { debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); if let Some(points) = &mut self.points { points.insert(region, point); - } else { - if self.elements.point_in_range(point) { - self.live_regions.as_mut().unwrap().insert(region); - } + } else if self.elements.point_in_range(point) { + self.live_regions.as_mut().unwrap().insert(region); } // When available, record the loans flowing into this region as live at the given point. @@ -137,10 +135,8 @@ impl LivenessValues { debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); if let Some(this) = &mut self.points { this.union_row(region, points); - } else { - if points.iter().any(|point| self.elements.point_in_range(point)) { - self.live_regions.as_mut().unwrap().insert(region); - } + } else if points.iter().any(|point| self.elements.point_in_range(point)) { + self.live_regions.as_mut().unwrap().insert(region); } // When available, record the loans flowing into this region as live at the given points. diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 4a50b0f070408..627444a4ce5b8 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,5 +1,5 @@ -use rustc_errors::codes::*; use rustc_errors::MultiSpan; +use rustc_errors::codes::*; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; @@ -415,7 +415,7 @@ pub(crate) enum CaptureReasonSuggest<'tcx> { span: Span, }, #[suggestion( - borrowck_suggest_create_freash_reborrow, + borrowck_suggest_create_fresh_reborrow, applicability = "maybe-incorrect", code = ".as_mut()", style = "verbose" diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 4b15ce8873d37..0c6f8cd7b5bfe 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -5,11 +5,11 @@ use rustc_infer::infer::canonical::Canonical; use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast}; -use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_span::def_id::DefId; +use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; -use rustc_trait_selection::traits::ObligationCause; use tracing::{debug, instrument}; use super::{Locations, NormalizeLocation, TypeChecker}; diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 0f1d79a2c3530..fc1600ea4a611 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,13 +6,13 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::bug; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; -use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::Span; +use rustc_trait_selection::traits::ScrubbedTraitError; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; -use rustc_trait_selection::traits::ScrubbedTraitError; use tracing::{debug, instrument}; use crate::constraints::OutlivesConstraint; diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 33cdb1b1f3774..6977fed59ed9d 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -6,10 +6,10 @@ use rustc_hir::def::DefKind; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::GenericKind; -use rustc_infer::infer::{outlives, InferCtxt}; +use rustc_infer::infer::{InferCtxt, outlives}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -18,7 +18,7 @@ use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use tracing::{debug, instrument}; use type_op::TypeOpOutput; -use crate::type_check::{constraint_conversion, Locations, MirTypeckRegionConstraints}; +use crate::type_check::{Locations, MirTypeckRegionConstraints, constraint_conversion}; use crate::universal_regions::UniversalRegions; #[derive(Debug)] @@ -181,12 +181,12 @@ impl UniversalRegionRelations<'_> { } } -struct UniversalRegionRelationsBuilder<'this, 'tcx> { - infcx: &'this InferCtxt<'tcx>, +struct UniversalRegionRelationsBuilder<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, universal_regions: Rc>, implicit_region_bound: ty::Region<'tcx>, - constraints: &'this mut MirTypeckRegionConstraints<'tcx>, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, // outputs: outlives: TransitiveRelationBuilder, diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 56f8464628c7b..141f251244bf9 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -77,20 +77,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let output_ty = Ty::new_coroutine( self.tcx(), self.tcx().coroutine_for_closure(mir_def_id), - ty::CoroutineArgs::new( - self.tcx(), - ty::CoroutineArgsParts { - parent_args: args.parent_args(), - kind_ty: Ty::from_coroutine_closure_kind(self.tcx(), args.kind()), - return_ty: user_provided_sig.output(), - tupled_upvars_ty, - // For async closures, none of these can be annotated, so just fill - // them with fresh ty vars. - resume_ty: next_ty_var(), - yield_ty: next_ty_var(), - witness: next_ty_var(), - }, - ) + ty::CoroutineArgs::new(self.tcx(), ty::CoroutineArgsParts { + parent_args: args.parent_args(), + kind_ty: Ty::from_coroutine_closure_kind(self.tcx(), args.kind()), + return_ty: user_provided_sig.output(), + tupled_upvars_ty, + // For async closures, none of these can be annotated, so just fill + // them with fresh ty vars. + resume_ty: next_ty_var(), + yield_ty: next_ty_var(), + witness: next_ty_var(), + }) .args, ); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index a24fd95e3e650..d4900d21f8f5a 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -7,10 +7,10 @@ use rustc_middle::mir::{Body, Local, Location, SourceInfo}; use rustc_middle::span_bug; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt}; +use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::ResultsCursor; use tracing::debug; use super::TypeChecker; @@ -30,11 +30,11 @@ mod trace; /// /// N.B., this computation requires normalization; therefore, it must be /// performed before -pub(super) fn generate<'mir, 'tcx>( +pub(super) fn generate<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &Rc, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>, + flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, ) { debug!("liveness::generate"); @@ -148,12 +148,12 @@ fn record_regular_live_regions<'tcx>( } /// Visitor looking for regions that should be live within rvalues or calls. -struct LiveVariablesVisitor<'cx, 'tcx> { +struct LiveVariablesVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, - liveness_constraints: &'cx mut LivenessValues, + liveness_constraints: &'a mut LivenessValues, } -impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> { /// We sometimes have `args` within an rvalue, or within a /// call. Make them live at the location where they appear. fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) { @@ -188,7 +188,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> { } } -impl<'cx, 'tcx> LiveVariablesVisitor<'cx, 'tcx> { +impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> { /// Some variable is "regular live" at `location` -- i.e., it may be used later. This means that /// all regions appearing in the type of `value` must be live at `location`. fn record_regions_live_at(&mut self, value: T, location: Location) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs index 7f6aabf8841dd..3a458731f2891 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs @@ -11,13 +11,13 @@ use crate::location::{LocationIndex, LocationTable}; type VarPointRelation = Vec<(Local, LocationIndex)>; type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>; -struct UseFactsExtractor<'me, 'tcx> { - var_defined_at: &'me mut VarPointRelation, - var_used_at: &'me mut VarPointRelation, - location_table: &'me LocationTable, - var_dropped_at: &'me mut VarPointRelation, - move_data: &'me MoveData<'tcx>, - path_accessed_at_base: &'me mut PathPointRelation, +struct UseFactsExtractor<'a, 'tcx> { + var_defined_at: &'a mut VarPointRelation, + var_used_at: &'a mut VarPointRelation, + location_table: &'a LocationTable, + var_dropped_at: &'a mut VarPointRelation, + move_data: &'a MoveData<'tcx>, + path_accessed_at_base: &'a mut PathPointRelation, } // A Visitor to walk through the MIR and extract point-wise facts diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index de3ff8378bcc7..8cbe3ac67016b 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -8,10 +8,10 @@ use rustc_infer::infer::outlives::for_liveness; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; -use rustc_mir_dataflow::ResultsCursor; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -37,11 +37,11 @@ use crate::type_check::{NormalizeLocation, TypeChecker}; /// DROP-LIVE set are to the liveness sets for regions found in the /// `dropck_outlives` result of the variable's type (in particular, /// this respects `#[may_dangle]` annotations). -pub(super) fn trace<'mir, 'tcx>( +pub(super) fn trace<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &Rc, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>, + flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, boring_locals: Vec, @@ -99,29 +99,29 @@ pub(super) fn trace<'mir, 'tcx>( } /// Contextual state for the type-liveness coroutine. -struct LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx> { +struct LivenessContext<'a, 'typeck, 'b, 'tcx> { /// Current type-checker, giving us our inference context etc. - typeck: &'me mut TypeChecker<'typeck, 'tcx>, + typeck: &'a mut TypeChecker<'typeck, 'tcx>, /// Defines the `PointIndex` mapping - elements: &'me DenseLocationMap, + elements: &'a DenseLocationMap, /// MIR we are analyzing. - body: &'me Body<'tcx>, + body: &'a Body<'tcx>, /// Mapping to/from the various indices used for initialization tracking. - move_data: &'me MoveData<'tcx>, + move_data: &'a MoveData<'tcx>, /// Cache for the results of `dropck_outlives` query. drop_data: FxIndexMap, DropData<'tcx>>, /// Results of dataflow tracking which variables (and paths) have been /// initialized. - flow_inits: &'me mut ResultsCursor<'flow, 'tcx, MaybeInitializedPlaces<'a, 'flow, 'tcx>>, + flow_inits: &'a mut ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>, /// Index indicating where each variable is assigned, used, or /// dropped. - local_use_map: &'me LocalUseMap, + local_use_map: &'a LocalUseMap, } struct DropData<'tcx> { @@ -129,8 +129,8 @@ struct DropData<'tcx> { region_constraint_data: Option<&'tcx QueryRegionConstraints<'tcx>>, } -struct LivenessResults<'a, 'me, 'typeck, 'flow, 'tcx> { - cx: LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx>, +struct LivenessResults<'a, 'typeck, 'b, 'tcx> { + cx: LivenessContext<'a, 'typeck, 'b, 'tcx>, /// Set of points that define the current local. defs: BitSet, @@ -151,8 +151,8 @@ struct LivenessResults<'a, 'me, 'typeck, 'flow, 'tcx> { stack: Vec, } -impl<'a, 'me, 'typeck, 'flow, 'tcx> LivenessResults<'a, 'me, 'typeck, 'flow, 'tcx> { - fn new(cx: LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx>) -> Self { +impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { + fn new(cx: LivenessContext<'a, 'typeck, 'b, 'tcx>) -> Self { let num_points = cx.elements.num_points(); LivenessResults { cx, @@ -218,7 +218,7 @@ impl<'a, 'me, 'typeck, 'flow, 'tcx> LivenessResults<'a, 'me, 'typeck, 'flow, 'tc // This collect is more necessary than immediately apparent // because these facts go into `add_drop_live_facts_for()`, // which also writes to `all_facts`, and so this is genuinely - // a simulatneous overlapping mutable borrow. + // a simultaneous overlapping mutable borrow. // FIXME for future hackers: investigate whether this is // actually necessary; these facts come from Polonius // and probably maybe plausibly does not need to go back in. @@ -353,11 +353,11 @@ impl<'a, 'me, 'typeck, 'flow, 'tcx> LivenessResults<'a, 'me, 'typeck, 'flow, 'tc let location = self.cx.elements.to_location(drop_point); debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); - if self.cx.initialized_at_terminator(location.block, mpi) { - if self.drop_live_at.insert(drop_point) { - self.drop_locations.push(location); - self.stack.push(drop_point); - } + if self.cx.initialized_at_terminator(location.block, mpi) + && self.drop_live_at.insert(drop_point) + { + self.drop_locations.push(location); + self.stack.push(drop_point); } } @@ -505,7 +505,7 @@ impl<'a, 'me, 'typeck, 'flow, 'tcx> LivenessResults<'a, 'me, 'typeck, 'flow, 'tc } } -impl<'tcx> LivenessContext<'_, '_, '_, '_, 'tcx> { +impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { /// Returns `true` if the local variable (or some part of it) is initialized at the current /// cursor position. Callers should call one of the `seek` methods immediately before to point /// the cursor to the desired location. diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 224f8d5c893d7..16e51e82f85e0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -31,20 +31,20 @@ use rustc_middle::ty::{ UserType, UserTypeAnnotationIndex, }; use rustc_middle::{bug, span_bug}; +use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::ResultsCursor; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; +use rustc_span::{DUMMY_SP, Span}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx}; +use rustc_trait_selection::traits::PredicateObligation; use rustc_trait_selection::traits::query::type_op::custom::{ - scrape_region_constraints, CustomTypeOp, + CustomTypeOp, scrape_region_constraints, }; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; -use rustc_trait_selection::traits::PredicateObligation; use tracing::{debug, instrument, trace}; use crate::borrow_set::BorrowSet; @@ -53,13 +53,13 @@ use crate::diagnostics::UniverseInfo; use crate::facts::AllFacts; use crate::location::LocationTable; use crate::member_constraints::MemberConstraintSet; -use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; use crate::region_infer::TypeTest; +use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; use crate::renumber::RegionCtxt; use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations}; use crate::universal_regions::{DefiningTy, UniversalRegions}; -use crate::{path_utils, BorrowckInferCtxt}; +use crate::{BorrowckInferCtxt, path_utils}; macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ @@ -116,7 +116,7 @@ mod relate_tys; /// - `flow_inits` -- results of a maybe-init dataflow analysis /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `elements` -- MIR region map -pub(crate) fn type_check<'mir, 'tcx>( +pub(crate) fn type_check<'a, 'tcx>( infcx: &BorrowckInferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, @@ -125,7 +125,7 @@ pub(crate) fn type_check<'mir, 'tcx>( location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>, + flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, elements: &Rc, upvars: &[&ty::CapturedPlace<'tcx>], @@ -1944,11 +1944,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, Some(span)), [ + ty, + ]); self.prove_trait_ref( trait_ref, @@ -1961,11 +1960,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::ShallowInitBox(operand, ty) => { self.check_operand(operand, location); - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [*ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, Some(span)), [ + *ty, + ]); self.prove_trait_ref( trait_ref, @@ -1977,49 +1975,111 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::Cast(cast_kind, op, ty) => { self.check_operand(op, location); - match cast_kind { - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); + match *cast_kind { + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, coercion_source) => { + let is_implicit_coercion = coercion_source == CoercionSource::Implicit; + let src_sig = op.ty(body, tcx).fn_sig(tcx); + + // HACK: This shouldn't be necessary... We can remove this when we actually + // get binders with where clauses, then elaborate implied bounds into that + // binder, and implement a higher-ranked subtyping algorithm that actually + // respects these implied bounds. + // + // This protects against the case where we are casting from a higher-ranked + // fn item to a non-higher-ranked fn pointer, where the cast throws away + // implied bounds that would've needed to be checked at the call site. This + // only works when we're casting to a non-higher-ranked fn ptr, since + // placeholders in the target signature could have untracked implied + // bounds, resulting in incorrect errors. + // + // We check that this signature is WF before subtyping the signature with + // the target fn sig. + if src_sig.has_bound_regions() + && let ty::FnPtr(target_fn_tys, target_hdr) = *ty.kind() + && let target_sig = target_fn_tys.with(target_hdr) + && let Some(target_sig) = target_sig.no_bound_vars() + { + let src_sig = self.infcx.instantiate_binder_with_fresh_vars( + span, + BoundRegionConversionTime::HigherRankedType, + src_sig, + ); + let src_ty = Ty::new_fn_ptr(self.tcx(), ty::Binder::dummy(src_sig)); + self.prove_predicate( + ty::ClauseKind::WellFormed(src_ty.into()), + location.to_locations(), + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, + ); + + let src_ty = self.normalize(src_ty, location); + if let Err(terr) = self.sub_types( + src_ty, + *ty, + location.to_locations(), + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, + ) { + span_mirbug!( + self, + rvalue, + "equating {:?} with {:?} yields {:?}", + target_sig, + src_sig, + terr + ); + }; + } + + let src_ty = Ty::new_fn_ptr(tcx, src_sig); + // HACK: We want to assert that the signature of the source fn is + // well-formed, because we don't enforce that via the WF of FnDef + // types normally. This should be removed when we improve the tracking + // of implied bounds of fn signatures. + self.prove_predicate( + ty::ClauseKind::WellFormed(src_ty.into()), + location.to_locations(), + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, + ); // The type that we see in the fcx is like // `foo::<'a, 'b>`, where `foo` is the path to a // function definition. When we extract the // signature, it comes from the `fn_sig` query, // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); - - let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig); - + let src_ty = self.normalize(src_ty, location); if let Err(terr) = self.sub_types( - ty_fn_ptr_from, + src_ty, *ty, location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, ) { span_mirbug!( self, rvalue, "equating {:?} with {:?} yields {:?}", - ty_fn_ptr_from, + src_ty, ty, terr ); } } - CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(safety)) => { + CastKind::PointerCoercion( + PointerCoercion::ClosureFnPointer(safety), + coercion_source, + ) => { let sig = match op.ty(body, tcx).kind() { ty::Closure(_, args) => args.as_closure().sig(), _ => bug!(), }; let ty_fn_ptr_from = - Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *safety)); + Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, safety)); + let is_implicit_coercion = coercion_source == CoercionSource::Implicit; if let Err(terr) = self.sub_types( ty_fn_ptr_from, *ty, location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, ) { span_mirbug!( self, @@ -2032,7 +2092,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { + CastKind::PointerCoercion( + PointerCoercion::UnsafeFnPointer, + coercion_source, + ) => { let fn_sig = op.ty(body, tcx).fn_sig(tcx); // The type that we see in the fcx is like @@ -2044,11 +2107,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); + let is_implicit_coercion = coercion_source == CoercionSource::Implicit; if let Err(terr) = self.sub_types( ty_fn_ptr_from, *ty, location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, ) { span_mirbug!( self, @@ -2061,7 +2125,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::PointerCoercion(PointerCoercion::Unsize) => { + CastKind::PointerCoercion(PointerCoercion::Unsize, coercion_source) => { let &ty = ty; let trait_ref = ty::TraitRef::new( tcx, @@ -2069,22 +2133,21 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { [op.ty(body, tcx), ty], ); + let is_implicit_coercion = coercion_source == CoercionSource::Implicit; + let unsize_to = tcx.fold_regions(ty, |r, _| { + if let ty::ReVar(_) = r.kind() { tcx.lifetimes.re_erased } else { r } + }); self.prove_trait_ref( trait_ref, location.to_locations(), ConstraintCategory::Cast { - unsize_to: Some(tcx.fold_regions(ty, |r, _| { - if let ty::ReVar(_) = r.kind() { - tcx.lifetimes.re_erased - } else { - r - } - })), + is_implicit_coercion, + unsize_to: Some(unsize_to), }, ); } - CastKind::DynStar => { + CastKind::PointerCoercion(PointerCoercion::DynStar, coercion_source) => { // get the constraints from the target type (`dyn* Clone`) // // apply them to prove that the source type `Foo` implements `Clone` etc @@ -2095,12 +2158,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let self_ty = op.ty(body, tcx); + let is_implicit_coercion = coercion_source == CoercionSource::Implicit; self.prove_predicates( existential_predicates .iter() .map(|predicate| predicate.with_self_ty(tcx, self_ty)), location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, ); let outlives_predicate = tcx.mk_predicate(Binder::dummy( @@ -2111,11 +2175,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.prove_predicate( outlives_predicate, location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, ); } - CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => { + CastKind::PointerCoercion( + PointerCoercion::MutToConstPointer, + coercion_source, + ) => { let ty::RawPtr(ty_from, hir::Mutability::Mut) = op.ty(body, tcx).kind() else { span_mirbug!(self, rvalue, "unexpected base type for cast {:?}", ty,); @@ -2125,11 +2192,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span_mirbug!(self, rvalue, "unexpected target type for cast {:?}", ty,); return; }; + let is_implicit_coercion = coercion_source == CoercionSource::Implicit; if let Err(terr) = self.sub_types( *ty_from, *ty_to, location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, ) { span_mirbug!( self, @@ -2142,7 +2210,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::PointerCoercion(PointerCoercion::ArrayToPointer) => { + CastKind::PointerCoercion(PointerCoercion::ArrayToPointer, coercion_source) => { let ty_from = op.ty(body, tcx); let opt_ty_elem_mut = match ty_from.kind() { @@ -2187,11 +2255,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return; } + let is_implicit_coercion = coercion_source == CoercionSource::Implicit; if let Err(terr) = self.sub_types( *ty_elem, *ty_to, location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, + ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, ) { span_mirbug!( self, @@ -2372,7 +2441,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { src_obj, dst_obj, location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, + ConstraintCategory::Cast { + is_implicit_coercion: false, + unsize_to: None, + }, ) .unwrap(); } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index bb4a58930e1bb..bf079e813f16b 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -4,12 +4,12 @@ use rustc_infer::infer::relate::{ PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, }; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; -use rustc_infer::traits::solve::Goal; use rustc_infer::traits::Obligation; +use rustc_infer::traits::solve::Goal; use rustc_middle::mir::ConstraintCategory; use rustc_middle::span_bug; -use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; @@ -58,8 +58,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } -struct NllTypeRelating<'me, 'bccx, 'tcx> { - type_checker: &'me mut TypeChecker<'bccx, 'tcx>, +struct NllTypeRelating<'a, 'b, 'tcx> { + type_checker: &'a mut TypeChecker<'b, 'tcx>, /// Where (and why) is this relation taking place? locations: Locations, @@ -82,9 +82,9 @@ struct NllTypeRelating<'me, 'bccx, 'tcx> { ambient_variance_info: ty::VarianceDiagInfo>, } -impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { +impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { fn new( - type_checker: &'me mut TypeChecker<'bccx, 'tcx>, + type_checker: &'a mut TypeChecker<'b, 'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, universe_info: UniverseInfo<'tcx>, @@ -214,7 +214,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { let delegate = FnMutDelegate { regions: &mut |br: ty::BoundRegion| { if let Some(ex_reg_var) = reg_map.get(&br) { - return *ex_reg_var; + *ex_reg_var } else { let ex_reg_var = self.next_existential_region_var(true, br.kind.get_name()); debug!(?ex_reg_var); @@ -309,7 +309,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { } } -impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'b, 'tcx> TypeRelation> for NllTypeRelating<'_, 'b, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.type_checker.infcx.tcx } @@ -520,7 +520,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx } } -impl<'bccx, 'tcx> PredicateEmittingRelation> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'b, 'tcx> PredicateEmittingRelation> for NllTypeRelating<'_, 'b, 'tcx> { fn span(&self) -> Span { self.locations.span(self.type_checker.body) } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 9eabe817359c0..fa44ffcd17dd0 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -20,24 +20,25 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Diag; +use rustc_hir::BodyOwnerKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::BodyOwnerKind; use rustc_index::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_macros::extension; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt, + self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, + TyCtxt, TypeVisitableExt, }; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym}; use rustc_span::{ErrorGuaranteed, Symbol}; use tracing::{debug, instrument}; -use crate::renumber::RegionCtxt; use crate::BorrowckInferCtxt; +use crate::renumber::RegionCtxt; #[derive(Debug)] pub(crate) struct UniversalRegions<'tcx> { @@ -422,8 +423,8 @@ impl<'tcx> UniversalRegions<'tcx> { } } -struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx BorrowckInferCtxt<'tcx>, +struct UniversalRegionsBuilder<'infcx, 'tcx> { + infcx: &'infcx BorrowckInferCtxt<'tcx>, mir_def: LocalDefId, param_env: ty::ParamEnv<'tcx>, } @@ -628,10 +629,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = tcx .typeck(self.mir_def) .node_type(tcx.local_def_id_to_hir_id(self.mir_def)); - let args = InlineConstArgs::new( - tcx, - InlineConstArgsParts { parent_args: identity_args, ty }, - ) + let args = InlineConstArgs::new(tcx, InlineConstArgsParts { + parent_args: identity_args, + ty, + }) .args; let args = self.infcx.replace_free_regions_with_nll_infer_vars(FR, args); DefiningTy::InlineConst(self.mir_def.to_def_id(), args) @@ -688,7 +689,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> ty::Binder<'tcx, &'tcx ty::List>> { let tcx = self.infcx.tcx; - match defining_ty { + + let inputs_and_output = match defining_ty { DefiningTy::Closure(def_id, args) => { assert_eq!(self.mir_def.to_def_id(), def_id); let closure_sig = args.as_closure().sig(); @@ -798,6 +800,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // "output" (the type of the constant). assert_eq!(self.mir_def.to_def_id(), def_id); let ty = tcx.type_of(self.mir_def).instantiate_identity(); + let ty = indices.fold_to_region_vids(tcx, ty); ty::Binder::dummy(tcx.mk_type_list(&[ty])) } @@ -807,7 +810,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = args.as_inline_const().ty(); ty::Binder::dummy(tcx.mk_type_list(&[ty])) } + }; + + // FIXME(#129952): We probably want a more principled approach here. + if let Err(terr) = inputs_and_output.skip_binder().error_reported() { + self.infcx.set_tainted_by_errors(terr); } + + inputs_and_output } } diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs index 981e7daf6702e..bde07c05c0e16 100644 --- a/compiler/rustc_borrowck/src/used_muts.rs +++ b/compiler/rustc_borrowck/src/used_muts.rs @@ -7,7 +7,7 @@ use tracing::debug; use crate::MirBorrowckCtxt; -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes /// of the `unused_mut` lint. /// @@ -46,13 +46,13 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { /// MIR visitor for collecting used mutable variables. /// The 'visit lifetime represents the duration of the MIR walk. -struct GatherUsedMutsVisitor<'visit, 'a, 'mir, 'infcx, 'tcx> { +struct GatherUsedMutsVisitor<'a, 'b, 'infcx, 'tcx> { temporary_used_locals: FxIndexSet, - never_initialized_mut_locals: &'visit mut FxIndexSet, - mbcx: &'visit mut MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx>, + never_initialized_mut_locals: &'a mut FxIndexSet, + mbcx: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>, } -impl GatherUsedMutsVisitor<'_, '_, '_, '_, '_> { +impl GatherUsedMutsVisitor<'_, '_, '_, '_> { fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) { // Remove any locals that we found were initialized from the // `never_initialized_mut_locals` set. At the end, the only remaining locals will @@ -64,7 +64,7 @@ impl GatherUsedMutsVisitor<'_, '_, '_, '_, '_> { } } -impl<'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'_, '_, '_, '_, 'tcx> { +impl<'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'_, '_, '_, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { debug!("visit_terminator: terminator={:?}", terminator); match &terminator.kind { diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 1df2812e0c887..0caad997b9df1 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -3,9 +3,9 @@ use rustc_ast::{ self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind, }; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, kw, sym}; +use thin_vec::{ThinVec, thin_vec}; use crate::errors; use crate::util::check_builtin_macro_attribute; @@ -68,11 +68,10 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: 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, - thin_vec![cx.expr_ident(span, size), cx.expr_ident(span, align)], - ); + let layout = cx.expr_call(span, layout_new, thin_vec![ + cx.expr_ident(span, size), + cx.expr_ident(span, align) + ]); let call = cx.expr_call_ident(sig_span, handler, thin_vec![layout]); diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index ae2627d693867..94e40da8c9297 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,5 +1,6 @@ use ast::token::IdentIsRaw; use lint::BuiltinLintDiag; +use rustc_ast::AsmMacro; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter}; use rustc_ast::tokenstream::TokenStream; @@ -9,7 +10,7 @@ use rustc_expand::base::*; use rustc_index::bit_set::GrowableBitSet; use rustc_parse::parser::Parser; use rustc_session::lint; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{ErrorGuaranteed, InnerSpan, Span}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; @@ -234,13 +235,11 @@ pub fn parse_asm_args<'a>( continue; } args.named_args.insert(name, slot); - } else { - if !args.named_args.is_empty() || !args.reg_args.is_empty() { - let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); - let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect(); + } else if !args.named_args.is_empty() || !args.reg_args.is_empty() { + let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); + let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect(); - dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); - } + dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); } } @@ -484,6 +483,7 @@ fn parse_reg<'a>( fn expand_preparsed_asm( ecx: &mut ExtCtxt<'_>, + asm_macro: ast::AsmMacro, args: AsmArgs, ) -> ExpandResult, ()> { let mut template = vec![]; @@ -774,6 +774,7 @@ fn expand_preparsed_asm( } ExpandResult::Ready(Ok(ast::InlineAsm { + asm_macro, template, template_strs: template_strs.into_boxed_slice(), operands: args.operands, @@ -790,7 +791,7 @@ pub(super) fn expand_asm<'cx>( ) -> MacroExpanderResult<'cx> { ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { Ok(args) => { - let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else { + let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else { return ExpandResult::Retry(()); }; let expr = match mac { @@ -812,6 +813,45 @@ pub(super) fn expand_asm<'cx>( }) } +pub(super) fn expand_naked_asm<'cx>( + ecx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { + Ok(args) => { + let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args) + else { + return ExpandResult::Retry(()); + }; + let expr = match mac { + Ok(mut inline_asm) => { + // for future compatibility, we always set the NORETURN option. + // + // When we turn `asm!` into `naked_asm!` with this implementation, we can drop + // the `options(noreturn)`, which makes the upgrade smooth when `naked_asm!` + // starts disallowing the `noreturn` option in the future + inline_asm.options |= ast::InlineAsmOptions::NORETURN; + + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + kind: ast::ExprKind::InlineAsm(P(inline_asm)), + span: sp, + attrs: ast::AttrVec::new(), + tokens: None, + }) + } + Err(guar) => DummyResult::raw_expr(sp, Some(guar)), + }; + MacEager::expr(expr) + } + Err(err) => { + let guar = err.emit(); + DummyResult::any(sp, guar) + } + }) +} + pub(super) fn expand_global_asm<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -819,7 +859,8 @@ pub(super) fn expand_global_asm<'cx>( ) -> MacroExpanderResult<'cx> { ExpandResult::Ready(match parse_args(ecx, sp, tts, true) { Ok(args) => { - let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else { + let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args) + else { return ExpandResult::Retry(()); }; match mac { diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 99f433c0851ad..714493509859a 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -3,13 +3,13 @@ mod context; use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{token, DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp}; +use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token}; use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_parse::parser::Parser; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span}; use thin_vec::thin_vec; use crate::edition_panic::use_panic_2021; diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 2cd5b9d68a012..70fa4d00c0f39 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -2,15 +2,15 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, IdentIsRaw}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::{ - BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability, - Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, + BinOpKind, BorrowKind, DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, + Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::ExtCtxt; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, Symbol, sym}; +use thin_vec::{ThinVec, thin_vec}; pub(super) struct Context<'cx, 'a> { // An optimization. diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 3d3bd3aea059c..23578781a833f 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -4,8 +4,8 @@ use rustc_ast as ast; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use crate::errors; diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 4b05c144d37d7..b686a8cf935ca 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -4,7 +4,7 @@ use rustc_ast as ast; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::ptr::P; use rustc_ast::visit::{AssocCtxt, Visitor}; -use rustc_ast::{mut_visit, visit, Attribute, HasAttrs, HasTokens, NodeId}; +use rustc_ast::{Attribute, HasAttrs, HasTokens, NodeId, mut_visit, visit}; use rustc_errors::PResult; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::config::StripUnconfigured; @@ -12,8 +12,8 @@ use rustc_expand::configure; use rustc_feature::Features; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::Session; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use smallvec::SmallVec; use tracing::instrument; diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 66fa74da60d9f..6afd8c4b43b9a 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -1,7 +1,7 @@ //! Attributes injected into the crate root from command line using `-Z crate-attr`. use rustc_ast::attr::mk_attr; -use rustc_ast::{self as ast, token, AttrItem, AttrStyle}; +use rustc_ast::{self as ast, AttrItem, AttrStyle, token}; use rustc_parse::parser::ForceCollect; use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 196bf906dc028..456f2b9ab31de 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{token, ExprKind, LitIntType, LitKind, UintTy}; +use rustc_ast::{ExprKind, LitIntType, LitKind, UintTy, token}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_session::errors::report_lit_error; use rustc_span::{ErrorGuaranteed, Span}; diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 13729a9d250fe..b459cc3007d37 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -1,10 +1,10 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID}; +use rustc_ast::{AttrVec, DUMMY_NODE_ID, Expr, ExprKind, Path, Ty, TyKind}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult}; -use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol}; use crate::errors; diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index e8704bc2f639d..4be2d209ae785 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -6,7 +6,7 @@ use rustc_expand::base::{ use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_session::Session; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{Ident, sym}; use rustc_span::{ErrorGuaranteed, Span}; use crate::cfg_eval::cfg_eval; diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 22beca4ea9a06..dde696fca610b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -1,9 +1,9 @@ use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData}; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, kw, sym}; +use thin_vec::{ThinVec, thin_vec}; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; @@ -115,13 +115,10 @@ fn cs_clone_simple( // type parameters. } else if !field.ty.kind.is_anon_adt() { // let _: AssertParamIsClone; - super::assert_ty_bounds( - cx, - &mut stmts, - field.ty.clone(), - field.span, - &[sym::clone, sym::AssertParamIsClone], - ); + super::assert_ty_bounds(cx, &mut stmts, field.ty.clone(), field.span, &[ + sym::clone, + sym::AssertParamIsClone, + ]); } } }; @@ -130,13 +127,10 @@ fn cs_clone_simple( // Just a single assertion for unions, that the union impls `Copy`. // let _: AssertParamIsCopy; let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper))); - super::assert_ty_bounds( - cx, - &mut stmts, - self_ty, - trait_span, - &[sym::clone, sym::AssertParamIsCopy], - ); + super::assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, &[ + sym::clone, + sym::AssertParamIsCopy, + ]); } else { match *substr.fields { StaticStruct(vdata, ..) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index a5e1217479641..bd6f4eb8d9945 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -1,9 +1,9 @@ use rustc_ast::{self as ast, MetaItem}; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::sym; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::sym; +use thin_vec::{ThinVec, thin_vec}; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; @@ -66,13 +66,10 @@ fn cs_total_eq_assert( // Already produced an assertion for this type. } else { // let _: AssertParamIsEq; - super::assert_ty_bounds( - cx, - &mut stmts, - field.ty.clone(), - field.span, - &[sym::cmp, sym::AssertParamIsEq], - ); + super::assert_ty_bounds(cx, &mut stmts, field.ty.clone(), field.span, &[ + sym::cmp, + sym::AssertParamIsEq, + ]); } } }; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 705c41175e70f..433cbfaa6cb08 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -1,7 +1,7 @@ use rustc_ast::MetaItem; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, sym}; use thin_vec::thin_vec; use crate::deriving::generic::ty::*; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index f6299589e0f3e..ae1e5f4a2198c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -1,8 +1,8 @@ use rustc_ast::ptr::P; use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use thin_vec::thin_vec; use crate::deriving::generic::ty::*; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index a51f98f5396ce..99a9832505327 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,7 +1,7 @@ use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind}; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, sym}; use thin_vec::thin_vec; use crate::deriving::generic::ty::*; diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 57d9c07615044..06a598cf3b0ef 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -1,9 +1,9 @@ use rustc_ast::{self as ast, EnumDef, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_session::config::FmtDebug; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, Symbol, sym}; +use thin_vec::{ThinVec, thin_vec}; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 89300a36d1b56..686424770fc58 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -3,9 +3,9 @@ use rustc_ast::ptr::P; use rustc_ast::{self as ast, Expr, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, Symbol, sym}; +use thin_vec::{ThinVec, thin_vec}; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; @@ -32,10 +32,11 @@ pub(crate) fn expand_deriving_rustc_decodable( methods: vec![MethodDef { name: sym::decode, generics: Bounds { - bounds: vec![( - typaram, - vec![Path::new_(vec![krate, sym::Decoder], vec![], PathKind::Global)], - )], + bounds: vec![(typaram, vec![Path::new_( + vec![krate, sym::Decoder], + vec![], + PathKind::Global, + )])], }, explicit_self: false, nonself_args: vec![( @@ -94,32 +95,24 @@ fn decodable_substructure( decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| { cx.expr_try( span, - cx.expr_call_global( - span, - fn_read_struct_field_path.clone(), - thin_vec![ - blkdecoder.clone(), - cx.expr_str(span, name), - cx.expr_usize(span, field), - exprdecode.clone(), - ], - ), + cx.expr_call_global(span, fn_read_struct_field_path.clone(), thin_vec![ + blkdecoder.clone(), + cx.expr_str(span, name), + cx.expr_usize(span, field), + exprdecode.clone(), + ]), ) }); let result = cx.expr_ok(trait_span, result); let fn_read_struct_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct]); - cx.expr_call_global( - trait_span, - fn_read_struct_path, - thin_vec![ - decoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, nfields), - cx.lambda1(trait_span, result, blkarg), - ], - ) + cx.expr_call_global(trait_span, fn_read_struct_path, thin_vec![ + decoder, + cx.expr_str(trait_span, substr.type_ident.name), + cx.expr_usize(trait_span, nfields), + cx.lambda1(trait_span, result, blkarg), + ]) } StaticEnum(_, fields) => { let variant = Ident::new(sym::i, trait_span); @@ -160,23 +153,19 @@ fn decodable_substructure( let variant_array_ref = cx.expr_array_ref(trait_span, variants); let fn_read_enum_variant_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]); - let result = cx.expr_call_global( - trait_span, - fn_read_enum_variant_path, - thin_vec![blkdecoder, variant_array_ref, lambda], - ); + let result = cx.expr_call_global(trait_span, fn_read_enum_variant_path, thin_vec![ + blkdecoder, + variant_array_ref, + lambda + ]); let fn_read_enum_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]); - cx.expr_call_global( - trait_span, - fn_read_enum_path, - thin_vec![ - decoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.lambda1(trait_span, result, blkarg), - ], - ) + cx.expr_call_global(trait_span, fn_read_enum_path, thin_vec![ + decoder, + cx.expr_str(trait_span, substr.type_ident.name), + cx.lambda1(trait_span, result, blkarg), + ]) } _ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"), }; diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index afc55ddd2302e..652e6f7740f9f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -2,12 +2,12 @@ use core::ops::ControlFlow; use rustc_ast as ast; use rustc_ast::visit::visit_opt; -use rustc_ast::{attr, EnumDef, VariantData}; +use rustc_ast::{EnumDef, VariantData, attr}; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{ErrorGuaranteed, Span}; use smallvec::SmallVec; -use thin_vec::{thin_vec, ThinVec}; +use thin_vec::{ThinVec, thin_vec}; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; @@ -93,10 +93,10 @@ fn default_enum_substructure( } { Ok(default_variant) => { // We now know there is exactly one unit variant with exactly one `#[default]` attribute. - cx.expr_path(cx.path( - default_variant.span, - vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], - )) + cx.expr_path(cx.path(default_variant.span, vec![ + Ident::new(kw::SelfUpper, default_variant.span), + default_variant.ident, + ])) } Err(guar) => DummyResult::raw_expr(trait_span, Some(guar)), }; diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 9c26d05f811d1..5c7583f2a77d8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -87,9 +87,9 @@ use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, Symbol, sym}; +use thin_vec::{ThinVec, thin_vec}; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; @@ -116,10 +116,11 @@ pub(crate) fn expand_deriving_rustc_encodable( methods: vec![MethodDef { name: sym::encode, generics: Bounds { - bounds: vec![( - typaram, - vec![Path::new_(vec![krate, sym::Encoder], vec![], PathKind::Global)], - )], + bounds: vec![(typaram, vec![Path::new_( + vec![krate, sym::Encoder], + vec![], + PathKind::Global, + )])], }, explicit_self: true, nonself_args: vec![( @@ -157,14 +158,11 @@ fn encodable_substructure( // throw an underscore in front to suppress unused variable warnings let blkarg = Ident::new(sym::_e, trait_span); let blkencoder = cx.expr_ident(trait_span, blkarg); - let fn_path = cx.expr_path(cx.path_global( - trait_span, - vec![ - Ident::new(krate, trait_span), - Ident::new(sym::Encodable, trait_span), - Ident::new(sym::encode, trait_span), - ], - )); + let fn_path = cx.expr_path(cx.path_global(trait_span, vec![ + Ident::new(krate, trait_span), + Ident::new(sym::Encodable, trait_span), + Ident::new(sym::encode, trait_span), + ])); match substr.fields { Struct(_, fields) => { @@ -180,16 +178,12 @@ fn encodable_substructure( let enc = cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda1(span, enc, blkarg); - let call = cx.expr_call_global( - span, - fn_emit_struct_field_path.clone(), - thin_vec![ - blkencoder.clone(), - cx.expr_str(span, name), - cx.expr_usize(span, i), - lambda, - ], - ); + let call = cx.expr_call_global(span, fn_emit_struct_field_path.clone(), thin_vec![ + blkencoder.clone(), + cx.expr_str(span, name), + cx.expr_usize(span, i), + lambda, + ]); // last call doesn't need a try! let last = fields.len() - 1; @@ -214,16 +208,12 @@ fn encodable_substructure( let fn_emit_struct_path = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]); - let expr = cx.expr_call_global( - trait_span, - fn_emit_struct_path, - thin_vec![ - encoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, fields.len()), - blk, - ], - ); + let expr = cx.expr_call_global(trait_span, fn_emit_struct_path, thin_vec![ + encoder, + cx.expr_str(trait_span, substr.type_ident.name), + cx.expr_usize(trait_span, fields.len()), + blk, + ]); BlockOrExpr::new_expr(expr) } @@ -243,11 +233,8 @@ fn encodable_substructure( let last = fields.len() - 1; for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() { let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = cx.expr_call( - span, - fn_path.clone(), - thin_vec![self_ref, blkencoder.clone()], - ); + let enc = cx + .expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_call_global( @@ -274,26 +261,22 @@ fn encodable_substructure( let fn_emit_enum_variant_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]); - let call = cx.expr_call_global( - trait_span, - fn_emit_enum_variant_path, - thin_vec![ - blkencoder, - name, - cx.expr_usize(trait_span, *idx), - cx.expr_usize(trait_span, fields.len()), - blk, - ], - ); + let call = cx.expr_call_global(trait_span, fn_emit_enum_variant_path, thin_vec![ + blkencoder, + name, + cx.expr_usize(trait_span, *idx), + cx.expr_usize(trait_span, fields.len()), + blk, + ]); let blk = cx.lambda1(trait_span, call, blkarg); let fn_emit_enum_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]); - let expr = cx.expr_call_global( - trait_span, - fn_emit_enum_path, - thin_vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk], - ); + let expr = cx.expr_call_global(trait_span, fn_emit_enum_path, thin_vec![ + encoder, + cx.expr_str(trait_span, substr.type_ident.name), + blk + ]); BlockOrExpr::new_mixed(thin_vec![me], Some(expr)) } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 289e92a69b2c0..82baaca9a4641 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -178,6 +178,8 @@ use std::cell::RefCell; use std::ops::Not; use std::{iter, vec}; +pub(crate) use StaticFields::*; +pub(crate) use SubstructureFields::*; use rustc_ast::ptr::P; use rustc_ast::{ self as ast, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, @@ -185,12 +187,10 @@ use rustc_ast::{ }; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Span}; +use thin_vec::{ThinVec, thin_vec}; use ty::{Bounds, Path, Ref, Self_, Ty}; -pub(crate) use StaticFields::*; -pub(crate) use SubstructureFields::*; use crate::{deriving, errors}; @@ -1228,12 +1228,10 @@ impl<'a> MethodDef<'a> { let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args) .map(|(&ident, selflike_arg)| { - let variant_value = deriving::call_intrinsic( - cx, - span, - sym::discriminant_value, - thin_vec![selflike_arg.clone()], - ); + let variant_value = + deriving::call_intrinsic(cx, span, sym::discriminant_value, thin_vec![ + selflike_arg.clone() + ]); cx.stmt_let(span, false, ident, variant_value) }) .collect(); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 42855e255a806..b118cbfbd913b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -1,14 +1,14 @@ //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use //! when specifying impls to be derived. +pub(crate) use Ty::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind}; use rustc_expand::base::ExtCtxt; use rustc_span::source_map::respan; -use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::{DUMMY_SP, Span}; use thin_vec::ThinVec; -pub(crate) use Ty::*; /// A path, e.g., `::std::option::Option::` (global). Has support /// for type parameters. diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 4fa6686b7b34b..2d1f5b70f7746 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -1,7 +1,7 @@ use rustc_ast::{MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use thin_vec::thin_vec; use crate::deriving::generic::ty::*; diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 32936ac183df9..d5ee5e430d5d0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -4,9 +4,9 @@ use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::{GenericArg, MetaItem}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Symbol, sym}; +use thin_vec::{ThinVec, thin_vec}; macro path_local($x:ident) { generic::ty::Path::new_local(sym::$x) diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index bc41d33a609e3..12749e87dcbcc 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -1,5 +1,5 @@ -use ast::ptr::P; use ast::HasAttrs; +use ast::ptr::P; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::visit::BoundKind; use rustc_ast::{ @@ -9,9 +9,9 @@ use rustc_ast::{ use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{Ident, sym}; use rustc_span::{Span, Symbol}; -use thin_vec::{thin_vec, ThinVec}; +use thin_vec::{ThinVec, thin_vec}; macro_rules! path { ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index cc385bade4703..c4164a7db9a47 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -3,9 +3,9 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::*; use rustc_expand::base::*; +use rustc_span::Span; use rustc_span::edition::Edition; use rustc_span::symbol::sym; -use rustc_span::Span; /// This expands to either /// - `$crate::panic::panic_2015!(...)` or diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 1a4fc65f0a8a6..25583cda5a20d 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -10,8 +10,8 @@ use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; use thin_vec::thin_vec; use crate::errors; @@ -58,11 +58,11 @@ pub(crate) fn expand_option_env<'cx>( ))], )) } - Some(value) => cx.expr_call_global( - sp, - cx.std_path(&[sym::option, sym::Option, sym::Some]), - thin_vec![cx.expr_str(sp, value)], - ), + Some(value) => { + cx.expr_call_global(sp, cx.std_path(&[sym::option, sym::Option, sym::Some]), thin_vec![ + cx.expr_str(sp, value) + ]) + } }; ExpandResult::Ready(MacEager::expr(e)) } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index f99530cad18f9..9501e93bad534 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -2,9 +2,10 @@ use parse::Position::ArgumentNamed; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ - token, Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, + Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount, FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, Recovered, StmtKind, + token, }; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 866ec72f11646..71320e6d5ad37 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -183,14 +183,10 @@ pub(crate) mod printf { s.push('{'); if let Some(arg) = self.parameter { - match write!( - s, - "{}", - match arg.checked_sub(1) { - Some(a) => a, - None => return Err(None), - } - ) { + match write!(s, "{}", match arg.checked_sub(1) { + Some(a) => a, + None => return Err(None), + }) { Err(_) => return Err(None), _ => {} } diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs index df773910dbc8f..8fe06df48e5ec 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs @@ -1,4 +1,4 @@ -use super::{iter_subs, parse_next_substitution as pns, Format as F, Num as N, Substitution as S}; +use super::{Format as F, Num as N, Substitution as S, iter_subs, parse_next_substitution as pns}; macro_rules! assert_eq_pnsat { ($lhs:expr, $rhs:expr) => { @@ -99,10 +99,12 @@ fn test_parse() { fn test_iter() { let s = "The %d'th word %% is: `%.*s` %!\n"; let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); - assert_eq!( - subs.iter().map(Option::as_deref).collect::>(), - vec![Some("{}"), None, Some("{:.*}"), None] - ); + assert_eq!(subs.iter().map(Option::as_deref).collect::>(), vec![ + Some("{}"), + None, + Some("{:.*}"), + None + ]); } /// Checks that the translations are what we expect. diff --git a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs index 93a7afcd6e8b6..dd2ee2b6ca9a9 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs @@ -1,4 +1,4 @@ -use super::{parse_next_substitution as pns, Substitution as S}; +use super::{Substitution as S, parse_next_substitution as pns}; macro_rules! assert_eq_pnsat { ($lhs:expr, $rhs:expr) => { @@ -38,10 +38,11 @@ fn test_iter() { use super::iter_subs; let s = "The $0'th word $$ is: `$WORD` $!\n"; let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); - assert_eq!( - subs.iter().map(Option::as_deref).collect::>(), - vec![Some("{0}"), None, Some("{WORD}")] - ); + assert_eq!(subs.iter().map(Option::as_deref).collect::>(), vec![ + Some("{0}"), + None, + Some("{WORD}") + ]); } #[test] diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 734da318ac1bb..b4b18409a18eb 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -1,5 +1,5 @@ use rustc_ast::expand::allocator::{ - global_fn_name, AllocatorMethod, AllocatorMethodInput, AllocatorTy, ALLOCATOR_METHODS, + ALLOCATOR_METHODS, AllocatorMethod, AllocatorMethodInput, AllocatorTy, global_fn_name, }; use rustc_ast::ptr::P; use rustc_ast::{ @@ -7,9 +7,9 @@ use rustc_ast::{ Stmt, StmtKind, Ty, TyKind, }; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use thin_vec::{ThinVec, thin_vec}; use crate::errors; use crate::util::check_builtin_macro_attribute; @@ -65,7 +65,7 @@ struct AllocFnFactory<'a, 'b> { span: Span, ty_span: Span, global: Ident, - cx: &'b ExtCtxt<'a>, + cx: &'a ExtCtxt<'b>, } impl AllocFnFactory<'_, '_> { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 30e1c8d262216..ebe5e2b544292 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -94,6 +94,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { line: source_util::expand_line, log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, + naked_asm: asm::expand_naked_asm, option_env: env::expand_option_env, pattern_type: pattern_type::expand, std_panic: edition_panic::expand_panic, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 869d203f68eba..90b5f097b32b3 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,9 +1,9 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ast, Pat, Ty}; +use rustc_ast::{Pat, Ty, ast}; use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub(crate) fn expand<'cx>( cx: &'cx mut ExtCtxt<'_>, diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 6b2b2b90457c5..d6603af101afc 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -2,19 +2,19 @@ use std::mem; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, attr, NodeId}; +use rustc_ast::{self as ast, NodeId, attr}; use rustc_ast_pretty::pprust; use rustc_errors::DiagCtxtHandle; -use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand}; +use rustc_expand::base::{ExtCtxt, ResolverExpand, parse_macro_name_and_helper_attrs}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; use rustc_session::Session; use rustc_span::hygiene::AstPass; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Span}; use smallvec::smallvec; -use thin_vec::{thin_vec, ThinVec}; +use thin_vec::{ThinVec, thin_vec}; use crate::errors; @@ -302,29 +302,25 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { }; let local_path = |cx: &ExtCtxt<'_>, name| cx.expr_path(cx.path(span, vec![name])); let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| { - cx.expr_path(cx.path( - span.with_ctxt(harness_span.ctxt()), - vec![proc_macro, bridge, client, proc_macro_ty, method], - )) + cx.expr_path(cx.path(span.with_ctxt(harness_span.ctxt()), vec![ + proc_macro, + bridge, + client, + proc_macro_ty, + method, + ])) }; match m { ProcMacro::Derive(cd) => { cx.resolver.declare_proc_macro(cd.id); - cx.expr_call( - span, - proc_macro_ty_method_path(cx, custom_derive), - thin_vec![ - cx.expr_str(span, cd.trait_name), - cx.expr_array_ref( - span, - cd.attrs - .iter() - .map(|&s| cx.expr_str(span, s)) - .collect::>(), - ), - local_path(cx, cd.function_name), - ], - ) + cx.expr_call(span, proc_macro_ty_method_path(cx, custom_derive), thin_vec![ + cx.expr_str(span, cd.trait_name), + cx.expr_array_ref( + span, + cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::>(), + ), + local_path(cx, cd.function_name), + ]) } ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => { cx.resolver.declare_proc_macro(ca.id); @@ -334,14 +330,10 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { ProcMacro::Derive(_) => unreachable!(), }; - cx.expr_call( - span, - proc_macro_ty_method_path(cx, ident), - thin_vec![ - cx.expr_str(span, ca.function_name.name), - local_path(cx, ca.function_name), - ], - ) + cx.expr_call(span, proc_macro_ty_method_path(cx, ident), thin_vec![ + cx.expr_str(span, ca.function_name.name), + local_path(cx, ca.function_name), + ]) } } }) @@ -355,9 +347,12 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { span, cx.ty( span, - ast::TyKind::Slice( - cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), - ), + ast::TyKind::Slice(cx.ty_path(cx.path(span, vec![ + proc_macro, + bridge, + client, + proc_macro_ty, + ]))), ), None, ast::Mutability::Not, diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 9554d97829e21..946fbe918e6a6 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -8,7 +8,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_expand::base::{ - resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, + DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path, }; use rustc_expand::module::DirOwnership; use rustc_lint_defs::BuiltinLintDiag; @@ -73,8 +73,8 @@ pub(crate) fn expand_file( let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); - use rustc_session::config::RemapPathScopeComponents; use rustc_session::RemapFileNameExt; + use rustc_session::config::RemapPathScopeComponents; ExpandResult::Ready(MacEager::expr(cx.expr_str( topmost, Symbol::intern( diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 9bcd793c45041..a3fc53344ab14 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -3,10 +3,10 @@ use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::ExpansionConfig; use rustc_feature::Features; use rustc_session::Session; +use rustc_span::DUMMY_SP; use rustc_span::edition::Edition::*; use rustc_span::hygiene::AstPass; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::DUMMY_SP; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; use thin_vec::thin_vec; pub fn inject( diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 1b76a5f3234a2..664e935ee14a3 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -5,13 +5,13 @@ use std::assert_matches::assert_matches; use std::iter; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, attr, GenericParamKind}; +use rustc_ast::{self as ast, GenericParamKind, attr}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, Level}; use rustc_expand::base::*; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{Ident, Symbol, sym}; use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span}; -use thin_vec::{thin_vec, ThinVec}; +use thin_vec::{ThinVec, thin_vec}; use tracing::debug; use crate::errors; @@ -170,26 +170,20 @@ pub(crate) fn expand_test_or_bench( // creates test::ShouldPanic::$name let should_panic_path = |name| { - cx.path( - sp, - vec![ - test_id, - Ident::from_str_and_span("ShouldPanic", sp), - Ident::from_str_and_span(name, sp), - ], - ) + cx.path(sp, vec![ + test_id, + Ident::from_str_and_span("ShouldPanic", sp), + Ident::from_str_and_span(name, sp), + ]) }; // creates test::TestType::$name let test_type_path = |name| { - cx.path( - sp, - vec![ - test_id, - Ident::from_str_and_span("TestType", sp), - Ident::from_str_and_span(name, sp), - ], - ) + cx.path(sp, vec![ + test_id, + Ident::from_str_and_span("TestType", sp), + Ident::from_str_and_span(name, sp), + ]) }; // creates $name: $expr @@ -209,55 +203,39 @@ pub(crate) fn expand_test_or_bench( // A simple ident for a lambda let b = Ident::from_str_and_span("b", attr_sp); - cx.expr_call( - sp, - cx.expr_path(test_path("StaticBenchFn")), - thin_vec![ - // #[coverage(off)] - // |b| self::test::assert_test_result( - coverage_off(cx.lambda1( - sp, + cx.expr_call(sp, cx.expr_path(test_path("StaticBenchFn")), thin_vec![ + // #[coverage(off)] + // |b| self::test::assert_test_result( + coverage_off(cx.lambda1( + sp, + cx.expr_call(sp, cx.expr_path(test_path("assert_test_result")), thin_vec![ + // super::$test_fn(b) cx.expr_call( - sp, - cx.expr_path(test_path("assert_test_result")), - thin_vec![ - // super::$test_fn(b) - cx.expr_call( - ret_ty_sp, - cx.expr_path(cx.path(sp, vec![item.ident])), - thin_vec![cx.expr_ident(sp, b)], - ), - ], + ret_ty_sp, + cx.expr_path(cx.path(sp, vec![item.ident])), + thin_vec![cx.expr_ident(sp, b)], ), - b, - )), // ) - ], - ) + ],), + b, + )), // ) + ]) } else { - cx.expr_call( - sp, - cx.expr_path(test_path("StaticTestFn")), - thin_vec![ - // #[coverage(off)] - // || { - coverage_off(cx.lambda0( - sp, - // test::assert_test_result( + cx.expr_call(sp, cx.expr_path(test_path("StaticTestFn")), thin_vec![ + // #[coverage(off)] + // || { + coverage_off(cx.lambda0( + sp, + // test::assert_test_result( + cx.expr_call(sp, cx.expr_path(test_path("assert_test_result")), thin_vec![ + // $test_fn() cx.expr_call( - sp, - cx.expr_path(test_path("assert_test_result")), - thin_vec![ - // $test_fn() - cx.expr_call( - ret_ty_sp, - cx.expr_path(cx.path(sp, vec![item.ident])), - ThinVec::new(), - ), // ) - ], - ), // } - )), // ) - ], - ) + ret_ty_sp, + cx.expr_path(cx.path(sp, vec![item.ident])), + ThinVec::new(), + ), // ) + ],), // } + )), // ) + ]) }; let test_path_symbol = Symbol::intern(&item_path( @@ -268,120 +246,107 @@ pub(crate) fn expand_test_or_bench( let location_info = get_location_info(cx, &item); - let mut test_const = - cx.item( - sp, - Ident::new(item.ident.name, sp), - thin_vec![ - // #[cfg(test)] - cx.attr_nested_word(sym::cfg, sym::test, attr_sp), - // #[rustc_test_marker = "test_case_sort_key"] - cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), - ], - // const $ident: test::TestDescAndFn = - ast::ItemKind::Const( - ast::ConstItem { - defaultness: ast::Defaultness::Final, - generics: ast::Generics::default(), - ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), - // test::TestDescAndFn { - expr: Some( - cx.expr_struct( - sp, - test_path("TestDescAndFn"), - thin_vec![ + let mut test_const = cx.item( + sp, + Ident::new(item.ident.name, sp), + thin_vec![ + // #[cfg(test)] + cx.attr_nested_word(sym::cfg, sym::test, attr_sp), + // #[rustc_test_marker = "test_case_sort_key"] + cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), + // #[doc(hidden)] + cx.attr_nested_word(sym::doc, sym::hidden, attr_sp), + ], + // const $ident: test::TestDescAndFn = + ast::ItemKind::Const( + ast::ConstItem { + defaultness: ast::Defaultness::Final, + generics: ast::Generics::default(), + ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + // test::TestDescAndFn { + expr: Some( + cx.expr_struct(sp, test_path("TestDescAndFn"), thin_vec![ // desc: test::TestDesc { field( "desc", - cx.expr_struct( - sp, - test_path("TestDesc"), - thin_vec![ - // name: "path::to::test" - field( - "name", - cx.expr_call( - sp, - cx.expr_path(test_path("StaticTestName")), - thin_vec![cx.expr_str(sp, test_path_symbol)], - ), + cx.expr_struct(sp, test_path("TestDesc"), thin_vec![ + // name: "path::to::test" + field( + "name", + cx.expr_call( + sp, + cx.expr_path(test_path("StaticTestName")), + thin_vec![cx.expr_str(sp, test_path_symbol)], ), - // ignore: true | false - field("ignore", cx.expr_bool(sp, should_ignore(&item)),), - // ignore_message: Some("...") | None - field( - "ignore_message", - if let Some(msg) = should_ignore_message(&item) { - cx.expr_some(sp, cx.expr_str(sp, msg)) - } else { - cx.expr_none(sp) - }, + ), + // ignore: true | false + field("ignore", cx.expr_bool(sp, should_ignore(&item)),), + // ignore_message: Some("...") | None + field( + "ignore_message", + if let Some(msg) = should_ignore_message(&item) { + cx.expr_some(sp, cx.expr_str(sp, msg)) + } else { + cx.expr_none(sp) + }, + ), + // source_file: + field("source_file", cx.expr_str(sp, location_info.0)), + // start_line: start line of the test fn identifier. + field("start_line", cx.expr_usize(sp, location_info.1)), + // start_col: start column of the test fn identifier. + field("start_col", cx.expr_usize(sp, location_info.2)), + // end_line: end line of the test fn identifier. + field("end_line", cx.expr_usize(sp, location_info.3)), + // end_col: end column of the test fn identifier. + field("end_col", cx.expr_usize(sp, location_info.4)), + // compile_fail: true | false + field("compile_fail", cx.expr_bool(sp, false)), + // no_run: true | false + field("no_run", cx.expr_bool(sp, false)), + // should_panic: ... + field("should_panic", match should_panic(cx, &item) { + // test::ShouldPanic::No + ShouldPanic::No => { + cx.expr_path(should_panic_path("No")) + } + // test::ShouldPanic::Yes + ShouldPanic::Yes(None) => { + cx.expr_path(should_panic_path("Yes")) + } + // test::ShouldPanic::YesWithMessage("...") + ShouldPanic::Yes(Some(sym)) => cx.expr_call( + sp, + cx.expr_path(should_panic_path("YesWithMessage")), + thin_vec![cx.expr_str(sp, sym)], ), - // source_file: - field("source_file", cx.expr_str(sp, location_info.0)), - // start_line: start line of the test fn identifier. - field("start_line", cx.expr_usize(sp, location_info.1)), - // start_col: start column of the test fn identifier. - field("start_col", cx.expr_usize(sp, location_info.2)), - // end_line: end line of the test fn identifier. - field("end_line", cx.expr_usize(sp, location_info.3)), - // end_col: end column of the test fn identifier. - field("end_col", cx.expr_usize(sp, location_info.4)), - // compile_fail: true | false - field("compile_fail", cx.expr_bool(sp, false)), - // no_run: true | false - field("no_run", cx.expr_bool(sp, false)), - // should_panic: ... - field( - "should_panic", - match should_panic(cx, &item) { - // test::ShouldPanic::No - ShouldPanic::No => { - cx.expr_path(should_panic_path("No")) - } - // test::ShouldPanic::Yes - ShouldPanic::Yes(None) => { - cx.expr_path(should_panic_path("Yes")) - } - // test::ShouldPanic::YesWithMessage("...") - ShouldPanic::Yes(Some(sym)) => cx.expr_call( - sp, - cx.expr_path(should_panic_path("YesWithMessage")), - thin_vec![cx.expr_str(sp, sym)], - ), - }, - ), - // test_type: ... - field( - "test_type", - match test_type(cx) { - // test::TestType::UnitTest - TestType::UnitTest => { - cx.expr_path(test_type_path("UnitTest")) - } - // test::TestType::IntegrationTest - TestType::IntegrationTest => { - cx.expr_path(test_type_path("IntegrationTest")) - } - // test::TestPath::Unknown - TestType::Unknown => { - cx.expr_path(test_type_path("Unknown")) - } - }, - ), - // }, - ], - ), + },), + // test_type: ... + field("test_type", match test_type(cx) { + // test::TestType::UnitTest + TestType::UnitTest => { + cx.expr_path(test_type_path("UnitTest")) + } + // test::TestType::IntegrationTest + TestType::IntegrationTest => { + cx.expr_path(test_type_path("IntegrationTest")) + } + // test::TestPath::Unknown + TestType::Unknown => { + cx.expr_path(test_type_path("Unknown")) + } + },), + // }, + ],), ), // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) field("testfn", test_fn), // } - ], - ), // } - ), - } - .into(), - ), - ); + ]), // } + ), + } + .into(), + ), + ); test_const = test_const.map(|mut tc| { tc.vis.kind = ast::VisibilityKind::Public; tc diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index a9e4434581163..953484533087c 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -6,21 +6,21 @@ use rustc_ast as ast; use rustc_ast::entry::EntryPointType; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_ast::visit::{walk_item, Visitor}; -use rustc_ast::{attr, ModKind}; +use rustc_ast::visit::{Visitor, walk_item}; +use rustc_ast::{ModKind, attr}; use rustc_errors::DiagCtxtHandle; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; use rustc_lint_defs::BuiltinLintDiag; -use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS; use rustc_session::Session; +use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS; use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::PanicStrategy; -use smallvec::{smallvec, SmallVec}; -use thin_vec::{thin_vec, ThinVec}; +use smallvec::{SmallVec, smallvec}; +use thin_vec::{ThinVec, thin_vec}; use tracing::debug; use crate::errors; @@ -326,6 +326,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { let main_attr = ecx.attr_word(sym::rustc_main, sp); // #[coverage(off)] let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp); + // #[doc(hidden)] + let doc_hidden_attr = ecx.attr_nested_word(sym::doc, sym::hidden, sp); // pub fn main() { ... } let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new())); @@ -355,7 +357,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { let main = P(ast::Item { ident: main_id, - attrs: thin_vec![main_attr, coverage_attr], + attrs: thin_vec![main_attr, coverage_attr, doc_hidden_attr], id: ast::DUMMY_NODE_ID, kind: main, vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None }, diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs index bd9ebc355e158..e624d1da66bd5 100644 --- a/compiler/rustc_builtin_macros/src/trace_macros.rs +++ b/compiler/rustc_builtin_macros/src/trace_macros.rs @@ -1,7 +1,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; use crate::errors; diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 0bcd5aef28bab..d7b03a43ecb0d 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,12 +1,12 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{self as ast, attr, token, AttrStyle, Attribute, MetaItem}; +use rustc_ast::{self as ast, AttrStyle, Attribute, MetaItem, attr, token}; use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt}; use rustc_expand::expand::AstFragment; use rustc_feature::AttributeTemplate; -use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; use rustc_lint_defs::BuiltinLintDiag; +use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; use rustc_parse::{parser, validate_attr}; use rustc_session::errors::report_lit_error; use rustc_span::{BytePos, Span, Symbol}; diff --git a/compiler/rustc_codegen_cranelift/.cirrus.yml b/compiler/rustc_codegen_cranelift/.cirrus.yml index 5a464bfac3644..1ec99eb3d17a5 100644 --- a/compiler/rustc_codegen_cranelift/.cirrus.yml +++ b/compiler/rustc_codegen_cranelift/.cirrus.yml @@ -3,7 +3,7 @@ task: freebsd_instance: image: freebsd-13-2-release-amd64 setup_rust_script: - - pkg install -y git bash binutils + - pkg install -y git-tiny binutils - curl https://sh.rustup.rs -sSf --output rustup.sh - sh rustup.sh --default-toolchain none -y --profile=minimal target_cache: diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 896a5c34c3eff..2ee94146c1a4e 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -279,8 +279,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 if: ${{ github.ref == 'refs/heads/master' }} - # FIXME add the bench job back to the dependency list once rust-lang/rust#125493 gets merged - needs: [rustfmt, test, dist] + needs: [rustfmt, test, bench, dist] permissions: contents: write # for creating the dev tag and release diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 02d4d98dc4212..1c2ca95b075ca 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -46,24 +46,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effa84ab2023f7138045ece6b326588c17447ca22e66db71ec15cb0a6c0c4ad2" +checksum = "b80c3a50b9c4c7e5b5f73c0ed746687774fc9e36ef652b110da8daebf0c6e0e6" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a1dfc50dca188a15d938867c4400589530bcb0138f7022aae6d059d1d8c309" +checksum = "38778758c2ca918b05acb2199134e0c561fb577c50574259b26190b6c2d95ded" [[package]] name = "cranelift-codegen" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "821c20c639350158ecca928dc2a244d0d1c9cef2377a378fc62a445a286eb1ca" +checksum = "58258667ad10e468bfc13a8d620f50dfcd4bb35d668123e97defa2549b9ad397" dependencies = [ "bumpalo", "cranelift-bforest", @@ -84,42 +84,42 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064473f2fd59b44fa2c9aaa60de1f9c44db5e13521e28bc85d2b92ee535ef625" +checksum = "043f0b702e529dcb07ff92bd7d40e7d5317b5493595172c5eb0983343751ee06" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f39b9ebfd2febdc2acfb9a0fca110665bcd5a6839502576307735ed07b2177" +checksum = "7763578888ab53eca5ce7da141953f828e82c2bfadcffc106d10d1866094ffbb" [[package]] name = "cranelift-control" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e125c189c3a1ca8dfe209fc6f46edba058a6d24e0b92aff69459a15f4711e7" +checksum = "32db15f08c05df570f11e8ab33cb1ec449a64b37c8a3498377b77650bef33d8b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea62eb109baec2247e1a6fa7b74c0f584b1e76e289cfd7017385b4b031fc8450" +checksum = "5289cdb399381a27e7bbfa1b42185916007c3d49aeef70b1d01cb4caa8010130" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722b089357aacb6c7528b2e59a5fe00917d61ce63448b25a3e477a5b7819fac8" +checksum = "31ba8ab24eb9470477e98ddfa3c799a649ac5a0d9a2042868c4c952133c234e8" dependencies = [ "cranelift-codegen", "log", @@ -129,15 +129,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b5005a48288e7fc2a2991a377831c534e26929b063c379c018060727785a9b" +checksum = "2b72a3c5c166a70426dcb209bdd0bb71a787c1ea76023dc0974fbabca770e8f9" [[package]] name = "cranelift-jit" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f843932baf8d1025c5f114b929eda172d74b7163d058e0de2597c308b567c7e9" +checksum = "df32578a47582e49b4fc1f9a5786839d9be1fedaa9f00bea7612c54425663c6b" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449819ef1c4af139cf1b9717916fcaea0e23248853d3e95135139773a842d3eb" +checksum = "96094a758cdb543c9143f70817cd31069fecd49f50981a0fac06820ac011dc2f" dependencies = [ "anyhow", "cranelift-codegen", @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae2d48f38081a9e679ad795bd36bb29bedeb5552fc1c195185bf9885fa1b16e" +checksum = "46a42424c956bbc31fc5c2706073df896156c5420ae8fa2a5d48dbc7b295d71b" dependencies = [ "cranelift-codegen", "libc", @@ -177,9 +177,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a39ee2cfd0ec485eca76f6b4dc17701a280fa406bc05137bb43f1635ed12c9f" +checksum = "1cf5e2484ab47fe38a3150747cdd2016535f13542a925acca152b63383a6591b" dependencies = [ "anyhow", "cranelift-codegen", @@ -213,9 +213,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" dependencies = [ "fallible-iterator", "indexmap", @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.15" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "unicode-ident" @@ -421,9 +421,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "23.0.1" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fddf3e2980fb1d123d1fcac55189e417fdd3dba4f62139b5a0a1f9efe5669d5" +checksum = "d15de8429db996f0d17a4163a35eccc3f874cbfb50f29c379951ea1bbb39452e" dependencies = [ "anyhow", "cfg-if", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index a0df502dadc47..6594ffb5d66bd 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,14 +8,14 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.110.1", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.110.1" } -cranelift-module = { version = "0.110.1" } -cranelift-native = { version = "0.110.1" } -cranelift-jit = { version = "0.110.1", optional = true } -cranelift-object = { version = "0.110.1" } +cranelift-codegen = { version = "0.111.0", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.111.0" } +cranelift-module = { version = "0.111.0" } +cranelift-native = { version = "0.111.0" } +cranelift-jit = { version = "0.111.0", optional = true } +cranelift-object = { version = "0.111.0" } target-lexicon = "0.12.0" -gimli = { version = "0.28", default-features = false, features = ["write"]} +gimli = { version = "0.29", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index 6766e2f844d6d..18a840f8a50e0 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -70,7 +70,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system |AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| |Other unixes|❓|❓|❓|❓| |macOS|✅|✅|N/A|N/A| -|Windows|✅[^no-rustup]|❌|N/A|N/A| +|Windows|✅|❌|N/A|N/A| ✅: Fully supported and tested ❓: Maybe supported, not tested diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs index e3f1162445b33..9292778806a2e 100644 --- a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs +++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs @@ -1,7 +1,7 @@ use crate::path::{Dirs, RelPath}; use crate::prepare::GitRepo; -use crate::utils::{spawn_and_wait, CargoProject, Compiler}; -use crate::{build_sysroot, CodegenBackend, SysrootKind}; +use crate::utils::{CargoProject, Compiler, spawn_and_wait}; +use crate::{CodegenBackend, SysrootKind, build_sysroot}; static ABI_CAFE_REPO: GitRepo = GitRepo::github( "Gankra", @@ -14,7 +14,6 @@ static ABI_CAFE_REPO: GitRepo = GitRepo::github( static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe_target"); pub(crate) fn run( - channel: &str, sysroot_kind: SysrootKind, dirs: &Dirs, cg_clif_dylib: &CodegenBackend, @@ -28,7 +27,6 @@ pub(crate) fn run( eprintln!("Building sysroot for abi-cafe"); build_sysroot::build_sysroot( dirs, - channel, sysroot_kind, cg_clif_dylib, bootstrap_host_compiler, @@ -38,12 +36,11 @@ pub(crate) fn run( eprintln!("Running abi-cafe"); - let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"]; - let pairs = + let pairs: &[_] = if cfg!(not(any(target_os = "macos", all(target_os = "windows", target_env = "msvc")))) { - &pairs[..] + &["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"] } else { - &pairs[..2] + &["rustc_calls_cgclif", "cgclif_calls_rustc"] }; let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs); diff --git a/compiler/rustc_codegen_cranelift/build_system/bench.rs b/compiler/rustc_codegen_cranelift/build_system/bench.rs index 6c64faaa2563e..ebeb67722507a 100644 --- a/compiler/rustc_codegen_cranelift/build_system/bench.rs +++ b/compiler/rustc_codegen_cranelift/build_system/bench.rs @@ -1,11 +1,12 @@ use std::env; use std::io::Write; use std::path::Path; +use std::process::Command; use crate::path::{Dirs, RelPath}; use crate::prepare::GitRepo; use crate::rustc_info::get_file_name; -use crate::utils::{hyperfine_command, spawn_and_wait, Compiler}; +use crate::utils::{Compiler, spawn_and_wait}; static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github( "ebobby", @@ -128,3 +129,37 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { gha_step_summary.write_all(b"\n").unwrap(); } } + +#[must_use] +fn hyperfine_command( + warmup: u64, + runs: u64, + prepare: Option<&str>, + cmds: &[(&str, &str)], + markdown_export: &Path, +) -> Command { + let mut bench = Command::new("hyperfine"); + + bench.arg("--export-markdown").arg(markdown_export); + + if warmup != 0 { + bench.arg("--warmup").arg(warmup.to_string()); + } + + if runs != 0 { + bench.arg("--runs").arg(runs.to_string()); + } + + if let Some(prepare) = prepare { + bench.arg("--prepare").arg(prepare); + } + + for &(name, cmd) in cmds { + if name != "" { + bench.arg("-n").arg(name); + } + bench.arg(cmd); + } + + bench +} diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index 129713e574ad0..02da89f737cf2 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -6,11 +6,10 @@ use crate::rustc_info::get_file_name; use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env}; use crate::utils::{CargoProject, Compiler, LogGroup}; -pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); +static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); pub(crate) fn build_backend( dirs: &Dirs, - channel: &str, bootstrap_host_compiler: &Compiler, use_unstable_features: bool, ) -> PathBuf { @@ -19,8 +18,8 @@ pub(crate) fn build_backend( let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); let mut rustflags = rustflags_from_env("RUSTFLAGS"); - rustflags.push("-Zallow-features=rustc_private".to_owned()); + rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); if env::var("CG_CLIF_EXPENSIVE_CHECKS").is_ok() { // Enabling debug assertions implicitly enables the clif ir verifier @@ -32,15 +31,7 @@ pub(crate) fn build_backend( cmd.arg("--features").arg("unstable-features"); } - match channel { - "debug" => {} - "release" => { - cmd.arg("--release"); - } - _ => unreachable!(), - } - - rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); + cmd.arg("--release"); eprintln!("[BUILD] rustc_codegen_cranelift"); crate::utils::spawn_and_wait(cmd); @@ -48,6 +39,6 @@ pub(crate) fn build_backend( CG_CLIF .target_dir(dirs) .join(&bootstrap_host_compiler.triple) - .join(channel) + .join("release") .join(get_file_name(&bootstrap_host_compiler.rustc, "rustc_codegen_cranelift", "dylib")) } diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index e41f6c5e709e2..82558999aface 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -3,19 +3,15 @@ use std::process::Command; use std::{env, fs}; use crate::path::{Dirs, RelPath}; -use crate::rustc_info::get_file_name; +use crate::prepare::apply_patches; +use crate::rustc_info::{get_default_sysroot, get_file_name}; use crate::utils::{ - remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler, LogGroup, + CargoProject, Compiler, LogGroup, ensure_empty_dir, spawn_and_wait, try_hard_link, }; -use crate::{config, CodegenBackend, SysrootKind}; - -static DIST_DIR: RelPath = RelPath::DIST; -static BIN_DIR: RelPath = RelPath::DIST.join("bin"); -static LIB_DIR: RelPath = RelPath::DIST.join("lib"); +use crate::{CodegenBackend, SysrootKind, config}; pub(crate) fn build_sysroot( dirs: &Dirs, - channel: &str, sysroot_kind: SysrootKind, cg_clif_dylib_src: &CodegenBackend, bootstrap_host_compiler: &Compiler, @@ -26,9 +22,11 @@ pub(crate) fn build_sysroot( eprintln!("[BUILD] sysroot {:?}", sysroot_kind); - DIST_DIR.ensure_fresh(dirs); - BIN_DIR.ensure_exists(dirs); - LIB_DIR.ensure_exists(dirs); + let dist_dir = RelPath::DIST.to_path(dirs); + + ensure_empty_dir(&dist_dir); + fs::create_dir_all(dist_dir.join("bin")).unwrap(); + fs::create_dir_all(dist_dir.join("lib")).unwrap(); let is_native = bootstrap_host_compiler.triple == target_triple; @@ -38,11 +36,10 @@ pub(crate) fn build_sysroot( let cg_clif_dylib_path = if cfg!(windows) { // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the // binaries. - BIN_DIR + dist_dir.join("bin") } else { - LIB_DIR + dist_dir.join("lib") } - .to_path(dirs) .join(src_path.file_name().unwrap()); try_hard_link(src_path, &cg_clif_dylib_path); CodegenBackend::Local(cg_clif_dylib_path) @@ -56,7 +53,7 @@ pub(crate) fn build_sysroot( let wrapper_name = wrapper_base_name.replace("____", wrapper); let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc); - let wrapper_path = DIST_DIR.to_path(dirs).join(&wrapper_name); + let wrapper_path = dist_dir.join(&wrapper_name); build_cargo_wrapper_cmd .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs"))) .arg("-o") @@ -79,22 +76,20 @@ pub(crate) fn build_sysroot( build_cargo_wrapper_cmd.env("BUILTIN_BACKEND", name); } spawn_and_wait(build_cargo_wrapper_cmd); - try_hard_link(wrapper_path, BIN_DIR.to_path(dirs).join(wrapper_name)); + try_hard_link(wrapper_path, dist_dir.join("bin").join(wrapper_name)); } let host = build_sysroot_for_triple( dirs, - channel, bootstrap_host_compiler.clone(), &cg_clif_dylib_path, sysroot_kind, ); - host.install_into_sysroot(&DIST_DIR.to_path(dirs)); + host.install_into_sysroot(&dist_dir); if !is_native { build_sysroot_for_triple( dirs, - channel, { let mut bootstrap_target_compiler = bootstrap_host_compiler.clone(); bootstrap_target_compiler.triple = target_triple.clone(); @@ -104,7 +99,7 @@ pub(crate) fn build_sysroot( &cg_clif_dylib_path, sysroot_kind, ) - .install_into_sysroot(&DIST_DIR.to_path(dirs)); + .install_into_sysroot(&dist_dir); } // Copy std for the host to the lib dir. This is necessary for the jit mode to find @@ -112,16 +107,13 @@ pub(crate) fn build_sysroot( for lib in host.libs { let filename = lib.file_name().unwrap().to_str().unwrap(); if filename.contains("std-") && !filename.contains(".rlib") { - try_hard_link(&lib, LIB_DIR.to_path(dirs).join(lib.file_name().unwrap())); + try_hard_link(&lib, dist_dir.join("lib").join(lib.file_name().unwrap())); } } let mut target_compiler = { - let dirs: &Dirs = &dirs; - let rustc_clif = - RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustc-clif")); - let rustdoc_clif = - RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustdoc-clif")); + let rustc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustc-clif")); + let rustdoc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif")); Compiler { cargo: bootstrap_host_compiler.cargo.clone(), @@ -139,6 +131,7 @@ pub(crate) fn build_sysroot( target_compiler } +#[must_use] struct SysrootTarget { triple: String, libs: Vec, @@ -159,15 +152,13 @@ impl SysrootTarget { } } -pub(crate) static STDLIB_SRC: RelPath = RelPath::BUILD.join("stdlib"); -pub(crate) static STANDARD_LIBRARY: CargoProject = +static STDLIB_SRC: RelPath = RelPath::BUILD.join("stdlib"); +static STANDARD_LIBRARY: CargoProject = CargoProject::new(&STDLIB_SRC.join("library/sysroot"), "stdlib_target"); -pub(crate) static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup"); +static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup"); -#[must_use] fn build_sysroot_for_triple( dirs: &Dirs, - channel: &str, compiler: Compiler, cg_clif_dylib_path: &CodegenBackend, sysroot_kind: SysrootKind, @@ -176,13 +167,10 @@ fn build_sysroot_for_triple( SysrootKind::None => build_rtstartup(dirs, &compiler) .unwrap_or(SysrootTarget { triple: compiler.triple, libs: vec![] }), SysrootKind::Llvm => build_llvm_sysroot_for_triple(compiler), - SysrootKind::Clif => { - build_clif_sysroot_for_triple(dirs, channel, compiler, cg_clif_dylib_path) - } + SysrootKind::Clif => build_clif_sysroot_for_triple(dirs, compiler, cg_clif_dylib_path), } } -#[must_use] fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { let default_sysroot = crate::rustc_info::get_default_sysroot(&compiler.rustc); @@ -216,10 +204,8 @@ fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { target_libs } -#[must_use] fn build_clif_sysroot_for_triple( dirs: &Dirs, - channel: &str, mut compiler: Compiler, cg_clif_dylib_path: &CodegenBackend, ) -> SysrootTarget { @@ -231,12 +217,12 @@ fn build_clif_sysroot_for_triple( target_libs.libs.extend(rtstartup_target_libs.libs); } - let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join(channel); + let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join("release"); if !config::get_bool("keep_sysroot") { // Cleanup the deps dir, but keep build scripts and the incremental cache for faster // recompilation as they are not affected by changes in cg_clif. - remove_dir_if_exists(&build_dir.join("deps")); + ensure_empty_dir(&build_dir.join("deps")); } // Build sysroot @@ -252,12 +238,12 @@ fn build_clif_sysroot_for_triple( // Necessary for MinGW to find rsbegin.o and rsend.o rustflags.push("--sysroot".to_owned()); rustflags.push(RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap().to_owned()); - if channel == "release" { - // Incremental compilation by default disables mir inlining. This leads to both a decent - // compile perf and a significant runtime perf regression. As such forcefully enable mir - // inlining. - rustflags.push("-Zinline-mir".to_owned()); - } + + // Incremental compilation by default disables mir inlining. This leads to both a decent + // compile perf and a significant runtime perf regression. As such forcefully enable mir + // inlining. + rustflags.push("-Zinline-mir".to_owned()); + if let Some(prefix) = env::var_os("CG_CLIF_STDLIB_REMAP_PATH_PREFIX") { rustflags.push("--remap-path-prefix".to_owned()); rustflags.push(format!( @@ -268,9 +254,7 @@ fn build_clif_sysroot_for_triple( } compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); - if channel == "release" { - build_cmd.arg("--release"); - } + build_cmd.arg("--release"); build_cmd.arg("--features").arg("backtrace panic-unwind compiler-builtins-no-f16-f128"); build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true"); build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif"); @@ -296,7 +280,10 @@ fn build_clif_sysroot_for_triple( fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option { if !config::get_bool("keep_sysroot") { - crate::prepare::prepare_stdlib(dirs, &compiler.rustc); + let sysroot_src_orig = get_default_sysroot(&compiler.rustc).join("lib/rustlib/src/rust"); + assert!(sysroot_src_orig.exists()); + + apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs)); } if !compiler.triple.ends_with("windows-gnu") { diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs index 9ddeda583afd1..b68ac7c09267e 100644 --- a/compiler/rustc_codegen_cranelift/build_system/main.rs +++ b/compiler/rustc_codegen_cranelift/build_system/main.rs @@ -81,7 +81,6 @@ fn main() { let mut out_dir = PathBuf::from("."); let mut download_dir = None; - let mut channel = "release"; let mut sysroot_kind = SysrootKind::Clif; let mut use_unstable_features = true; let mut frozen = false; @@ -99,7 +98,6 @@ fn main() { arg_error!("--download-dir requires argument"); }))); } - "--debug" => channel = "debug", "--sysroot" => { sysroot_kind = match args.next().as_deref() { Some("none") => SysrootKind::None, @@ -206,7 +204,6 @@ fn main() { } else { CodegenBackend::Local(build_backend::build_backend( &dirs, - channel, &bootstrap_host_compiler, use_unstable_features, )) @@ -218,7 +215,6 @@ fn main() { Command::Test => { tests::run_tests( &dirs, - channel, sysroot_kind, use_unstable_features, &skip_tests.iter().map(|test| &**test).collect::>(), @@ -234,7 +230,6 @@ fn main() { process::exit(1); } abi_cafe::run( - channel, sysroot_kind, &dirs, &cg_clif_dylib, @@ -245,7 +240,6 @@ fn main() { Command::Build => { build_sysroot::build_sysroot( &dirs, - channel, sysroot_kind, &cg_clif_dylib, &bootstrap_host_compiler, @@ -256,7 +250,6 @@ fn main() { Command::Bench => { build_sysroot::build_sysroot( &dirs, - channel, sysroot_kind, &cg_clif_dylib, &bootstrap_host_compiler, diff --git a/compiler/rustc_codegen_cranelift/build_system/path.rs b/compiler/rustc_codegen_cranelift/build_system/path.rs index 8572815fc55e4..35e7e81c5285d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/path.rs +++ b/compiler/rustc_codegen_cranelift/build_system/path.rs @@ -1,7 +1,7 @@ use std::fs; use std::path::PathBuf; -use crate::utils::remove_dir_if_exists; +use crate::utils::ensure_empty_dir; #[derive(Debug, Clone)] pub(crate) struct Dirs { @@ -64,7 +64,6 @@ impl RelPath { pub(crate) fn ensure_fresh(&self, dirs: &Dirs) { let path = self.to_path(dirs); - remove_dir_if_exists(&path); - fs::create_dir_all(path).unwrap(); + ensure_empty_dir(&path); } } diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index be0bed0f4e636..30bd7ae26a186 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -4,12 +4,8 @@ use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::Command; -use crate::build_sysroot::STDLIB_SRC; use crate::path::{Dirs, RelPath}; -use crate::rustc_info::get_default_sysroot; -use crate::utils::{ - copy_dir_recursively, git_command, remove_dir_if_exists, retry_spawn_and_wait, spawn_and_wait, -}; +use crate::utils::{copy_dir_recursively, ensure_empty_dir, spawn_and_wait}; pub(crate) fn prepare(dirs: &Dirs) { RelPath::DOWNLOAD.ensure_exists(dirs); @@ -17,13 +13,6 @@ pub(crate) fn prepare(dirs: &Dirs) { crate::tests::REGEX_REPO.fetch(dirs); } -pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) { - let sysroot_src_orig = get_default_sysroot(rustc).join("lib/rustlib/src/rust"); - assert!(sysroot_src_orig.exists()); - - apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs)); -} - pub(crate) struct GitRepo { url: GitRepoUrl, rev: &'static str, @@ -119,7 +108,11 @@ impl GitRepo { match self.url { GitRepoUrl::Github { user, repo } => { - clone_repo_shallow_github(dirs, &download_dir, user, repo, self.rev); + clone_repo( + &download_dir, + &format!("https://github.com/{}/{}.git", user, repo), + self.rev, + ); } } @@ -154,7 +147,6 @@ impl GitRepo { } } -#[allow(dead_code)] fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { eprintln!("[CLONE] {}", repo); // Ignore exit code as the repo may already have been checked out @@ -171,55 +163,6 @@ fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { std::fs::remove_dir_all(download_dir.join(".git")).unwrap(); } -fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: &str, rev: &str) { - if cfg!(windows) { - // Older windows doesn't have tar or curl by default. Fall back to using git. - clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev); - return; - } - - let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev); - let archive_file = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz", rev)); - let archive_dir = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}", repo, rev)); - - eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url); - - // Remove previous results if they exists - let _ = std::fs::remove_file(&archive_file); - let _ = std::fs::remove_dir_all(&archive_dir); - let _ = std::fs::remove_dir_all(&download_dir); - - // Download zip archive - let mut download_cmd = Command::new("curl"); - download_cmd - .arg("--max-time") - .arg("600") - .arg("-y") - .arg("30") - .arg("-Y") - .arg("10") - .arg("--connect-timeout") - .arg("30") - .arg("--continue-at") - .arg("-") - .arg("--location") - .arg("--output") - .arg(&archive_file) - .arg(archive_url); - retry_spawn_and_wait(5, download_cmd); - - // Unpack tar archive - let mut unpack_cmd = Command::new("tar"); - unpack_cmd.arg("xf").arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path(dirs)); - spawn_and_wait(unpack_cmd); - - // Rename unpacked dir to the expected name - std::fs::rename(archive_dir, &download_dir).unwrap(); - - // Cleanup - std::fs::remove_file(archive_file).unwrap(); -} - fn init_git_repo(repo_dir: &Path) { let mut git_init_cmd = git_command(repo_dir, "init"); git_init_cmd.arg("-q"); @@ -259,8 +202,7 @@ pub(crate) fn apply_patches(dirs: &Dirs, crate_name: &str, source_dir: &Path, ta eprintln!("[COPY] {crate_name} source"); - remove_dir_if_exists(target_dir); - fs::create_dir_all(target_dir).unwrap(); + ensure_empty_dir(target_dir); if crate_name == "stdlib" { fs::create_dir(target_dir.join("library")).unwrap(); copy_dir_recursively(&source_dir.join("library"), &target_dir.join("library")); @@ -285,3 +227,22 @@ pub(crate) fn apply_patches(dirs: &Dirs, crate_name: &str, source_dir: &Path, ta spawn_and_wait(apply_patch_cmd); } } + +#[must_use] +fn git_command<'a>(repo_dir: impl Into>, cmd: &str) -> Command { + let mut git_cmd = Command::new("git"); + git_cmd + .arg("-c") + .arg("user.name=Dummy") + .arg("-c") + .arg("user.email=dummy@example.com") + .arg("-c") + .arg("core.autocrlf=false") + .arg("-c") + .arg("commit.gpgSign=false") + .arg(cmd); + if let Some(repo_dir) = repo_dir.into() { + git_cmd.current_dir(repo_dir); + } + git_cmd +} diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index 38c3786a94a42..fd94e80f6312e 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -4,11 +4,11 @@ use std::path::PathBuf; use std::process::Command; use crate::path::{Dirs, RelPath}; -use crate::prepare::{apply_patches, GitRepo}; +use crate::prepare::{GitRepo, apply_patches}; use crate::rustc_info::get_default_sysroot; use crate::shared_utils::rustflags_from_env; -use crate::utils::{spawn_and_wait, CargoProject, Compiler, LogGroup}; -use crate::{build_sysroot, config, CodegenBackend, SysrootKind}; +use crate::utils::{CargoProject, Compiler, LogGroup, spawn_and_wait}; +use crate::{CodegenBackend, SysrootKind, build_sysroot, config}; static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example"); @@ -117,7 +117,7 @@ pub(crate) static RAND_REPO: GitRepo = GitRepo::github( "rand", ); -pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand_target"); +static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand_target"); pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "rust-lang", @@ -127,12 +127,11 @@ pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "regex", ); -pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); +static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); -pub(crate) static PORTABLE_SIMD_SRC: RelPath = RelPath::BUILD.join("coretests"); +static PORTABLE_SIMD_SRC: RelPath = RelPath::BUILD.join("portable-simd"); -pub(crate) static PORTABLE_SIMD: CargoProject = - CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); +static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); static LIBCORE_TESTS_SRC: RelPath = RelPath::BUILD.join("coretests"); @@ -230,13 +229,6 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ if runner.is_native { let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs); test_cmd.arg("-q"); - // FIXME remove after portable-simd update - test_cmd - .arg("--") - .arg("--skip") - .arg("core_simd::swizzle::simd_swizzle") - .arg("--skip") - .arg("core_simd::vector::Simd::lanes"); spawn_and_wait(test_cmd); } }), @@ -244,7 +236,6 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ pub(crate) fn run_tests( dirs: &Dirs, - channel: &str, sysroot_kind: SysrootKind, use_unstable_features: bool, skip_tests: &[&str], @@ -260,7 +251,6 @@ pub(crate) fn run_tests( if config::get_bool("testsuite.no_sysroot") && !skip_tests.contains(&"testsuite.no_sysroot") { let target_compiler = build_sysroot::build_sysroot( dirs, - channel, SysrootKind::None, cg_clif_dylib, bootstrap_host_compiler, @@ -291,7 +281,6 @@ pub(crate) fn run_tests( if run_base_sysroot || run_extended_sysroot { let target_compiler = build_sysroot::build_sysroot( dirs, - channel, sysroot_kind, cg_clif_dylib, bootstrap_host_compiler, @@ -443,7 +432,6 @@ impl<'a> TestRunner<'a> { cmd.arg("--target"); cmd.arg(&self.target_compiler.triple); cmd.arg("-Cpanic=abort"); - cmd.arg("-Zunstable-options"); cmd.arg("--check-cfg=cfg(jit)"); cmd.args(args); cmd @@ -458,26 +446,11 @@ impl<'a> TestRunner<'a> { } fn run_out_command(&self, name: &str, args: &[&str]) { - let mut full_cmd = vec![]; + let mut cmd = self + .target_compiler + .run_with_runner(BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name)); - // Prepend the RUN_WRAPPER's - if !self.target_compiler.runner.is_empty() { - full_cmd.extend(self.target_compiler.runner.iter().cloned()); - } - - full_cmd.push( - BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(), - ); - - for arg in args { - full_cmd.push(arg.to_string()); - } - - let mut cmd_iter = full_cmd.into_iter(); - let first = cmd_iter.next().unwrap(); - - let mut cmd = Command::new(first); - cmd.args(cmd_iter); + cmd.args(args); spawn_and_wait(cmd); } diff --git a/compiler/rustc_codegen_cranelift/build_system/usage.txt b/compiler/rustc_codegen_cranelift/build_system/usage.txt index f652599447bcf..5c333fe2db596 100644 --- a/compiler/rustc_codegen_cranelift/build_system/usage.txt +++ b/compiler/rustc_codegen_cranelift/build_system/usage.txt @@ -2,16 +2,12 @@ The build system of cg_clif. USAGE: ./y.sh prepare [--out-dir DIR] [--download-dir DIR] - ./y.sh build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] - ./y.sh test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME] - ./y.sh abi-cafe [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] - ./y.sh bench [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] + ./y.sh build [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] + ./y.sh test [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME] + ./y.sh abi-cafe [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] + ./y.sh bench [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] OPTIONS: - --debug - Build cg_clif and the standard library in debug mode rather than release mode. - Warning: An unoptimized cg_clif is very slow. - --sysroot none|clif|llvm Which sysroot libraries to use: `none` will not include any standard library in the sysroot. @@ -43,7 +39,5 @@ REQUIREMENTS: * Rustup: By default rustup is used to install the right nightly version. If you don't want to use rustup, you can manually install the nightly version indicated by rust-toolchain.toml and point the CARGO, RUSTC and RUSTDOC env vars to the right executables. - * Git: Git is used for applying patches and on Windows for downloading test repos. - * Curl and tar (non-Windows only): Used by `./y.sh prepare` to download a single commit for - repos. Git will be used to clone the whole repo when using Windows. + * Git: Git is used for downloading test repos and applying patches. * [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.sh bench`. diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs index 3c4b45e02cc25..22a9487a202d6 100644 --- a/compiler/rustc_codegen_cranelift/build_system/utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs @@ -1,3 +1,4 @@ +use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::process::{self, Command}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -59,6 +60,18 @@ impl Compiler { } } } + + pub(crate) fn run_with_runner(&self, program: impl AsRef) -> Command { + if self.runner.is_empty() { + Command::new(program) + } else { + let mut runner_iter = self.runner.iter(); + let mut cmd = Command::new(runner_iter.next().unwrap()); + cmd.args(runner_iter); + cmd.arg(program); + cmd + } + } } pub(crate) struct CargoProject { @@ -141,59 +154,6 @@ impl CargoProject { } } -#[must_use] -pub(crate) fn hyperfine_command( - warmup: u64, - runs: u64, - prepare: Option<&str>, - cmds: &[(&str, &str)], - markdown_export: &Path, -) -> Command { - let mut bench = Command::new("hyperfine"); - - bench.arg("--export-markdown").arg(markdown_export); - - if warmup != 0 { - bench.arg("--warmup").arg(warmup.to_string()); - } - - if runs != 0 { - bench.arg("--runs").arg(runs.to_string()); - } - - if let Some(prepare) = prepare { - bench.arg("--prepare").arg(prepare); - } - - for &(name, cmd) in cmds { - if name != "" { - bench.arg("-n").arg(name); - } - bench.arg(cmd); - } - - bench -} - -#[must_use] -pub(crate) fn git_command<'a>(repo_dir: impl Into>, cmd: &str) -> Command { - let mut git_cmd = Command::new("git"); - git_cmd - .arg("-c") - .arg("user.name=Dummy") - .arg("-c") - .arg("user.email=dummy@example.com") - .arg("-c") - .arg("core.autocrlf=false") - .arg("-c") - .arg("commit.gpgSign=false") - .arg(cmd); - if let Some(repo_dir) = repo_dir.into() { - git_cmd.current_dir(repo_dir); - } - git_cmd -} - #[track_caller] pub(crate) fn try_hard_link(src: impl AsRef, dst: impl AsRef) { let src = src.as_ref(); @@ -212,27 +172,33 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) { } } -// Based on the retry function in rust's src/ci/shared.sh -#[track_caller] -pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) { - for i in 1..tries + 1 { - if i != 1 { - eprintln!("Command failed. Attempt {i}/{tries}:"); - } - if cmd.spawn().unwrap().wait().unwrap().success() { +/// Create the specified directory if it doesn't exist yet and delete all contents. +pub(crate) fn ensure_empty_dir(path: &Path) { + fs::create_dir_all(path).unwrap(); + let read_dir = match fs::read_dir(&path) { + Ok(read_dir) => read_dir, + Err(err) if err.kind() == io::ErrorKind::NotFound => { return; } - std::thread::sleep(std::time::Duration::from_secs(i * 5)); - } - eprintln!("The command has failed after {tries} attempts."); - process::exit(1); -} - -pub(crate) fn remove_dir_if_exists(path: &Path) { - match fs::remove_dir_all(&path) { - Ok(()) => {} - Err(err) if err.kind() == io::ErrorKind::NotFound => {} - Err(err) => panic!("Failed to remove {path}: {err}", path = path.display()), + Err(err) => { + panic!("Failed to read contents of {path}: {err}", path = path.display()) + } + }; + for entry in read_dir { + let entry = entry.unwrap(); + if entry.file_type().unwrap().is_dir() { + match fs::remove_dir_all(entry.path()) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::NotFound => {} + Err(err) => panic!("Failed to remove {path}: {err}", path = entry.path().display()), + } + } else { + match fs::remove_file(entry.path()) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::NotFound => {} + Err(err) => panic!("Failed to remove {path}: {err}", path = entry.path().display()), + } + } } } diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index 19405a53d1c65..4dbd9dac94a89 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -1,9 +1,10 @@ -#!/usr/bin/env bash +#!/bin/sh set -e -rm -rf target/ build_system/target download/ build/ dist/ y.bin y.bin.dSYM y.exe y.pdb +rm -rf target/ build_system/target download/ build/ dist/ # Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh # FIXME remove at some point in the future +rm y.bin y.bin.dSYM y.exe y.pdb 2>/dev/null || true rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/ rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} diff --git a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs index c54574d801d3a..ad46e18c11c0d 100644 --- a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs +++ b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs @@ -9,13 +9,13 @@ #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); +struct f32x4(pub [f32; 4]); use std::intrinsics::simd::*; fn main() { - let x = f32x4(1.0, 2.0, 3.0, 4.0); - let y = f32x4(2.0, 1.0, 4.0, 3.0); + let x = f32x4([1.0, 2.0, 3.0, 4.0]); + let y = f32x4([2.0, 1.0, 4.0, 3.0]); #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] let nan = f32::NAN; @@ -24,13 +24,13 @@ fn main() { #[cfg(any(target_arch = "mips", target_arch = "mips64"))] let nan = f32::from_bits(f32::NAN.to_bits() - 1); - let n = f32x4(nan, nan, nan, nan); + let n = f32x4([nan, nan, nan, nan]); unsafe { let min0 = simd_fmin(x, y); let min1 = simd_fmin(y, x); assert_eq!(min0, min1); - let e = f32x4(1.0, 1.0, 3.0, 3.0); + let e = f32x4([1.0, 1.0, 3.0, 3.0]); assert_eq!(min0, e); let minn = simd_fmin(x, n); assert_eq!(minn, x); @@ -40,7 +40,7 @@ fn main() { let max0 = simd_fmax(x, y); let max1 = simd_fmax(y, x); assert_eq!(max0, max1); - let e = f32x4(2.0, 2.0, 4.0, 4.0); + let e = f32x4([2.0, 2.0, 4.0, 4.0]); assert_eq!(max0, e); let maxn = simd_fmax(x, n); assert_eq!(maxn, x); diff --git a/compiler/rustc_codegen_cranelift/example/neon.rs b/compiler/rustc_codegen_cranelift/example/neon.rs index 00e437d7e546a..69ce17d3d752a 100644 --- a/compiler/rustc_codegen_cranelift/example/neon.rs +++ b/compiler/rustc_codegen_cranelift/example/neon.rs @@ -202,6 +202,44 @@ unsafe fn test_vqadd_u8() { assert_eq!(r, e); } +#[cfg(target_arch = "aarch64")] +unsafe fn test_vmaxq_f32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.fmax.v4f32 + let a = f32x4::from([0., -1., 2., -3.]); + let b = f32x4::from([-4., 5., -6., 7.]); + let e = f32x4::from([0., 5., 2., 7.]); + let r: f32x4 = transmute(vmaxq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vminq_f32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.fmin.v4f32 + let a = f32x4::from([0., -1., 2., -3.]); + let b = f32x4::from([-4., 5., -6., 7.]); + let e = f32x4::from([-4., -1., -6., -3.]); + let r: f32x4 = transmute(vminq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vaddvq_f32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.faddv.f32.v4f32 + let a = f32x4::from([0., 1., 2., 3.]); + let e = 6f32; + let r = vaddvq_f32(transmute(a)); + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vrndnq_f32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.frintn.v4f32 + let a = f32x4::from([0.1, -1.9, 4.5, 5.5]); + let e = f32x4::from([0., -2., 4., 6.]); + let r: f32x4 = transmute(vrndnq_f32(transmute(a))); + assert_eq!(r, e); +} + #[cfg(target_arch = "aarch64")] fn main() { unsafe { @@ -229,6 +267,11 @@ fn main() { test_vqsub_u8(); test_vqadd_u8(); + + test_vmaxq_f32(); + test_vminq_f32(); + test_vaddvq_f32(); + test_vrndnq_f32(); } } diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index e99763e272233..ebaa9c69c810a 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -166,7 +166,7 @@ fn main() { enum Never {} } - foo(I64X2(0, 0)); + foo(I64X2([0, 0])); transmute_fat_pointer(); @@ -204,7 +204,7 @@ fn rust_call_abi() { } #[repr(simd)] -struct I64X2(i64, i64); +struct I64X2([i64; 2]); #[allow(improper_ctypes_definitions)] extern "C" fn foo(_a: I64X2) {} @@ -238,10 +238,9 @@ unsafe fn test_simd() { let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x); assert_eq!((zero0, zero1), (0, 0)); assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]); - assert_eq!( - std::mem::transmute::<_, [u16; 8]>(cmp_eq), - [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff] - ); + assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [ + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff + ]); assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]); test_mm_slli_si128(); @@ -259,6 +258,9 @@ unsafe fn test_simd() { test_mm_insert_epi16(); test_mm_shuffle_epi8(); + #[cfg(not(jit))] + test_mm_cmpestri(); + test_mm256_shuffle_epi8(); test_mm256_permute2x128_si256(); test_mm256_permutevar8x32_epi32(); @@ -430,6 +432,31 @@ unsafe fn test_mm_shuffle_epi8() { assert_eq_m128i(r, expected); } +// Currently one cannot `load` a &[u8] that is less than 16 +// in length. This makes loading strings less than 16 in length +// a bit difficult. Rather than `load` and mutate the __m128i, +// it is easier to memcpy the given string to a local slice with +// length 16 and `load` the local slice. +#[cfg(not(jit))] +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse4.2")] +unsafe fn str_to_m128i(s: &[u8]) -> __m128i { + assert!(s.len() <= 16); + let slice = &mut [0u8; 16]; + std::ptr::copy_nonoverlapping(s.as_ptr(), slice.as_mut_ptr(), s.len()); + _mm_loadu_si128(slice.as_ptr() as *const _) +} + +#[cfg(not(jit))] +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse4.2")] +unsafe fn test_mm_cmpestri() { + let a = str_to_m128i(b"bar - garbage"); + let b = str_to_m128i(b"foobar"); + let i = _mm_cmpestri::<_SIDD_CMP_EQUAL_ORDERED>(a, 3, b, 6); + assert_eq!(3, i); +} + #[cfg(target_arch = "x86_64")] #[target_feature(enable = "avx2")] unsafe fn test_mm256_shuffle_epi8() { diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch new file mode 100644 index 0000000000000..b1fd6224632be --- /dev/null +++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch @@ -0,0 +1,26 @@ +From 5489384bc265e9e6fc2efaa63d93a4d51ebec2f5 Mon Sep 17 00:00:00 2001 +From: bjorn3 <17426603+bjorn3@users.noreply.github.com> +Date: Thu, 22 Aug 2024 19:22:58 +0000 +Subject: [PATCH] Disable broken reduce_sum test + +It was broken by an upstream change to the .sum() implementation on +float iterators. +--- + crates/core_simd/tests/ops_macros.rs | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs +index aa565a1..5e6ac41 100644 +--- a/crates/core_simd/tests/ops_macros.rs ++++ b/crates/core_simd/tests/ops_macros.rs +@@ -646,6 +646,7 @@ macro_rules! impl_float_tests { + } + + fn reduce_sum() { ++ return; + test_helpers::test_1(&|x| { + test_helpers::prop_assert_biteq! ( + Vector::::from_array(x).reduce_sum(), +-- +2.34.1 + diff --git a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch index 8c404956bcc20..5117b04fd3447 100644 --- a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch @@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644 @@ -1,3 +1,4 @@ +#![cfg(test)] // tidy-alphabetical-start - #![cfg_attr(bootstrap, feature(offset_of_nested))] + #![cfg_attr(bootstrap, feature(const_mut_refs))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] -- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch index d579c9588f08a..efd721d9df885 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch @@ -14,14 +14,13 @@ diff --git a/lib.rs b/lib.rs index 1e336bf..35e6f54 100644 --- a/lib.rs +++ b/lib.rs -@@ -1,7 +1,6 @@ +@@ -1,6 +1,5 @@ #![cfg(test)] // tidy-alphabetical-start - #![cfg_attr(bootstrap, feature(offset_of_nested))] + #![cfg_attr(bootstrap, feature(const_mut_refs))] -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(alloc_layout_extra)] - #![feature(array_chunks)] diff --git a/atomic.rs b/atomic.rs index b735957..ea728b6 100644 --- a/atomic.rs diff --git a/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch b/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch index 440177018f428..d7204add7a788 100644 --- a/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch @@ -43,6 +43,26 @@ index 8402833..84592e0 100644 #[test] fn test_slice_from_ptr_range() { +diff --git a/lazy.rs b/lazy.rs +index 711511e..49c8d78 100644 +--- a/lazy.rs ++++ b/lazy.rs +@@ -113,6 +113,7 @@ fn lazy_type_inference() { + let _ = LazyCell::new(|| ()); + } + ++/* + #[test] + #[should_panic = "LazyCell instance has previously been poisoned"] + fn lazy_force_mut_panic() { +@@ -123,6 +124,7 @@ fn lazy_force_mut_panic() { + .unwrap_err(); + let _ = &*lazy; + } ++*/ + + #[test] + fn lazy_force_mut() { -- 2.26.2.7.g19db9cfb68 diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 96c467e091cff..651770be3775d 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-08-09" +channel = "nightly-2024-09-23" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 684a5d0729355..2f13b0b9cb834 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -25,6 +25,9 @@ git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \ cat > config.toml <) { + + let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js"); + +- if mode == "run-make" { +- let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host }); +- cmd.arg("--cargo-path").arg(cargo); +- } +- + // Avoid depending on rustdoc when we don't need it. + if mode == "rustdoc" + || mode == "run-make" +diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs +index 414f9f3a7f1..5c18179b6fe 100644 +--- a/src/tools/compiletest/src/common.rs ++++ b/src/tools/compiletest/src/common.rs +@@ -183,9 +183,6 @@ pub struct Config { + /// The rustc executable. + pub rustc_path: PathBuf, + +- /// The cargo executable. +- pub cargo_path: Option, +- + /// The rustdoc executable. + pub rustdoc_path: Option, + +diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs +index 3339116d542..250b5084d13 100644 +--- a/src/tools/compiletest/src/lib.rs ++++ b/src/tools/compiletest/src/lib.rs +@@ -47,7 +47,6 @@ pub fn parse_config(args: Vec) -> Config { + opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") + .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") + .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") +- .optopt("", "cargo-path", "path to cargo to use for compiling", "PATH") + .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") + .optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH") + .reqopt("", "python", "path to python to use for doc tests", "PATH") +@@ -261,7 +260,6 @@ fn make_absolute(path: PathBuf) -> PathBuf { + compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), + run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), + rustc_path: opt_path(matches, "rustc-path"), +- cargo_path: matches.opt_str("cargo-path").map(PathBuf::from), + rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), + coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), + python: matches.opt_str("python").unwrap(), +@@ -366,7 +364,6 @@ pub fn log_config(config: &Config) { + logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); + logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); + logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); +- logv(c, format!("cargo_path: {:?}", config.cargo_path)); + logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); + logv(c, format!("src_base: {:?}", config.src_base.display())); + logv(c, format!("build_base: {:?}", config.build_base.display())); +diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs +index 75fe6a6baaf..852568ae925 100644 +--- a/src/tools/compiletest/src/runtest/run_make.rs ++++ b/src/tools/compiletest/src/runtest/run_make.rs +@@ -61,10 +61,6 @@ fn run_rmake_legacy_test(&self) { + .env_remove("MFLAGS") + .env_remove("CARGO_MAKEFLAGS"); + +- if let Some(ref cargo) = self.config.cargo_path { +- cmd.env("CARGO", cwd.join(cargo)); +- } +- + if let Some(ref rustdoc) = self.config.rustdoc_path { + cmd.env("RUSTDOC", cwd.join(rustdoc)); + } +@@ -413,10 +409,6 @@ fn run_rmake_v2_test(&self) { + // through a specific CI runner). + .env("LLVM_COMPONENTS", &self.config.llvm_components); + +- if let Some(ref cargo) = self.config.cargo_path { +- cmd.env("CARGO", source_root.join(cargo)); +- } +- + if let Some(ref rustdoc) = self.config.rustdoc_path { + cmd.env("RUSTDOC", source_root.join(rustdoc)); + } EOF echo "[TEST] rustc test suite" diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 24cf3f061a567..892ec3e95855e 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -13,9 +13,9 @@ use cranelift_module::ModuleError; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::TypeVisitableExt; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_target::abi::call::{Conv, FnAbi, PassMode}; @@ -61,6 +61,9 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call Conv::CCmseNonSecureCall => { sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented"); } + Conv::CCmseNonSecureEntry => { + sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented"); + } Conv::Msp430Intr | Conv::PtxKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); @@ -505,7 +508,10 @@ pub(crate) fn codegen_terminator_call<'tcx>( let nop_inst = fx.bcx.ins().nop(); fx.add_comment( nop_inst, - format!("virtual call; self arg pass mode: {:?}", fn_abi.args[0]), + with_no_trimmed_paths!(format!( + "virtual call; self arg pass mode: {:?}", + fn_abi.args[0] + )), ); } diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 0652267002910..38c322b5e0450 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -4,7 +4,7 @@ use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose}; use rustc_target::abi::call::{ ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind, }; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use crate::prelude::*; use crate::value_and_place::assert_assignable; diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index e0f399e616e5d..a294c789b220d 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -1,7 +1,7 @@ //! Return value handling use rustc_target::abi::call::{ArgAbi, PassMode}; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use crate::prelude::*; diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index b4a3825e9965f..5e33b9d606fa5 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -2,8 +2,8 @@ // Adapted from rustc use rustc_ast::expand::allocator::{ - alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy, - ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, + ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, + alloc_error_handler_name, default_fn_name, global_fn_name, }; use rustc_codegen_ssa::base::allocator_kind_for_codegen; use rustc_session::config::OomStrategy; diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 4af4b39cc5b9e..1ce0aacab4998 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -1,17 +1,17 @@ //! Codegen of a single function -use cranelift_codegen::ir::UserFuncName; use cranelift_codegen::CodegenError; +use cranelift_codegen::ir::UserFuncName; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_module::ModuleError; use rustc_ast::InlineAsmOptions; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::TypeVisitableExt; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; @@ -652,7 +652,7 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, res); } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer), + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _), ref operand, to_ty, ) => { @@ -677,7 +677,7 @@ fn codegen_stmt<'tcx>( } } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer), + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _), ref operand, to_ty, ) => { @@ -688,6 +688,7 @@ fn codegen_stmt<'tcx>( Rvalue::Cast( CastKind::PointerCoercion( PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, + _, ), .., ) => { @@ -741,7 +742,7 @@ fn codegen_stmt<'tcx>( } } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), + CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _), ref operand, _to_ty, ) => { @@ -763,14 +764,18 @@ fn codegen_stmt<'tcx>( } } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize), + CastKind::PointerCoercion(PointerCoercion::Unsize, _), ref operand, _to_ty, ) => { let operand = codegen_operand(fx, operand); crate::unsize::coerce_unsized_into(fx, operand, lval); } - Rvalue::Cast(CastKind::DynStar, ref operand, _) => { + Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::DynStar, _), + ref operand, + _, + ) => { let operand = codegen_operand(fx, operand); crate::unsize::coerce_dyn_star(fx, operand, lval); } @@ -785,8 +790,10 @@ fn codegen_stmt<'tcx>( } Rvalue::Repeat(ref operand, times) => { let operand = codegen_operand(fx, operand); - let times = - fx.monomorphize(times).eval_target_usize(fx.tcx, ParamEnv::reveal_all()); + let times = fx + .monomorphize(times) + .try_to_target_usize(fx.tcx) + .expect("expected monomorphic const in codegen"); if operand.layout().size.bytes() == 0 { // Do nothing for ZST's } else if fx.clif_type(operand.layout().ty) == Some(types::I8) { @@ -944,7 +951,10 @@ fn codegen_stmt<'tcx>( fn codegen_array_len<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx>) -> Value { match *place.layout().ty.kind() { ty::Array(_elem_ty, len) => { - let len = fx.monomorphize(len).eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64; + let len = fx + .monomorphize(len) + .try_to_target_usize(fx.tcx) + .expect("expected monomorphic const in codegen") as i64; fx.bcx.ins().iconst(fx.pointer_type, len) } ty::Slice(_elem_ty) => place.to_ptr_unsized().1, diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index b9000a3874f5d..e78ba5a341531 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -1,10 +1,10 @@ use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_index::IndexVec; +use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, }; -use rustc_middle::ty::TypeFoldable; use rustc_span::source_map::Spanned; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Float, Integer, Primitive}; @@ -309,8 +309,6 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { } impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { - type LayoutOfResult = TyAndLayout<'tcx>; - #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty) @@ -318,8 +316,6 @@ impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { } impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { - type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; - #[inline] fn handle_fn_abi_err( &self, @@ -450,8 +446,6 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { - type LayoutOfResult = TyAndLayout<'tcx>; - #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { @@ -466,8 +460,6 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { } impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { - type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; - #[inline] fn handle_fn_abi_err( &self, diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 0ba163f50aec5..ab78584332a05 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -5,7 +5,7 @@ use std::cmp::Ordering; use cranelift_module::*; use rustc_data_structures::fx::FxHashSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::interpret::{read_target_uint, AllocId, GlobalAlloc, Scalar}; +use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint}; use rustc_middle::ty::{Binder, ExistentialTraitRef, ScalarInt}; use crate::prelude::*; @@ -161,13 +161,13 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } - GlobalAlloc::VTable(ty, trait_ref) => { + GlobalAlloc::VTable(ty, dyn_ty) => { let data_id = data_id_for_vtable( fx.tcx, &mut fx.constants_cx, fx.module, ty, - trait_ref, + dyn_ty.principal(), ); let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); @@ -456,8 +456,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(target_alloc) => { data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) } - GlobalAlloc::VTable(ty, trait_ref) => { - data_id_for_vtable(tcx, cx, module, ty, trait_ref) + GlobalAlloc::VTable(ty, dyn_ty) => { + data_id_for_vtable(tcx, cx, module, ty, dyn_ty.principal()) } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) @@ -490,6 +490,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } /// Used only for intrinsic implementations that need a compile-time constant +/// +/// All uses of this function are a bug inside stdarch. [`eval_mir_constant`] +/// should be used everywhere, but for some vendor intrinsics stdarch forgets +/// to wrap the immediate argument in `const {}`, necesitating this hack to get +/// the correct value at compile time instead. pub(crate) fn mir_operand_get_const_val<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, operand: &Operand<'tcx>, diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index 36af7d4450d04..ccdc347af660f 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -6,8 +6,8 @@ use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer} use gimli::{RunTimeEndian, SectionId}; use rustc_data_structures::fx::FxHashMap; -use super::object::WriteDebugInfo; use super::DebugContext; +use super::object::WriteDebugInfo; pub(super) fn address_for_func(func_id: FuncId) -> Address { let symbol = func_id.as_u32(); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 78b3d5a58f4a2..c3d9d635084d6 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -3,15 +3,15 @@ use std::ffi::OsStr; use std::path::{Component, Path}; -use cranelift_codegen::binemit::CodeOffset; use cranelift_codegen::MachSrcLoc; +use cranelift_codegen::binemit::CodeOffset; use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable}; use rustc_span::{ - hygiene, FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, + FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, hygiene, }; -use crate::debuginfo::emit::address_for_func; use crate::debuginfo::FunctionDebugContext; +use crate::debuginfo::emit::address_for_func; use crate::prelude::*; // OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`. diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs index 1c6e471cc870f..048a388731fb0 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs @@ -73,19 +73,16 @@ impl WriteDebugInfo for ObjectProduct { } }; self.object - .add_relocation( - from.0, - Relocation { - offset: u64::from(reloc.offset), - symbol, - flags: RelocationFlags::Generic { - kind: reloc.kind, - encoding: RelocationEncoding::Generic, - size: reloc.size * 8, - }, - addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, + .add_relocation(from.0, Relocation { + offset: u64::from(reloc.offset), + symbol, + flags: RelocationFlags::Generic { + kind: reloc.kind, + encoding: RelocationEncoding::Generic, + size: reloc.size * 8, }, - ) + addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, + }) .unwrap(); } } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs index 7baf0a3868d2c..a710701e72c4b 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; -use crate::{has_ptr_meta, DebugContext, RevealAllLayoutCx}; +use crate::{DebugContext, RevealAllLayoutCx, has_ptr_meta}; #[derive(Default)] pub(crate) struct TypeDebugContext<'tcx> { @@ -44,7 +44,7 @@ impl DebugContext { type_dbg, ty, *elem_ty, - len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()), + len.try_to_target_usize(tcx).expect("expected monomorphic const in codegen"), ), // ty::Slice(_) | ty::Str // ty::Dynamic diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index ac7dd0bd46329..9399230f292e0 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -1,11 +1,11 @@ //! Unwind info generation (`.eh_frame`) use cranelift_codegen::ir::Endianness; -use cranelift_codegen::isa::unwind::UnwindInfo; use cranelift_codegen::isa::TargetIsa; +use cranelift_codegen::isa::unwind::UnwindInfo; use cranelift_object::ObjectProduct; -use gimli::write::{CieId, EhFrame, FrameTable, Section}; use gimli::RunTimeEndian; +use gimli::write::{CieId, EhFrame, FrameTable, Section}; use super::emit::address_for_func; use super::object::WriteDebugInfo; diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index b6fee1bf24a78..419efa9060081 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -12,24 +12,24 @@ use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{ - errors as ssa_errors, CodegenResults, CompiledModule, CrateInfo, ModuleKind, + CodegenResults, CompiledModule, CrateInfo, ModuleKind, errors as ssa_errors, }; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{par_map, IntoDynSyncSend}; -use rustc_metadata::fs::copy_to_stdout; +use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_metadata::EncodedMetadata; +use rustc_metadata::fs::copy_to_stdout; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; -use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; use rustc_session::Session; +use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; +use crate::BackendConfig; use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::debuginfo::TypeDebugContext; use crate::global_asm::GlobalAsmConfig; use crate::prelude::*; use crate::unwind_module::UnwindModule; -use crate::BackendConfig; struct ModuleCodegenResult { module_regular: CompiledModule, diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 12e860f676d05..0d62a13b4724e 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use std::ffi::CString; use std::os::raw::{c_char, c_int}; -use std::sync::{mpsc, Mutex, OnceLock}; +use std::sync::{Mutex, OnceLock, mpsc}; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_jit::{JITBuilder, JITModule}; @@ -359,15 +359,11 @@ fn codegen_shim<'tcx>( let instance_ptr = Box::into_raw(Box::new(inst)); let jit_fn = module - .declare_function( - "__clif_jit_fn", - Linkage::Import, - &Signature { - call_conv: module.target_config().default_call_conv, - params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)], - returns: vec![AbiParam::new(pointer_type)], - }, - ) + .declare_function("__clif_jit_fn", Linkage::Import, &Signature { + call_conv: module.target_config().default_call_conv, + params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)], + returns: vec![AbiParam::new(pointer_type)], + }) .unwrap(); let context = cached_context; diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 16edec47e1029..41f1b30d10b59 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -869,15 +869,11 @@ fn call_inline_asm<'tcx>( let inline_asm_func = fx .module - .declare_function( - asm_name, - Linkage::Import, - &Signature { - call_conv: CallConv::SystemV, - params: vec![AbiParam::new(fx.pointer_type)], - returns: vec![], - }, - ) + .declare_function(asm_name, Linkage::Import, &Signature { + call_conv: CallConv::SystemV, + params: vec![AbiParam::new(fx.pointer_type)], + returns: vec![], + }) .unwrap(); let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, fx.bcx.func); if fx.clif_comments.enabled() { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index f0fb18608e072..39f6763d9f2cb 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -91,6 +91,44 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( ); } + _ if intrinsic.starts_with("llvm.aarch64.neon.fmax.v") => { + intrinsic_args!(fx, args => (x, y); intrinsic); + + simd_pair_for_each_lane( + fx, + x, + y, + ret, + &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| fx.bcx.ins().fmax(x_lane, y_lane), + ); + } + + _ if intrinsic.starts_with("llvm.aarch64.neon.fmin.v") => { + intrinsic_args!(fx, args => (x, y); intrinsic); + + simd_pair_for_each_lane( + fx, + x, + y, + ret, + &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| fx.bcx.ins().fmin(x_lane, y_lane), + ); + } + + _ if intrinsic.starts_with("llvm.aarch64.neon.faddv.f32.v") => { + intrinsic_args!(fx, args => (v); intrinsic); + + simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().fadd(a, b)); + } + + _ if intrinsic.starts_with("llvm.aarch64.neon.frintn.v") => { + intrinsic_args!(fx, args => (v); intrinsic); + + simd_for_each_lane(fx, v, ret, &|fx, _lane_ty, _res_lane_ty, lane| { + fx.bcx.ins().nearest(lane) + }); + } + _ if intrinsic.starts_with("llvm.aarch64.neon.smaxv.i") => { intrinsic_args!(fx, args => (v); intrinsic); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index cb003037c265f..c02d31844e032 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -3,7 +3,7 @@ use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_target::asm::*; -use crate::inline_asm::{codegen_inline_asm_inner, CInlineAsmOperand}; +use crate::inline_asm::{CInlineAsmOperand, codegen_inline_asm_inner}; use crate::intrinsics::*; use crate::prelude::*; diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 29deac6073035..19e5adc253854 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -19,11 +19,11 @@ mod simd; use cranelift_codegen::ir::AtomicRmwOp; use rustc_middle::ty; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::GenericArgsRef; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; pub(crate) use self::llvm::codegen_llvm_intrinsic_call; use crate::cast::clif_intcast; @@ -600,9 +600,11 @@ fn codegen_regular_intrinsic_call<'tcx>( sym::ptr_mask => { intrinsic_args!(fx, args => (ptr, mask); intrinsic); + let ptr_layout = ptr.layout(); let ptr = ptr.load_scalar(fx); let mask = mask.load_scalar(fx); - fx.bcx.ins().band(ptr, mask); + let res = fx.bcx.ins().band(ptr, mask); + ret.write_cvalue(fx, CValue::by_val(res, ptr_layout)); } sym::write_bytes | sym::volatile_set_memory => { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 604a88393fd95..cbe411d78d5fd 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -131,9 +131,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let idx = generic_args[2] .expect_const() - .eval(fx.tcx, ty::ParamEnv::reveal_all(), span) - .unwrap() - .1 + .try_to_valtree() + .expect("expected monomorphic const in codegen") .unwrap_branch(); assert_eq!(x.layout(), y.layout()); @@ -180,35 +179,20 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - // Make sure this is actually an array, since typeck only checks the length-suffixed - // version of this intrinsic. + // Make sure this is actually a SIMD vector. let idx_ty = fx.monomorphize(idx.node.ty(fx.mir, fx.tcx)); - let n: u16 = match idx_ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len - .try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all()) - .unwrap_or_else(|| { - span_bug!(span, "could not evaluate shuffle index array length") - }) - .try_into() - .unwrap(), - _ if idx_ty.is_simd() - && matches!( - idx_ty.simd_size_and_type(fx.tcx).1.kind(), - ty::Uint(ty::UintTy::U32) - ) => - { - idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap() - } - _ => { - fx.tcx.dcx().span_err( - span, - format!("simd_shuffle index must be an array of `u32`, got `{}`", idx_ty), - ); - // Prevent verifier error - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - return; - } + if !idx_ty.is_simd() + || !matches!(idx_ty.simd_size_and_type(fx.tcx).1.kind(), ty::Uint(ty::UintTy::U32)) + { + fx.tcx.dcx().span_err( + span, + format!("simd_shuffle index must be a SIMD vector of `u32`, got `{}`", idx_ty), + ); + // Prevent verifier error + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + return; }; + let n: u16 = idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap(); assert_eq!(x.layout(), y.layout()); let layout = x.layout(); @@ -283,10 +267,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let val = codegen_operand(fx, &val.node); // FIXME validate - let idx_const = if let Some(idx_const) = - crate::constant::mir_operand_get_const_val(fx, &idx.node) - { - idx_const + let idx_const = if let Some(idx_const) = idx.node.constant() { + crate::constant::eval_mir_constant(fx, idx_const).0.try_to_scalar_int().unwrap() } else { fx.tcx.dcx().span_fatal(span, "Index argument for `simd_insert` is not a constant"); }; @@ -319,22 +301,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - let idx_const = if let Some(idx_const) = - crate::constant::mir_operand_get_const_val(fx, &idx.node) - { - idx_const + let idx_const = if let Some(idx_const) = idx.node.constant() { + crate::constant::eval_mir_constant(fx, idx_const).0.try_to_scalar_int().unwrap() } else { - fx.tcx.dcx().span_warn(span, "Index argument for `simd_extract` is not a constant"); - let trap_block = fx.bcx.create_block(); - let true_ = fx.bcx.ins().iconst(types::I8, 1); - let ret_block = fx.get_block(target); - fx.bcx.ins().brif(true_, trap_block, &[], ret_block, &[]); - fx.bcx.switch_to_block(trap_block); - crate::trap::trap_unimplemented( - fx, - "Index argument for `simd_extract` is not a constant", - ); - return; + fx.tcx + .dcx() + .span_fatal(span, "Index argument for `simd_extract` is not a constant"); }; let idx = idx_const.to_u32(); @@ -589,12 +561,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( (sym::simd_round, types::F64) => "round", _ => unreachable!("{:?}", intrinsic), }; - fx.lib_call( - name, - vec![AbiParam::new(lane_ty)], - vec![AbiParam::new(lane_ty)], - &[lane], - )[0] + fx.lib_call(name, vec![AbiParam::new(lane_ty)], vec![AbiParam::new(lane_ty)], &[ + lane, + ])[0] }); } diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index f737af25b62ee..f6b7981395a5f 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -38,15 +38,15 @@ use std::sync::Arc; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; -use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; +use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::ErrorGuaranteed; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_span::{sym, Symbol}; +use rustc_session::config::OutputFilenames; +use rustc_span::{Symbol, sym}; pub use crate::config::*; use crate::prelude::*; @@ -83,13 +83,13 @@ mod value_and_place; mod vtable; mod prelude { + pub(crate) use cranelift_codegen::Context; pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC}; pub(crate) use cranelift_codegen::ir::function::Function; pub(crate) use cranelift_codegen::ir::{ - types, AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, - StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value, + AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot, + StackSlotData, StackSlotKind, TrapCode, Type, Value, types, }; - pub(crate) use cranelift_codegen::Context; pub(crate) use cranelift_module::{self, DataDescription, FuncId, Linkage, Module}; pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -100,7 +100,7 @@ mod prelude { self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; - pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; + pub(crate) use rustc_target::abi::{Abi, FIRST_VARIANT, FieldIdx, Scalar, Size, VariantIdx}; pub(crate) use crate::abi::*; pub(crate) use crate::base::{codegen_operand, codegen_place}; diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index ba20a750d2b35..df92bc58bf53d 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,9 +1,9 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_hir::LangItem; use rustc_middle::ty::{AssocKind, GenericArg}; -use rustc_session::config::{sigpipe, EntryFnType}; -use rustc_span::symbol::Ident; +use rustc_session::config::{EntryFnType, sigpipe}; use rustc_span::DUMMY_SP; +use rustc_span::symbol::Ident; use crate::prelude::*; @@ -16,13 +16,10 @@ pub(crate) fn maybe_create_entry_wrapper( is_primary_cgu: bool, ) { let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) { - Some((def_id, entry_ty)) => ( - def_id, - match entry_ty { - EntryFnType::Main { sigpipe } => (true, sigpipe), - EntryFnType::Start => (false, sigpipe::DEFAULT), - }, - ), + Some((def_id, entry_ty)) => (def_id, match entry_ty { + EntryFnType::Main { sigpipe } => (true, sigpipe), + EntryFnType::Start => (false, sigpipe::DEFAULT), + }), None => return, }; diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index 196418023d920..13877b3b1e9ae 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -59,8 +59,8 @@ use std::fmt; use std::io::Write; use cranelift_codegen::entity::SecondaryMap; -use cranelift_codegen::ir::entities::AnyEntity; use cranelift_codegen::ir::Fact; +use cranelift_codegen::ir::entities::AnyEntity; use cranelift_codegen::write::{FuncWriter, PlainWriter}; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs index 2fb0c2164c309..a61e1e334eca1 100644 --- a/compiler/rustc_codegen_cranelift/src/trap.rs +++ b/compiler/rustc_codegen_cranelift/src/trap.rs @@ -5,15 +5,11 @@ use crate::prelude::*; fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { let puts = fx .module - .declare_function( - "puts", - Linkage::Import, - &Signature { - call_conv: fx.target_config.default_call_conv, - params: vec![AbiParam::new(fx.pointer_type)], - returns: vec![AbiParam::new(types::I32)], - }, - ) + .declare_function("puts", Linkage::Import, &Signature { + call_conv: fx.target_config.default_call_conv, + params: vec![AbiParam::new(fx.pointer_type)], + returns: vec![AbiParam::new(types::I32)], + }) .unwrap(); let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func); if fx.clif_comments.enabled() { diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index e09cd16e89a64..339628053a953 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -24,17 +24,32 @@ pub(crate) fn unsized_info<'tcx>( let (source, target) = fx.tcx.struct_lockstep_tails_for_codegen(source, target, ParamEnv::reveal_all()); match (&source.kind(), &target.kind()) { - (&ty::Array(_, len), &ty::Slice(_)) => fx - .bcx - .ins() - .iconst(fx.pointer_type, len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64), + (&ty::Array(_, len), &ty::Slice(_)) => fx.bcx.ins().iconst( + fx.pointer_type, + len.try_to_target_usize(fx.tcx).expect("expected monomorphic const in codegen") as i64, + ), (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind)) if src_dyn_kind == target_dyn_kind => { let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { - // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables. + // Codegen takes advantage of the additional assumption, where if the + // principal trait def id of what's being casted doesn't change, + // then we don't need to adjust the vtable at all. This + // corresponds to the fact that `dyn Tr: Unsize>` + // requires that `A = B`; we don't allow *upcasting* objects + // between the same trait with different args. If we, for + // some reason, were to relax the `Unsize` trait, it could become + // unsound, so let's assert here that the trait refs are *equal*. + // + // We can use `assert_eq` because the binders should have been anonymized, + // and because higher-ranked equality now requires the binders are equal. + debug_assert_eq!( + data_a.principal(), + data_b.principal(), + "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" + ); return old_info; } diff --git a/compiler/rustc_codegen_cranelift/test.sh b/compiler/rustc_codegen_cranelift/test.sh index 6357eebf02696..6c07c512ef294 100755 --- a/compiler/rustc_codegen_cranelift/test.sh +++ b/compiler/rustc_codegen_cranelift/test.sh @@ -1,2 +1,2 @@ -#!/usr/bin/env bash +#!/bin/sh exec ./y.sh test "$@" diff --git a/compiler/rustc_codegen_cranelift/y.sh b/compiler/rustc_codegen_cranelift/y.sh index b9152d2cc6de0..a70d457341b93 100755 --- a/compiler/rustc_codegen_cranelift/y.sh +++ b/compiler/rustc_codegen_cranelift/y.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -e echo "[BUILD] build system" 1>&2 diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 915229f7e7eef..0eb264f99eb08 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -11,63 +11,12 @@ dependencies = [ "memchr", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - [[package]] name = "boml" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85fdb93f04c73bff54305fa437ffea5449c41edcaadfe882f35836206b166ac5" -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fastrand" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" - [[package]] name = "fm" version = "0.2.2" @@ -132,12 +81,6 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" -[[package]] -name = "linux-raw-sys" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" - [[package]] name = "memchr" version = "2.5.0" @@ -154,24 +97,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.30.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" -dependencies = [ - "memchr", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "regex" version = "1.8.4" @@ -196,22 +121,6 @@ dependencies = [ "boml", "gccjit", "lang_tester", - "object", - "smallvec", - "tempfile", -] - -[[package]] -name = "rustix" -version = "0.38.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" -dependencies = [ - "bitflags 2.4.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", ] [[package]] @@ -223,25 +132,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "tempfile" -version = "3.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys", -] - [[package]] name = "termcolor" version = "1.2.0" @@ -315,69 +205,3 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 5caca63f63480..44fb5eef04a57 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -23,21 +23,11 @@ default = ["master"] [dependencies] gccjit = "2.1" - # Local copy. #gccjit = { path = "../gccjit.rs" } -object = { version = "0.30.1", default-features = false, features = [ - "std", - "read", -] } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } -# TODO(antoyo): make tempfile optional. -tempfile = "3.7.1" - [dev-dependencies] lang_tester = "0.8.0" -tempfile = "3.1.0" boml = "0.3.1" [profile.dev] diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs index 15ba1612167e4..a7980dec83b6c 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/config.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs @@ -3,8 +3,8 @@ use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::{env as std_env, fs}; -use boml::types::TomlValue; use boml::Toml; +use boml::types::TomlValue; use crate::utils::{ create_dir, create_symlink, get_os_name, get_sysroot_dir, run_command_with_output, diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index 83fa8059b1a05..50e27736aac2d 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::ffi::OsStr; -use std::fs::{remove_dir_all, File}; +use std::fs::{File, remove_dir_all}; use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use std::str::FromStr; diff --git a/compiler/rustc_codegen_gcc/build_system/src/utils.rs b/compiler/rustc_codegen_gcc/build_system/src/utils.rs index e338d1b4992e8..401c23948e5d3 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/utils.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/utils.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; +use std::ffi::OsStr; #[cfg(unix)] use std::ffi::c_int; -use std::ffi::OsStr; use std::fmt::Debug; use std::fs; #[cfg(unix)] diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 0a99e7213be56..14fc23593f0e6 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -1,11 +1,11 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; use gccjit::{ToLValue, ToRValue, Type}; -use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods}; +use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] use rustc_session::config; use rustc_target::abi::call::{ArgAttributes, CastTarget, FnAbi, PassMode, Reg, RegKind}; diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index deeb55e9d128e..e9498857fb9a3 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -2,8 +2,8 @@ use gccjit::FnAttribute; use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type}; use rustc_ast::expand::allocator::{ - alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy, - ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, + ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, + alloc_error_handler_name, default_fn_name, global_fn_name, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 7c135289958fe..13a00f7e08d80 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -5,8 +5,8 @@ use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ - AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, - InlineAsmOperandRef, + AsmBuilderMethods, AsmCodegenMethods, BaseTypeCodegenMethods, BuilderMethods, + GlobalAsmOperandRef, InlineAsmOperandRef, }; use rustc_middle::bug; use rustc_middle::ty::Instance; @@ -770,7 +770,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl } } -impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn codegen_global_asm( &self, template: &[InlineAsmTemplatePiece], diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 6b2dbbbed6771..ed92f9c52412c 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -27,7 +27,7 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; +use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::memmap::Mmap; use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_hir::def_id::LOCAL_CRATE; @@ -35,11 +35,11 @@ use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_session::config::{CrateType, Lto}; -use tempfile::{tempdir, TempDir}; +use tempfile::{TempDir, tempdir}; use crate::back::write::save_temp_bitcode; use crate::errors::{DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib}; -use crate::{to_gcc_opt_level, GccCodegenBackend, GccContext, SyncContext}; +use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level}; /// We keep track of the computed LTO cache keys from the previous /// session to determine which CGUs we can reuse. @@ -272,7 +272,6 @@ fn fat_lto( }*/ } }; - let mut serialized_bitcode = Vec::new(); { info!("using {:?} as a base module", module.name); @@ -317,7 +316,6 @@ fn fat_lto( unimplemented!("from uncompressed file") } } - serialized_bitcode.push(bc_decoded); } save_temp_bitcode(cgcx, &module, "lto.input"); @@ -337,7 +335,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode }) + Ok(LtoModuleCodegen::Fat(module)) } pub struct ModuleBuffer(PathBuf); diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 4940a7fa2051f..9836e654f37f6 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -6,7 +6,7 @@ use std::time::Instant; use gccjit::{CType, FunctionType, GlobalKind}; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; -use rustc_codegen_ssa::traits::DebugInfoMethods; +use rustc_codegen_ssa::traits::DebugInfoCodegenMethods; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_middle::dep_graph; use rustc_middle::mir::mono::Linkage; @@ -19,7 +19,7 @@ use rustc_target::spec::PanicStrategy; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::{gcc_util, new_context, GccContext, LockedTargetInfo, SyncContext}; +use crate::{GccContext, LockedTargetInfo, SyncContext, gcc_util, new_context}; #[cfg(feature = "master")] pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility { diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 6ba678e2e7c65..b687330438239 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -7,32 +7,31 @@ use gccjit::{ BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type, UnaryOp, }; -use rustc_apfloat::{ieee, Float, Round, Status}; +use rustc_apfloat::{Float, Round, Status, ieee}; +use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{ AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, }; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ - BackendTypes, BaseTypeMethods, BuilderMethods, ConstMethods, HasCodegen, LayoutTypeMethods, - OverflowOp, StaticBuilderMethods, + BackendTypes, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, + LayoutTypeCodegenMethods, OverflowOp, StaticBuilderMethods, }; -use rustc_codegen_ssa::MemFlags; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, - TyAndLayout, }; use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; -use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_span::def_id::DefId; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange}; use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi}; -use crate::common::{type_is_pointer, SignType, TypeReflection}; +use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -153,11 +152,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // NOTE: not sure why, but we have the wrong type here. let int_type = compare_exchange.get_param(2).to_rvalue().get_type(); let src = self.context.new_bitcast(self.location, src, int_type); - self.context.new_call( - self.location, - compare_exchange, - &[dst, expected, src, weak, order, failure_order], - ) + self.context.new_call(self.location, compare_exchange, &[ + dst, + expected, + src, + weak, + order, + failure_order, + ]) } pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) { @@ -460,10 +462,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } -impl<'gcc, 'tcx> HasCodegen<'tcx> for Builder<'_, 'gcc, 'tcx> { - type CodegenCx = CodegenCx<'gcc, 'tcx>; -} - impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.cx.tcx() @@ -477,8 +475,6 @@ impl HasDataLayout for Builder<'_, '_, '_> { } impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { - type LayoutOfResult = TyAndLayout<'tcx>; - #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { self.cx.handle_layout_err(err, span, ty) @@ -486,8 +482,6 @@ impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { } impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { - type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; - #[inline] fn handle_fn_abi_err( &self, @@ -509,6 +503,7 @@ impl<'a, 'gcc, 'tcx> Deref for Builder<'a, 'gcc, 'tcx> { impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { type Value = as BackendTypes>::Value; + type Metadata = as BackendTypes>::Metadata; type Function = as BackendTypes>::Function; type BasicBlock = as BackendTypes>::BasicBlock; type Type = as BackendTypes>::Type; @@ -531,6 +526,8 @@ fn set_rvalue_location<'a, 'gcc, 'tcx>( } impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { + type CodegenCx = CodegenCx<'gcc, 'tcx>; + fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> { Builder::with_cx(cx, block) } @@ -1086,11 +1083,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let align = dest.val.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); - let next = self.inbounds_gep( - self.backend_type(cg_elem.layout), - current.to_rvalue(), - &[self.const_usize(1)], - ); + let next = self.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[ + self.const_usize(1), + ]); self.llbb().add_assignment(self.location, current, next); self.br(header_bb); @@ -1939,33 +1934,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.int_type }; - let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() { - let mask_num_units = vector_type.get_num_units(); - let mut mask_elements = vec![]; - for i in 0..mask_num_units { - let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _); - mask_elements.push(self.context.new_cast( - self.location, - self.extract_element(mask, index).to_rvalue(), - mask_element_type, - )); - } - mask_elements - } else { - let struct_type = mask.get_type().is_struct().expect("mask should be of struct type"); - let mask_num_units = struct_type.get_field_count(); - let mut mask_elements = vec![]; - for i in 0..mask_num_units { - let field = struct_type.get_field(i as i32); - mask_elements.push(self.context.new_cast( - self.location, - mask.access_field(self.location, field).to_rvalue(), - mask_element_type, - )); - } - mask_elements - }; - let mask_num_units = mask_elements.len(); + let vector_type = + mask.get_type().dyncast_vector().expect("simd_shuffle mask should be of vector type"); + let mask_num_units = vector_type.get_num_units(); + let mut mask_elements = vec![]; + for i in 0..mask_num_units { + let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _); + mask_elements.push(self.context.new_cast( + self.location, + self.extract_element(mask, index).to_rvalue(), + mask_element_type, + )); + } // NOTE: the mask needs to be the same length as the input vectors, so add the missing // elements in the mask if needed. diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index dca6b6494f94b..726b126e727dd 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,7 +1,9 @@ use gccjit::{LValue, RValue, ToRValue, Type}; -use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods, StaticMethods}; -use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; +use rustc_codegen_ssa::traits::{ + BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, +}; use rustc_middle::mir::Mutability; +use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::LayoutOf; use rustc_target::abi::{self, HasDataLayout, Pointer}; @@ -55,7 +57,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool { typ.get_pointee().is_some() } -impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } @@ -78,22 +80,14 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.const_undef(typ) } - fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { - self.gcc_int(typ, int) - } - - fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> { - self.gcc_uint(typ, int) - } - - fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> { - self.gcc_uint_big(typ, num) - } - fn const_bool(&self, val: bool) -> RValue<'gcc> { self.const_uint(self.type_i1(), val as u64) } + fn const_i8(&self, i: i8) -> RValue<'gcc> { + self.const_int(self.type_i8(), i as i64) + } + fn const_i16(&self, i: i16) -> RValue<'gcc> { self.const_int(self.type_i16(), i as i64) } @@ -102,8 +96,12 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.const_int(self.type_i32(), i as i64) } - fn const_i8(&self, i: i8) -> RValue<'gcc> { - self.const_int(self.type_i8(), i as i64) + fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { + self.gcc_int(typ, int) + } + + fn const_u8(&self, i: u8) -> RValue<'gcc> { + self.const_uint(self.type_u8(), i as u64) } fn const_u32(&self, i: u32) -> RValue<'gcc> { @@ -128,8 +126,12 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.const_uint(self.usize_type, i) } - fn const_u8(&self, i: u8) -> RValue<'gcc> { - self.const_uint(self.type_u8(), i as u64) + fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> { + self.gcc_uint(typ, int) + } + + fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> { + self.gcc_uint_big(typ, num) } fn const_real(&self, typ: Type<'gcc>, val: f64) -> RValue<'gcc> { @@ -222,10 +224,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { value } GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), - GlobalAlloc::VTable(ty, trait_ref) => { + GlobalAlloc::VTable(ty, dyn_ty) => { let alloc = self .tcx - .global_alloc(self.tcx.vtable_allocation((ty, trait_ref))) + .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal()))) .unwrap_memory(); let init = const_alloc_to_gcc(self, alloc); self.static_addr_of(init, alloc.inner().align, None) diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index e5673cddc4a4f..5ad5117d7fd4f 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -1,11 +1,13 @@ #[cfg(feature = "master")] use gccjit::{FnAttribute, VarAttribute, Visibility}; use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type}; -use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, StaticMethods}; +use rustc_codegen_ssa::traits::{ + BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, +}; use rustc_hir::def::DefKind; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ - self, read_target_uint, ConstAllocation, ErrorHandled, Scalar as InterpScalar, + self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint, }; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance}; @@ -37,7 +39,7 @@ fn set_global_alignment<'gcc, 'tcx>( gv.set_alignment(align.bytes() as i32); } -impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { // TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the // following: diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index e330102fbd84b..caccf8296a294 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -5,20 +5,19 @@ use gccjit::{ }; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::errors as ssa_errors; -use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, MiscMethods}; -use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY}; +use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods}; +use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::span_bug; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, - LayoutOfHelpers, TyAndLayout, + LayoutOfHelpers, }; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::source_map::respan; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::call::FnAbi; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi}; @@ -415,6 +414,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { type Value = RValue<'gcc>; + type Metadata = RValue<'gcc>; type Function = RValue<'gcc>; type BasicBlock = Block<'gcc>; @@ -426,7 +426,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { type DIVariable = (); // TODO(antoyo) } -impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn vtables( &self, ) -> &RefCell, Option>), RValue<'gcc>>> { @@ -572,8 +572,6 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> { } impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { - type LayoutOfResult = TyAndLayout<'tcx>; - #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { @@ -585,8 +583,6 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { } impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { - type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; - #[inline] fn handle_fn_abi_err( &self, diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index d770da5a8c44f..271d65a823537 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -2,7 +2,7 @@ use std::ops::Range; use gccjit::{Location, RValue}; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; -use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; +use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; use rustc_data_structures::sync::Lrc; use rustc_index::bit_set::BitSet; use rustc_index::{Idx, IndexVec}; @@ -10,8 +10,8 @@ use rustc_middle::mir::{self, Body, SourceScope}; use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_session::config::DebugInfo; use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol}; -use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; +use rustc_target::abi::call::FnAbi; use crate::builder::Builder; use crate::context::CodegenCx; @@ -48,6 +48,10 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) { self.location = Some(dbg_loc); } + + fn clear_dbg_loc(&mut self) { + self.location = None; + } } /// Generate the `debug_context` in an MIR Body. @@ -202,7 +206,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn create_vtable_debuginfo( &self, _ty: Ty<'tcx>, diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index a2b158ee0a7e8..46818045f0b77 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -1,7 +1,7 @@ #[cfg(feature = "master")] use gccjit::{FnAttribute, ToRValue}; use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type}; -use rustc_codegen_ssa::traits::BaseTypeMethods; +use rustc_codegen_ssa::traits::BaseTypeCodegenMethods; use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::abi::call::FnAbi; diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 5308ccdb61469..01dd1a8856aab 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; use rustc_session::Session; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use crate::errors::{ PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 92d5c1cbbb80a..abb473a830c8d 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -4,10 +4,10 @@ use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp}; +use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{ParamEnv, Ty}; -use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}; use rustc_target::abi::Endian; +use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}; use rustc_target::spec; use crate::builder::{Builder, ToGccComp}; @@ -395,11 +395,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); - let return_type = self.context.new_struct_type( - self.location, - "result_overflow", - &[result_field, overflow_field], - ); + let return_type = self + .context + .new_struct_type(self.location, "result_overflow", &[result_field, overflow_field]); let result = if indirect { let return_value = self.current_func().new_local(self.location, return_type.as_type(), "return_value"); @@ -416,11 +414,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ); self.llbb().add_eval( self.location, - self.context.new_call( - self.location, - func, - &[return_value.get_address(self.location), lhs, rhs], - ), + self.context.new_call(self.location, func, &[ + return_value.get_address(self.location), + lhs, + rhs, + ]), ); return_value.to_rvalue() } else { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index 554e57250e6d8..48f96df61e97e 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -511,12 +511,11 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( let field2 = builder.context.new_field(None, args[1].get_type(), "carryResult"); let struct_type = builder.context.new_struct_type(None, "addcarryResult", &[field1, field2]); - return_value = builder.context.new_struct_constructor( - None, - struct_type.as_type(), - None, - &[return_value, last_arg.dereference(None).to_rvalue()], - ); + return_value = + builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[ + return_value, + last_arg.dereference(None).to_rvalue(), + ]); } } "__builtin_ia32_stmxcsr" => { @@ -541,12 +540,11 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( let field2 = builder.context.new_field(None, return_value.get_type(), "success"); let struct_type = builder.context.new_struct_type(None, "rdrand_result", &[field1, field2]); - return_value = builder.context.new_struct_constructor( - None, - struct_type.as_type(), - None, - &[random_number, success_variable.to_rvalue()], - ); + return_value = + builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[ + random_number, + success_variable.to_rvalue(), + ]); } _ => (), } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 9352a67e362fb..753c3a3dfa630 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -7,28 +7,28 @@ use std::iter; #[cfg(feature = "master")] use gccjit::FunctionType; use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp}; +use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::errors::InvalidMonomorphization; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::{ - ArgAbiMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods, + ArgAbiBuilderMethods, BuilderMethods, ConstCodegenMethods, IntrinsicCallBuilderMethods, }; #[cfg(feature = "master")] -use rustc_codegen_ssa::traits::{BaseTypeMethods, MiscMethods}; -use rustc_codegen_ssa::MemFlags; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, MiscCodegenMethods}; use rustc_middle::bug; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use rustc_middle::ty::{self, Instance, Ty}; -use rustc_span::{sym, Span, Symbol}; -use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::abi::HasDataLayout; +use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use rustc_target::spec::PanicStrategy; #[cfg(feature = "master")] use rustc_target::spec::abi::Abi; -use rustc_target::spec::PanicStrategy; #[cfg(feature = "master")] use crate::abi::FnAbiGccExt; @@ -94,7 +94,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>( Some(cx.context.get_builtin_function(gcc_name)) } -impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { +impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn codegen_intrinsic_call( &mut self, instance: Instance<'tcx>, @@ -448,7 +448,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } } -impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { +impl<'a, 'gcc, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn store_fn_arg( &mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 96a833ccaf2b6..d78b3f2eb8e81 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -10,14 +10,13 @@ use rustc_codegen_ssa::errors::ExpectedPointerMutability; use rustc_codegen_ssa::errors::InvalidMonomorphization; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; -use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; #[cfg(feature = "master")] use rustc_hir as hir; use rustc_middle::mir::BinOp; -use rustc_middle::span_bug; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::abi::{Align, Size}; use crate::builder::Builder; @@ -61,10 +60,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let arg_tys = sig.inputs(); if name == sym::simd_select_bitmask { - require_simd!( - arg_tys[1], - InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] } - ); + require_simd!(arg_tys[1], InvalidMonomorphization::SimdArgument { + span, + name, + ty: arg_tys[1] + }); let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); let expected_int_bits = (len.max(8) - 1).next_power_of_two(); @@ -136,17 +136,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); require!( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty } @@ -252,17 +249,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let lo_nibble = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &lo_nibble_elements); - let mask = bx.context.new_rvalue_from_vector( - None, - long_byte_vector_type, - &vec![bx.context.new_rvalue_from_int(bx.u8_type, 0x0f); byte_vector_type_size as _], - ); - - let four_vec = bx.context.new_rvalue_from_vector( - None, - long_byte_vector_type, - &vec![bx.context.new_rvalue_from_int(bx.u8_type, 4); byte_vector_type_size as _], - ); + let mask = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &vec![ + bx.context + .new_rvalue_from_int( + bx.u8_type, 0x0f + ); + byte_vector_type_size + as _ + ]); + + let four_vec = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &vec![ + bx.context + .new_rvalue_from_int( + bx.u8_type, 4 + ); + byte_vector_type_size + as _ + ]); // Step 2: Byte-swap the input. let swapped = simd_bswap(bx, args[0].immediate()); @@ -353,36 +356,33 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } if name == sym::simd_shuffle { - // Make sure this is actually an array or SIMD vector, since typeck only checks the length-suffixed - // version of this intrinsic. + // Make sure this is actually a SIMD vector. let idx_ty = args[2].layout.ty; - let n: u64 = match idx_ty.kind() { - ty::Array(ty, len) if matches!(*ty.kind(), ty::Uint(ty::UintTy::U32)) => { - len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( - || span_bug!(span, "could not evaluate shuffle index array length"), - ) - } - _ if idx_ty.is_simd() - && matches!( - idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), - ty::Uint(ty::UintTy::U32) - ) => - { - idx_ty.simd_size_and_type(bx.cx.tcx).0 - } - _ => return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }), + let n: u64 = if idx_ty.is_simd() + && matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32)) + { + idx_ty.simd_size_and_type(bx.cx.tcx).0 + } else { + return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }) }; require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); - require!( - out_len == n, - InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len } - ); - require!( - in_elem == out_ty, - InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty } - ); + require!(out_len == n, InvalidMonomorphization::ReturnLength { + span, + name, + in_len: n, + ret_ty, + out_len + }); + require!(in_elem == out_ty, InvalidMonomorphization::ReturnElement { + span, + name, + in_elem, + in_ty, + ret_ty, + out_ty + }); let vector = args[2].immediate(); @@ -391,16 +391,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( #[cfg(feature = "master")] if name == sym::simd_insert { - require!( - in_elem == arg_tys[2], - InvalidMonomorphization::InsertedType { - span, - name, - in_elem, - in_ty, - out_ty: arg_tys[2] - } - ); + require!(in_elem == arg_tys[2], InvalidMonomorphization::InsertedType { + span, + name, + in_elem, + in_ty, + out_ty: arg_tys[2] + }); let vector = args[0].immediate(); let index = args[1].immediate(); let value = args[2].immediate(); @@ -414,10 +411,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( #[cfg(feature = "master")] if name == sym::simd_extract { - require!( - ret_ty == in_elem, - InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } - ); + require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType { + span, + name, + in_elem, + in_ty, + ret_ty + }); let vector = args[0].immediate(); return Ok(bx.context.new_vector_access(None, vector, args[1].immediate()).to_rvalue()); } @@ -425,15 +425,18 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( if name == sym::simd_select { let m_elem_ty = in_elem; let m_len = in_len; - require_simd!( - arg_tys[1], - InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] } - ); + require_simd!(arg_tys[1], InvalidMonomorphization::SimdArgument { + span, + name, + ty: arg_tys[1] + }); let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); - require!( - m_len == v_len, - InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } - ); + require!(m_len == v_len, InvalidMonomorphization::MismatchedLengths { + span, + name, + m_len, + v_len + }); match *m_elem_ty.kind() { ty::Int(_) => {} _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }), @@ -445,27 +448,25 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); match *in_elem.kind() { ty::RawPtr(p_ty, _) => { let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!( - metadata.is_unit(), - InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem } - ); + require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + span, + name, + ty: in_elem + }); } _ => { return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem }) @@ -476,10 +477,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!( - metadata.is_unit(), - InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem } - ); + require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + span, + name, + ty: out_elem + }); } _ => { return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem }) @@ -502,17 +504,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); match *in_elem.kind() { ty::RawPtr(_, _) => {} @@ -541,17 +540,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); match *in_elem.kind() { ty::Uint(ty::UintTy::Usize) => {} @@ -580,17 +576,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( if name == sym::simd_cast || name == sym::simd_as { require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); // casting cares about nominal type, not just structural type if in_elem == out_elem { return Ok(args[0].immediate()); @@ -616,17 +609,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( match (in_style, out_style) { (Style::Unsupported, Style::Unsupported) => { - require!( - false, - InvalidMonomorphization::UnsupportedCast { - span, - name, - in_ty, - in_elem, - ret_ty, - out_elem - } - ); + require!(false, InvalidMonomorphization::UnsupportedCast { + span, + name, + in_ty, + in_elem, + ret_ty, + out_elem + }); } _ => return Ok(bx.context.convert_vector(None, args[0].immediate(), llret_ty)), } @@ -891,47 +881,45 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // All types must be simd vector types require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty }); - require_simd!( - arg_tys[1], - InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] } - ); - require_simd!( - arg_tys[2], - InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] } - ); + require_simd!(arg_tys[1], InvalidMonomorphization::SimdSecond { + span, + name, + ty: arg_tys[1] + }); + require_simd!(arg_tys[2], InvalidMonomorphization::SimdThird { + span, + name, + ty: arg_tys[2] + }); require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); // Of the same length: let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); - require!( - in_len == out_len, - InvalidMonomorphization::SecondArgumentLength { - span, - name, - in_len, - in_ty, - arg_ty: arg_tys[1], - out_len - } - ); - require!( - in_len == out_len2, - InvalidMonomorphization::ThirdArgumentLength { - span, - name, - in_len, - in_ty, - arg_ty: arg_tys[2], - out_len: out_len2 - } - ); + require!(in_len == out_len, InvalidMonomorphization::SecondArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[1], + out_len + }); + require!(in_len == out_len2, InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[2], + out_len: out_len2 + }); // The return type must match the first argument type - require!( - ret_ty == in_ty, - InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty } - ); + require!(ret_ty == in_ty, InvalidMonomorphization::ExpectedReturnType { + span, + name, + in_ty, + ret_ty + }); // This counts how many pointers fn ptr_count(t: Ty<'_>) -> usize { @@ -958,18 +946,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( (ptr_count(element_ty1), non_ptr(element_ty1)) } _ => { - require!( - false, - InvalidMonomorphization::ExpectedElementType { - span, - name, - expected_element: element_ty1, - second_arg: arg_tys[1], - in_elem, - in_ty, - mutability: ExpectedPointerMutability::Not, - } - ); + require!(false, InvalidMonomorphization::ExpectedElementType { + span, + name, + expected_element: element_ty1, + second_arg: arg_tys[1], + in_elem, + in_ty, + mutability: ExpectedPointerMutability::Not, + }); unreachable!(); } }; @@ -982,15 +967,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( match *element_ty2.kind() { ty::Int(_) => (), _ => { - require!( - false, - InvalidMonomorphization::ThirdArgElementType { - span, - name, - expected_element: element_ty2, - third_arg: arg_tys[2] - } - ); + require!(false, InvalidMonomorphization::ThirdArgElementType { + span, + name, + expected_element: element_ty2, + third_arg: arg_tys[2] + }); } } @@ -1014,40 +996,36 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // All types must be simd vector types require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty }); - require_simd!( - arg_tys[1], - InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] } - ); - require_simd!( - arg_tys[2], - InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] } - ); + require_simd!(arg_tys[1], InvalidMonomorphization::SimdSecond { + span, + name, + ty: arg_tys[1] + }); + require_simd!(arg_tys[2], InvalidMonomorphization::SimdThird { + span, + name, + ty: arg_tys[2] + }); // Of the same length: let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx()); let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); - require!( - in_len == element_len1, - InvalidMonomorphization::SecondArgumentLength { - span, - name, - in_len, - in_ty, - arg_ty: arg_tys[1], - out_len: element_len1 - } - ); - require!( - in_len == element_len2, - InvalidMonomorphization::ThirdArgumentLength { - span, - name, - in_len, - in_ty, - arg_ty: arg_tys[2], - out_len: element_len2 - } - ); + require!(in_len == element_len1, InvalidMonomorphization::SecondArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[1], + out_len: element_len1 + }); + require!(in_len == element_len2, InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[2], + out_len: element_len2 + }); // This counts how many pointers fn ptr_count(t: Ty<'_>) -> usize { @@ -1075,18 +1053,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( (ptr_count(element_ty1), non_ptr(element_ty1)) } _ => { - require!( - false, - InvalidMonomorphization::ExpectedElementType { - span, - name, - expected_element: element_ty1, - second_arg: arg_tys[1], - in_elem, - in_ty, - mutability: ExpectedPointerMutability::Mut, - } - ); + require!(false, InvalidMonomorphization::ExpectedElementType { + span, + name, + expected_element: element_ty1, + second_arg: arg_tys[1], + in_elem, + in_ty, + mutability: ExpectedPointerMutability::Mut, + }); unreachable!(); } }; @@ -1098,15 +1073,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( match *element_ty2.kind() { ty::Int(_) => (), _ => { - require!( - false, - InvalidMonomorphization::ThirdArgElementType { - span, - name, - expected_element: element_ty2, - third_arg: arg_tys[2] - } - ); + require!(false, InvalidMonomorphization::ThirdArgElementType { + span, + name, + expected_element: element_ty2, + third_arg: arg_tys[2] + }); } } @@ -1273,10 +1245,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( ($name:ident : $vec_op:expr, $float_reduce:ident, $ordered:expr, $op:ident, $identity:expr) => { if name == sym::$name { - require!( - ret_ty == in_elem, - InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } - ); + require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType { + span, + name, + in_elem, + in_ty, + ret_ty + }); return match *in_elem.kind() { ty::Int(_) | ty::Uint(_) => { let r = bx.vector_reduce_op(args[0].immediate(), $vec_op); @@ -1342,10 +1317,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( macro_rules! minmax_red { ($name:ident: $int_red:ident, $float_red:ident) => { if name == sym::$name { - require!( - ret_ty == in_elem, - InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } - ); + require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType { + span, + name, + in_elem, + in_ty, + ret_ty + }); return match *in_elem.kind() { ty::Int(_) | ty::Uint(_) => Ok(bx.$int_red(args[0].immediate())), ty::Float(_) => Ok(bx.$float_red(args[0].immediate())), @@ -1369,10 +1347,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( ($name:ident : $op:expr, $boolean:expr) => { if name == sym::$name { let input = if !$boolean { - require!( - ret_ty == in_elem, - InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } - ); + require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType { + span, + name, + in_elem, + in_ty, + ret_ty + }); args[0].immediate() } else { match *in_elem.kind() { diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 94f016234f921..edf524ff0b4af 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -24,6 +24,14 @@ #![deny(clippy::pattern_type_mismatch)] #![allow(clippy::needless_lifetimes)] +// Some "regular" crates we want to share with rustc +extern crate object; +extern crate smallvec; +extern crate tempfile; +#[macro_use] +extern crate tracing; + +// The rustc crates we need extern crate rustc_apfloat; extern crate rustc_ast; extern crate rustc_attr; @@ -42,8 +50,6 @@ extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; -#[macro_use] -extern crate tracing; // This prevents duplicating functions and statics that are already part of the host rustc process. #[allow(unused_extern_crates)] @@ -101,10 +107,10 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; -use rustc_session::config::{Lto, OptLevel, OutputFilenames}; use rustc_session::Session; -use rustc_span::fatal_error::FatalError; +use rustc_session::config::{Lto, OptLevel, OutputFilenames}; use rustc_span::Symbol; +use rustc_span::fatal_error::FatalError; use tempfile::TempDir; use crate::back::lto::ModuleBuffer; diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index e6b22d5187147..8a8b748750c76 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -1,6 +1,6 @@ #[cfg(feature = "master")] use gccjit::{FnAttribute, VarAttribute}; -use rustc_codegen_ssa::traits::PreDefineMethods; +use rustc_codegen_ssa::traits::PreDefineCodegenMethods; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; @@ -13,7 +13,7 @@ use crate::context::CodegenCx; use crate::type_of::LayoutGccExt; use crate::{attributes, base}; -impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { #[cfg_attr(not(feature = "master"), allow(unused_variables))] fn predefine_static( &self, diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index e20234c5ce79c..4ea5544721dea 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -5,7 +5,9 @@ use std::convert::TryInto; use gccjit::CType; use gccjit::{RValue, Struct, Type}; use rustc_codegen_ssa::common::TypeKind; -use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods}; +use rustc_codegen_ssa::traits::{ + BaseTypeCodegenMethods, DerivedTypeCodegenMethods, TypeMembershipCodegenMethods, +}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, ty}; use rustc_target::abi::{AddressSpace, Align, Integer, Size}; @@ -121,7 +123,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_i8(&self) -> Type<'gcc> { self.i8_type } @@ -381,4 +383,4 @@ pub fn struct_fields<'gcc, 'tcx>( (result, packed) } -impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {} +impl<'gcc, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {} diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index b7b1be5369c42..cb45bbde2c27d 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -1,7 +1,9 @@ use std::fmt::Write; use gccjit::{Struct, Type}; -use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; +use rustc_codegen_ssa::traits::{ + BaseTypeCodegenMethods, DerivedTypeCodegenMethods, LayoutTypeCodegenMethods, +}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -330,7 +332,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { } } -impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> { layout.gcc_type(self) } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index dea574a53cd7b..3d75393bf06fd 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -1,19 +1,19 @@ use std::cmp; use libc::c_uint; +use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::MemFlags; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; -use rustc_middle::ty::Ty; use rustc_middle::{bug, ty}; use rustc_session::config; pub(crate) use rustc_target::abi::call::*; use rustc_target::abi::{self, HasDataLayout, Int, Size}; -pub(crate) use rustc_target::spec::abi::Abi; use rustc_target::spec::SanitizerSet; +pub(crate) use rustc_target::spec::abi::Abi; use smallvec::SmallVec; use crate::attributes::llfn_attrs_from_instance; @@ -285,7 +285,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } } -impl<'ll, 'tcx> ArgAbiMethods<'tcx> for Builder<'_, 'll, 'tcx> { +impl<'ll, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn store_fn_arg( &mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, @@ -422,6 +422,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { if let Conv::RiscvInterrupt { kind } = self.conv { func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", kind.as_str())); } + if let Conv::CCmseNonSecureEntry = self.conv { + func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")) + } attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs }); let mut i = 0; @@ -442,11 +445,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // LLVM also rejects full range. && !scalar.is_always_valid(cx) { - attributes::apply_to_llfn( - llfn, - idx, - &[llvm::CreateRangeAttr(cx.llcx, scalar.size(cx), scalar.valid_range(cx))], - ); + attributes::apply_to_llfn(llfn, idx, &[llvm::CreateRangeAttr( + cx.llcx, + scalar.size(cx), + scalar.valid_range(cx), + )]); } }; @@ -465,17 +468,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { cx.type_array(cx.type_i8(), self.ret.layout.size.bytes()), ); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]); - if cx.sess().opts.optimize != config::OptLevel::No - && llvm_util::get_version() >= (18, 0, 0) - { - attributes::apply_to_llfn( - llfn, - llvm::AttributePlace::Argument(i), - &[ - llvm::AttributeKind::Writable.create_attr(cx.llcx), - llvm::AttributeKind::DeadOnUnwind.create_attr(cx.llcx), - ], - ); + if cx.sess().opts.optimize != config::OptLevel::No { + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[ + llvm::AttributeKind::Writable.create_attr(cx.llcx), + llvm::AttributeKind::DeadOnUnwind.create_attr(cx.llcx), + ]); } } PassMode::Cast { cast, pad_i32: _ } => { @@ -591,11 +588,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { bx.cx.llcx, bx.cx.type_array(bx.cx.type_i8(), arg.layout.size.bytes()), ); - attributes::apply_to_callsite( - callsite, - llvm::AttributePlace::Argument(i), - &[byval], - ); + attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[ + byval, + ]); } PassMode::Direct(attrs) | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => { @@ -627,11 +622,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // This will probably get ignored on all targets but those supporting the TrustZone-M // extension (thumbv8m targets). let cmse_nonsecure_call = llvm::CreateAttrString(bx.cx.llcx, "cmse_nonsecure_call"); - attributes::apply_to_callsite( - callsite, - llvm::AttributePlace::Function, - &[cmse_nonsecure_call], - ); + attributes::apply_to_callsite(callsite, llvm::AttributePlace::Function, &[ + cmse_nonsecure_call, + ]); } // Some intrinsics require that an elementtype attribute (with the pointee type of a @@ -661,9 +654,11 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { impl From for llvm::CallConv { fn from(conv: Conv) -> Self { match conv { - Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => { - llvm::CCallConv - } + Conv::C + | Conv::Rust + | Conv::CCmseNonSecureCall + | Conv::CCmseNonSecureEntry + | Conv::RiscvInterrupt { .. } => llvm::CCallConv, Conv::Cold => llvm::ColdCallConv, Conv::PreserveMost => llvm::PreserveMost, Conv::PreserveAll => llvm::PreserveAll, diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index b4f3784a31abd..2adac278c62f9 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -1,14 +1,14 @@ use libc::c_uint; use rustc_ast::expand::allocator::{ - alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy, - ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, + ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, + alloc_error_handler_name, default_fn_name, global_fn_name, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; use crate::llvm::{self, Context, False, Module, True, Type}; -use crate::{attributes, debuginfo, ModuleLlvm}; +use crate::{ModuleLlvm, attributes, debuginfo}; pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 1d91c3fb17ddc..7621f111fe257 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -5,10 +5,10 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::Instance; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, span_bug}; -use rustc_span::{sym, Pos, Span, Symbol}; +use rustc_span::{Pos, Span, Symbol, sym}; use rustc_target::abi::*; use rustc_target::asm::*; use smallvec::SmallVec; @@ -356,7 +356,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } -impl<'tcx> AsmMethods<'tcx> for CodegenCx<'_, 'tcx> { +impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { fn codegen_global_asm( &self, template: &[InlineAsmTemplatePiece], @@ -504,10 +504,15 @@ pub(crate) fn inline_asm_call<'ll>( // due to the asm template string coming from a macro. LLVM will // default to the first srcloc for lines that don't have an // associated srcloc. - srcloc.push(bx.const_i32(0)); + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_i32(0))); } - srcloc.extend(line_spans.iter().map(|span| bx.const_i32(span.lo().to_u32() as i32))); - let md = llvm::LLVMMDNodeInContext(bx.llcx, srcloc.as_ptr(), srcloc.len() as u32); + srcloc.extend( + line_spans + .iter() + .map(|span| llvm::LLVMValueAsMetadata(bx.const_i32(span.lo().to_u32() as i32))), + ); + let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()); + let md = llvm::LLVMMetadataAsValue(&bx.llcx, md); llvm::LLVMSetMetadata(call, kind, md); Some(call) @@ -520,24 +525,16 @@ pub(crate) fn inline_asm_call<'ll>( /// If the register is an xmm/ymm/zmm register then return its index. fn xmm_reg_index(reg: InlineAsmReg) -> Option { + use X86InlineAsmReg::*; match reg { - InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => - { - Some(reg as u32 - X86InlineAsmReg::xmm0 as u32) + InlineAsmReg::X86(reg) if reg as u32 >= xmm0 as u32 && reg as u32 <= xmm15 as u32 => { + Some(reg as u32 - xmm0 as u32) } - InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::ymm0 as u32 - && reg as u32 <= X86InlineAsmReg::ymm15 as u32 => - { - Some(reg as u32 - X86InlineAsmReg::ymm0 as u32) + InlineAsmReg::X86(reg) if reg as u32 >= ymm0 as u32 && reg as u32 <= ymm15 as u32 => { + Some(reg as u32 - ymm0 as u32) } - InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::zmm0 as u32 - && reg as u32 <= X86InlineAsmReg::zmm31 as u32 => - { - Some(reg as u32 - X86InlineAsmReg::zmm0 as u32) + InlineAsmReg::X86(reg) if reg as u32 >= zmm0 as u32 && reg as u32 <= zmm31 as u32 => { + Some(reg as u32 - zmm0 as u32) } _ => None, } @@ -545,50 +542,56 @@ fn xmm_reg_index(reg: InlineAsmReg) -> Option { /// If the register is an AArch64 integer register then return its index. fn a64_reg_index(reg: InlineAsmReg) -> Option { - 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, - } + use AArch64InlineAsmReg::*; + // Unlike `a64_vreg_index`, we can't subtract `x0` to get the u32 because + // `x19` and `x29` are missing and the integer constants for the + // `x0`..`x30` enum variants don't all match the register number. E.g. the + // integer constant for `x18` is 18, but the constant for `x20` is 19. + Some(match reg { + InlineAsmReg::AArch64(r) => match r { + x0 => 0, + x1 => 1, + x2 => 2, + x3 => 3, + x4 => 4, + x5 => 5, + x6 => 6, + x7 => 7, + x8 => 8, + x9 => 9, + x10 => 10, + x11 => 11, + x12 => 12, + x13 => 13, + x14 => 14, + x15 => 15, + x16 => 16, + x17 => 17, + x18 => 18, + // x19 is reserved + x20 => 20, + x21 => 21, + x22 => 22, + x23 => 23, + x24 => 24, + x25 => 25, + x26 => 26, + x27 => 27, + x28 => 28, + // x29 is reserved + x30 => 30, + _ => return None, + }, + _ => return None, + }) } /// If the register is an AArch64 vector register then return its index. fn a64_vreg_index(reg: InlineAsmReg) -> Option { + use AArch64InlineAsmReg::*; match reg { - InlineAsmReg::AArch64(reg) - if reg as u32 >= AArch64InlineAsmReg::v0 as u32 - && reg as u32 <= AArch64InlineAsmReg::v31 as u32 => - { - Some(reg as u32 - AArch64InlineAsmReg::v0 as u32) + InlineAsmReg::AArch64(reg) if reg as u32 >= v0 as u32 && reg as u32 <= v31 as u32 => { + Some(reg as u32 - v0 as u32) } _ => None, } @@ -596,6 +599,7 @@ fn a64_vreg_index(reg: InlineAsmReg) -> Option { /// Converts a register class to an LLVM constraint code. fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> String { + use InlineAsmRegClass::*; match reg { // For vector registers LLVM wants the register name to match the type size. InlineAsmRegOrRegClass::Reg(reg) => { @@ -652,75 +656,66 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> // The constraints can be retrieved from // https://llvm.org/docs/LangRef.html#supported-constraint-code-list InlineAsmRegOrRegClass::RegClass(reg) => match reg { - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => "t", - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x", - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", - InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + AArch64(AArch64InlineAsmRegClass::reg) => "r", + AArch64(AArch64InlineAsmRegClass::vreg) => "w", + AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", + AArch64(AArch64InlineAsmRegClass::preg) => unreachable!("clobber-only"), + Arm(ArmInlineAsmRegClass::reg) => "r", + Arm(ArmInlineAsmRegClass::sreg) + | Arm(ArmInlineAsmRegClass::dreg_low16) + | Arm(ArmInlineAsmRegClass::qreg_low8) => "t", + Arm(ArmInlineAsmRegClass::sreg_low16) + | Arm(ArmInlineAsmRegClass::dreg_low8) + | Arm(ArmInlineAsmRegClass::qreg_low4) => "x", + Arm(ArmInlineAsmRegClass::dreg) | Arm(ArmInlineAsmRegClass::qreg) => "w", + Hexagon(HexagonInlineAsmRegClass::reg) => "r", + LoongArch(LoongArchInlineAsmRegClass::reg) => "r", + LoongArch(LoongArchInlineAsmRegClass::freg) => "f", + Mips(MipsInlineAsmRegClass::reg) => "r", + Mips(MipsInlineAsmRegClass::freg) => "f", + Nvptx(NvptxInlineAsmRegClass::reg16) => "h", + Nvptx(NvptxInlineAsmRegClass::reg32) => "r", + Nvptx(NvptxInlineAsmRegClass::reg64) => "l", + PowerPC(PowerPCInlineAsmRegClass::reg) => "r", + PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", + PowerPC(PowerPCInlineAsmRegClass::freg) => "f", + PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { unreachable!("clobber-only") } - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q", - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q", - InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) - | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", - InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", - InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk", - InlineAsmRegClass::X86( + RiscV(RiscVInlineAsmRegClass::reg) => "r", + RiscV(RiscVInlineAsmRegClass::freg) => "f", + RiscV(RiscVInlineAsmRegClass::vreg) => unreachable!("clobber-only"), + X86(X86InlineAsmRegClass::reg) => "r", + X86(X86InlineAsmRegClass::reg_abcd) => "Q", + X86(X86InlineAsmRegClass::reg_byte) => "q", + X86(X86InlineAsmRegClass::xmm_reg) | X86(X86InlineAsmRegClass::ymm_reg) => "x", + X86(X86InlineAsmRegClass::zmm_reg) => "v", + X86(X86InlineAsmRegClass::kreg) => "^Yk", + X86( X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::kreg0 | X86InlineAsmRegClass::tmm_reg, ) => unreachable!("clobber-only"), - InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", - InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e", - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a", - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d", - InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { - bug!("LLVM backend does not support SPIR-V") - } - InlineAsmRegClass::Err => unreachable!(), + Wasm(WasmInlineAsmRegClass::local) => "r", + Bpf(BpfInlineAsmRegClass::reg) => "r", + Bpf(BpfInlineAsmRegClass::wreg) => "w", + Avr(AvrInlineAsmRegClass::reg) => "r", + Avr(AvrInlineAsmRegClass::reg_upper) => "d", + Avr(AvrInlineAsmRegClass::reg_pair) => "r", + Avr(AvrInlineAsmRegClass::reg_iw) => "w", + Avr(AvrInlineAsmRegClass::reg_ptr) => "e", + S390x(S390xInlineAsmRegClass::reg) => "r", + S390x(S390xInlineAsmRegClass::reg_addr) => "a", + S390x(S390xInlineAsmRegClass::freg) => "f", + Msp430(Msp430InlineAsmRegClass::reg) => "r", + M68k(M68kInlineAsmRegClass::reg) => "r", + M68k(M68kInlineAsmRegClass::reg_addr) => "a", + M68k(M68kInlineAsmRegClass::reg_data) => "d", + CSKY(CSKYInlineAsmRegClass::reg) => "r", + CSKY(CSKYInlineAsmRegClass::freg) => "f", + SpirV(SpirVInlineAsmRegClass::reg) => bug!("LLVM backend does not support SPIR-V"), + Err => unreachable!(), } .to_string(), } @@ -732,44 +727,41 @@ fn modifier_to_llvm( reg: InlineAsmRegClass, modifier: Option, ) -> Option { + use InlineAsmRegClass::*; // The modifiers can be retrieved from // https://llvm.org/docs/LangRef.html#asm-template-argument-modifiers match reg { - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier, - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) - | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { - if modifier == Some('v') { None } else { modifier } - } - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { - unreachable!("clobber-only") + AArch64(AArch64InlineAsmRegClass::reg) => modifier, + AArch64(AArch64InlineAsmRegClass::vreg) | AArch64(AArch64InlineAsmRegClass::vreg_low16) => { + if modifier == Some('v') { + None + } else { + modifier + } } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => None, - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => None, - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => Some('P'), - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { + AArch64(AArch64InlineAsmRegClass::preg) => unreachable!("clobber-only"), + Arm(ArmInlineAsmRegClass::reg) => None, + Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::sreg_low16) => None, + Arm(ArmInlineAsmRegClass::dreg) + | Arm(ArmInlineAsmRegClass::dreg_low16) + | Arm(ArmInlineAsmRegClass::dreg_low8) => Some('P'), + Arm(ArmInlineAsmRegClass::qreg) + | Arm(ArmInlineAsmRegClass::qreg_low8) + | Arm(ArmInlineAsmRegClass::qreg_low4) => { if modifier.is_none() { Some('q') } else { modifier } } - InlineAsmRegClass::Hexagon(_) => None, - InlineAsmRegClass::LoongArch(_) => None, - InlineAsmRegClass::Mips(_) => None, - InlineAsmRegClass::Nvptx(_) => None, - InlineAsmRegClass::PowerPC(_) => None, - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) - | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) - | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier { + Hexagon(_) => None, + LoongArch(_) => None, + Mips(_) => None, + Nvptx(_) => None, + PowerPC(_) => None, + RiscV(RiscVInlineAsmRegClass::reg) | RiscV(RiscVInlineAsmRegClass::freg) => None, + RiscV(RiscVInlineAsmRegClass::vreg) => unreachable!("clobber-only"), + X86(X86InlineAsmRegClass::reg) | X86(X86InlineAsmRegClass::reg_abcd) => match modifier { None if arch == InlineAsmArch::X86_64 => Some('q'), None => Some('k'), Some('l') => Some('b'), @@ -779,10 +771,10 @@ fn modifier_to_llvm( Some('r') => Some('q'), _ => unreachable!(), }, - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => None, - InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::xmm_reg) - | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::ymm_reg) - | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) { + X86(X86InlineAsmRegClass::reg_byte) => None, + X86(reg @ X86InlineAsmRegClass::xmm_reg) + | X86(reg @ X86InlineAsmRegClass::ymm_reg) + | X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) { (X86InlineAsmRegClass::xmm_reg, None) => Some('x'), (X86InlineAsmRegClass::ymm_reg, None) => Some('t'), (X86InlineAsmRegClass::zmm_reg, None) => Some('g'), @@ -791,116 +783,97 @@ fn modifier_to_llvm( (_, Some('z')) => Some('g'), _ => unreachable!(), }, - InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, - InlineAsmRegClass::X86( + X86(X86InlineAsmRegClass::kreg) => None, + X86( X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::kreg0 | X86InlineAsmRegClass::tmm_reg, - ) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None, - InlineAsmRegClass::Bpf(_) => None, - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) - | InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) - | InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => match modifier { + ) => unreachable!("clobber-only"), + Wasm(WasmInlineAsmRegClass::local) => None, + Bpf(_) => None, + Avr(AvrInlineAsmRegClass::reg_pair) + | Avr(AvrInlineAsmRegClass::reg_iw) + | Avr(AvrInlineAsmRegClass::reg_ptr) => match modifier { Some('h') => Some('B'), Some('l') => Some('A'), _ => None, }, - InlineAsmRegClass::Avr(_) => None, - InlineAsmRegClass::S390x(_) => None, - InlineAsmRegClass::Msp430(_) => None, - InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { - bug!("LLVM backend does not support SPIR-V") - } - InlineAsmRegClass::M68k(_) => None, - InlineAsmRegClass::CSKY(_) => None, - InlineAsmRegClass::Err => unreachable!(), + Avr(_) => None, + S390x(_) => None, + Msp430(_) => None, + SpirV(SpirVInlineAsmRegClass::reg) => bug!("LLVM backend does not support SPIR-V"), + M68k(_) => None, + CSKY(_) => None, + Err => unreachable!(), } } /// Type to use for outputs that are discarded. It doesn't really matter what /// the type is, as long as it is valid for the constraint code. fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'ll Type { + use InlineAsmRegClass::*; match reg { - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) - | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { + AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(), + AArch64(AArch64InlineAsmRegClass::vreg) | AArch64(AArch64InlineAsmRegClass::vreg_low16) => { cx.type_vector(cx.type_i64(), 2) } - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => cx.type_f64(), - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { - cx.type_vector(cx.type_i64(), 2) - } - InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(), - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { + AArch64(AArch64InlineAsmRegClass::preg) => unreachable!("clobber-only"), + Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(), + Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), + Arm(ArmInlineAsmRegClass::dreg) + | Arm(ArmInlineAsmRegClass::dreg_low16) + | Arm(ArmInlineAsmRegClass::dreg_low8) => cx.type_f64(), + Arm(ArmInlineAsmRegClass::qreg) + | Arm(ArmInlineAsmRegClass::qreg_low8) + | Arm(ArmInlineAsmRegClass::qreg_low4) => cx.type_vector(cx.type_i64(), 2), + Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(), + LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(), + Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), + Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), + Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), + Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), + Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), + PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), + PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), + PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), + PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { unreachable!("clobber-only") } - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) - | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(), - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(), - InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) - | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) - | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), - InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), - InlineAsmRegClass::X86( + RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), + RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), + RiscV(RiscVInlineAsmRegClass::vreg) => unreachable!("clobber-only"), + X86(X86InlineAsmRegClass::reg) | X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(), + X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(), + X86(X86InlineAsmRegClass::xmm_reg) + | X86(X86InlineAsmRegClass::ymm_reg) + | X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), + X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), + X86( X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::kreg0 | X86InlineAsmRegClass::tmm_reg, - ) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), - InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(), - InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(), - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => cx.type_i8(), - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => cx.type_i8(), - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => cx.type_i16(), - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => cx.type_i16(), - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(), - InlineAsmRegClass::S390x( - S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr, - ) => cx.type_i32(), - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), - InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(), - InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => cx.type_f32(), - InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { - bug!("LLVM backend does not support SPIR-V") - } - InlineAsmRegClass::Err => unreachable!(), + ) => unreachable!("clobber-only"), + Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), + Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(), + Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(), + Avr(AvrInlineAsmRegClass::reg) => cx.type_i8(), + Avr(AvrInlineAsmRegClass::reg_upper) => cx.type_i8(), + Avr(AvrInlineAsmRegClass::reg_pair) => cx.type_i16(), + Avr(AvrInlineAsmRegClass::reg_iw) => cx.type_i16(), + Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(), + S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(), + S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), + Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), + M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), + M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), + M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(), + CSKY(CSKYInlineAsmRegClass::reg) => cx.type_i32(), + CSKY(CSKYInlineAsmRegClass::freg) => cx.type_f32(), + SpirV(SpirVInlineAsmRegClass::reg) => bug!("LLVM backend does not support SPIR-V"), + Err => unreachable!(), } } @@ -940,9 +913,10 @@ fn llvm_fixup_input<'ll, 'tcx>( layout: &TyAndLayout<'tcx>, instance: Instance<'_>, ) -> &'ll Value { + use InlineAsmRegClass::*; let dl = &bx.tcx.data_layout; match (reg, layout.abi) { - (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { let vec_ty = bx.cx.type_vector(bx.cx.type_i8(), 8); bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) @@ -950,7 +924,7 @@ fn llvm_fixup_input<'ll, 'tcx>( value } } - (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { let elem_ty = llvm_asm_scalar_type(bx.cx, s); @@ -963,26 +937,25 @@ fn llvm_fixup_input<'ll, 'tcx>( } bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) } - ( - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), - Abi::Vector { element, count }, - ) if layout.size.bytes() == 8 => { + (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + if layout.size.bytes() == 8 => + { let elem_ty = llvm_asm_scalar_type(bx.cx, element); let vec_ty = bx.cx.type_vector(elem_ty, count); let indices: Vec<_> = (0..count * 2).map(|x| bx.const_i32(x as i32)).collect(); bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } - (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { bx.bitcast(value, bx.cx.type_i64()) } ( - InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), + X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, bx.cx.type_vector(bx.cx.type_f64(), 8)), ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -994,7 +967,7 @@ fn llvm_fixup_input<'ll, 'tcx>( bx.bitcast(value, bx.type_vector(bx.type_i32(), 4)) } ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -1009,7 +982,7 @@ fn llvm_fixup_input<'ll, 'tcx>( bx.bitcast(value, bx.type_vector(bx.type_i16(), 8)) } ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -1018,10 +991,7 @@ fn llvm_fixup_input<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } - ( - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), - Abi::Scalar(s), - ) => { + (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { bx.bitcast(value, bx.cx.type_f32()) } else { @@ -1029,7 +999,7 @@ fn llvm_fixup_input<'ll, 'tcx>( } } ( - InlineAsmRegClass::Arm( + Arm( ArmInlineAsmRegClass::dreg | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, @@ -1043,7 +1013,7 @@ fn llvm_fixup_input<'ll, 'tcx>( } } ( - InlineAsmRegClass::Arm( + Arm( ArmInlineAsmRegClass::dreg | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16 @@ -1055,7 +1025,7 @@ fn llvm_fixup_input<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } - (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), @@ -1064,7 +1034,7 @@ fn llvm_fixup_input<'ll, 'tcx>( _ => value, } } - (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => { @@ -1086,15 +1056,16 @@ fn llvm_fixup_output<'ll, 'tcx>( layout: &TyAndLayout<'tcx>, instance: Instance<'_>, ) -> &'ll Value { + use InlineAsmRegClass::*; match (reg, layout.abi) { - (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { bx.extract_element(value, bx.const_i32(0)) } else { value } } - (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { value = bx.extract_element(value, bx.const_i32(0)); @@ -1103,26 +1074,25 @@ fn llvm_fixup_output<'ll, 'tcx>( } value } - ( - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), - Abi::Vector { element, count }, - ) if layout.size.bytes() == 8 => { + (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + if layout.size.bytes() == 8 => + { let elem_ty = llvm_asm_scalar_type(bx.cx, element); let vec_ty = bx.cx.type_vector(elem_ty, count * 2); let indices: Vec<_> = (0..count).map(|x| bx.const_i32(x as i32)).collect(); bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } - (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { bx.bitcast(value, bx.cx.type_f64()) } ( - InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), + X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, layout.llvm_type(bx.cx)), ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -1134,7 +1104,7 @@ fn llvm_fixup_output<'ll, 'tcx>( bx.bitcast(value, bx.type_f128()) } ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -1145,7 +1115,7 @@ fn llvm_fixup_output<'ll, 'tcx>( bx.extract_element(value, bx.const_usize(0)) } ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -1154,10 +1124,7 @@ fn llvm_fixup_output<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } - ( - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), - Abi::Scalar(s), - ) => { + (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { bx.bitcast(value, bx.cx.type_i32()) } else { @@ -1165,7 +1132,7 @@ fn llvm_fixup_output<'ll, 'tcx>( } } ( - InlineAsmRegClass::Arm( + Arm( ArmInlineAsmRegClass::dreg | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, @@ -1179,7 +1146,7 @@ fn llvm_fixup_output<'ll, 'tcx>( } } ( - InlineAsmRegClass::Arm( + Arm( ArmInlineAsmRegClass::dreg | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16 @@ -1191,7 +1158,7 @@ fn llvm_fixup_output<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } - (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), @@ -1201,7 +1168,7 @@ fn llvm_fixup_output<'ll, 'tcx>( _ => value, } } - (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => { @@ -1220,39 +1187,39 @@ fn llvm_fixup_output_type<'ll, 'tcx>( layout: &TyAndLayout<'tcx>, instance: Instance<'_>, ) -> &'ll Type { + use InlineAsmRegClass::*; match (reg, layout.abi) { - (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { cx.type_vector(cx.type_i8(), 8) } else { layout.llvm_type(cx) } } - (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { let elem_ty = llvm_asm_scalar_type(cx, s); let count = 16 / layout.size.bytes(); cx.type_vector(elem_ty, count) } - ( - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), - Abi::Vector { element, count }, - ) if layout.size.bytes() == 8 => { + (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + if layout.size.bytes() == 8 => + { let elem_ty = llvm_asm_scalar_type(cx, element); cx.type_vector(elem_ty, count * 2) } - (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { cx.type_i64() } ( - InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), + X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => cx.type_vector(cx.type_f64(), 8), ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -1264,7 +1231,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( cx.type_vector(cx.type_i32(), 4) } ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -1272,7 +1239,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( Abi::Scalar(s), ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_vector(cx.type_i16(), 8), ( - InlineAsmRegClass::X86( + X86( X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, @@ -1281,10 +1248,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } - ( - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), - Abi::Scalar(s), - ) => { + (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { cx.type_f32() } else { @@ -1292,7 +1256,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( } } ( - InlineAsmRegClass::Arm( + Arm( ArmInlineAsmRegClass::dreg | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, @@ -1306,7 +1270,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( } } ( - InlineAsmRegClass::Arm( + Arm( ArmInlineAsmRegClass::dreg | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16 @@ -1318,7 +1282,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } - (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), @@ -1327,7 +1291,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( _ => layout.llvm_type(cx), } } - (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(cx, instance, &[sym::zfhmin, sym::zfh]) => { diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 92a857c2adcf4..489259da85646 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -403,34 +403,40 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { to_add.push(AttributeKind::Naked.create_attr(cx.llcx)); // HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions. - // And it is a module-level attribute, so the alternative is pulling naked functions into new LLVM modules. - // Otherwise LLVM's "naked" functions come with endbr prefixes per https://github.com/rust-lang/rust/issues/98768 + // And it is a module-level attribute, so the alternative is pulling naked functions into + // new LLVM modules. Otherwise LLVM's "naked" functions come with endbr prefixes per + // https://github.com/rust-lang/rust/issues/98768 to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx)); if llvm_util::get_version() < (19, 0, 0) { // Prior to LLVM 19, branch-target-enforcement was disabled by setting the attribute to // the string "false". Now it is disabled by absence of the attribute. to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false")); } - } else if llvm_util::get_version() >= (19, 0, 0) { - // For non-naked functions, set branch protection attributes on aarch64. - if let Some(BranchProtection { bti, pac_ret }) = - cx.sess().opts.unstable_opts.branch_protection - { - assert!(cx.sess().target.arch == "aarch64"); - if bti { - to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement")); - } - if let Some(PacRet { leaf, key }) = pac_ret { - to_add.push(llvm::CreateAttrStringValue( - cx.llcx, - "sign-return-address", - if leaf { "all" } else { "non-leaf" }, - )); - to_add.push(llvm::CreateAttrStringValue( - cx.llcx, - "sign-return-address-key", - if key == PAuthKey::A { "a_key" } else { "b_key" }, - )); + } else { + // Do not set sanitizer attributes for naked functions. + to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); + + if llvm_util::get_version() >= (19, 0, 0) { + // For non-naked functions, set branch protection attributes on aarch64. + if let Some(BranchProtection { bti, pac_ret }) = + cx.sess().opts.unstable_opts.branch_protection + { + assert!(cx.sess().target.arch == "aarch64"); + if bti { + to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement")); + } + if let Some(PacRet { leaf, key }) = pac_ret { + to_add.push(llvm::CreateAttrStringValue( + cx.llcx, + "sign-return-address", + if leaf { "all" } else { "non-leaf" }, + )); + to_add.push(llvm::CreateAttrStringValue( + cx.llcx, + "sign-return-address-key", + if key == PAuthKey::A { "a_key" } else { "b_key" }, + )); + } } } } @@ -449,7 +455,8 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( flags |= AllocKindFlags::Zeroed; } to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags)); - // apply to return place instead of function (unlike all other attributes applied in this function) + // apply to return place instead of function (unlike all other attributes applied in this + // function) let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]); } @@ -476,16 +483,12 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { - to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")); - } if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } if let Some(backchain) = backchain_attr(cx) { to_add.push(backchain); } - to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry)); // Always annotate functions with the target-cpu they are compiled for. diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 4f2c83634a8a8..1b4f6682af02d 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -1,12 +1,12 @@ //! A helper class for dealing with static archives -use std::ffi::{c_char, c_void, CStr, CString}; +use std::ffi::{CStr, CString, c_char, c_void}; use std::path::{Path, PathBuf}; use std::{io, mem, ptr, str}; use rustc_codegen_ssa::back::archive::{ - try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, - ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER, + ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, + DEFAULT_OBJECT_READER, ObjectReader, UnknownArchiveKind, try_extract_macho_fat_archive, }; use rustc_session::Session; diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index aa6842c75cec7..1f7a923dd2c68 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -11,7 +11,7 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, TargetMachineFactoryConfig}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; +use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_errors::{DiagCtxtHandle, FatalError}; @@ -23,7 +23,7 @@ use rustc_session::config::{self, CrateType, Lto}; use tracing::{debug, info}; use crate::back::write::{ - self, bitcode_section_name, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers, + self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, save_temp_bitcode, }; use crate::errors::{ DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro, @@ -92,11 +92,9 @@ fn prepare_lto( dcx.emit_err(LtoDylib); return Err(FatalError); } - } else if *crate_type == CrateType::ProcMacro { - if !cgcx.opts.unstable_opts.dylib_lto { - dcx.emit_err(LtoProcMacro); - return Err(FatalError); - } + } else if *crate_type == CrateType::ProcMacro && !cgcx.opts.unstable_opts.dylib_lto { + dcx.emit_err(LtoProcMacro); + return Err(FatalError); } } @@ -158,15 +156,15 @@ fn get_bitcode_slice_from_object_data<'a>( obj: &'a [u8], cgcx: &CodegenContext, ) -> Result<&'a [u8], LtoBitcodeFromRlib> { - // We're about to assume the data here is an object file with sections, but if it's raw LLVM IR that - // won't work. Fortunately, if that's what we have we can just return the object directly, so we sniff - // the relevant magic strings here and return. + // We're about to assume the data here is an object file with sections, but if it's raw LLVM IR + // that won't work. Fortunately, if that's what we have we can just return the object directly, + // so we sniff the relevant magic strings here and return. if obj.starts_with(b"\xDE\xC0\x17\x0B") || obj.starts_with(b"BC\xC0\xDE") { return Ok(obj); } - // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment name" - // which in the public API for sections gets treated as part of the section name, but internally - // in MachOObjectFile.cpp gets treated separately. + // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment + // name" which in the public API for sections gets treated as part of the section name, but + // internally in MachOObjectFile.cpp gets treated separately. let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,"); let mut len = 0; let data = unsafe { @@ -314,7 +312,6 @@ fn fat_lto( } } }; - let mut serialized_bitcode = Vec::new(); { let (llcx, llmod) = { let llvm = &module.module_llvm; @@ -342,9 +339,7 @@ fn fat_lto( serialized_modules.sort_by(|module1, module2| module1.1.cmp(&module2.1)); // For all serialized bitcode files we parse them and link them in as we did - // above, this is all mostly handled in C++. Like above, though, we don't - // know much about the memory management here so we err on the side of being - // save and persist everything with the original module. + // above, this is all mostly handled in C++. let mut linker = Linker::new(llmod); for (bc_decoded, name) in serialized_modules { let _timer = cgcx @@ -355,7 +350,6 @@ fn fat_lto( info!("linking {:?}", name); let data = bc_decoded.data(); linker.add(data).map_err(|()| write::llvm_err(dcx, LlvmError::LoadBitcode { name }))?; - serialized_bitcode.push(bc_decoded); } drop(linker); save_temp_bitcode(cgcx, &module, "lto.input"); @@ -372,7 +366,7 @@ fn fat_lto( } } - Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode }) + Ok(LtoModuleCodegen::Fat(module)) } pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>); @@ -814,8 +808,7 @@ struct ThinLTOKeysMap { impl ThinLTOKeysMap { fn save_to_file(&self, path: &Path) -> io::Result<()> { use std::io::Write; - let file = File::create(path)?; - let mut writer = io::BufWriter::new(file); + let mut writer = File::create_buffered(path)?; // The entries are loaded back into a hash map in `load_from_file()`, so // the order in which we write them to file here does not matter. for (module, key) in &self.keys { @@ -827,8 +820,8 @@ impl ThinLTOKeysMap { fn load_from_file(path: &Path) -> io::Result { use std::io::BufRead; let mut keys = BTreeMap::default(); - let file = File::open(path)?; - for line in io::BufReader::new(file).lines() { + let file = File::open_buffered(path)?; + for line in file.lines() { let line = line?; let mut split = line.split(' '); let module = split.next().unwrap(); @@ -850,7 +843,7 @@ impl ThinLTOKeysMap { llvm::LLVMRustComputeLTOCacheKey(rust_str, module.identifier, data.0); }) .expect("Invalid ThinLTO module key"); - (name.clone().into_string().unwrap(), key) + (module_name_to_str(name).to_string(), key) }) .collect(); Self { keys } diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 681ac75c8772a..44c30d22a9e9c 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_char, CStr}; +use std::ffi::{CStr, c_char}; use std::marker::PhantomData; use std::ops::Deref; use std::ptr::NonNull; @@ -30,7 +30,7 @@ impl OwnedTargetMachine { data_sections: bool, unique_section_names: bool, trap_unreachable: bool, - singletree: bool, + singlethread: bool, verbose_asm: bool, emit_stack_size_section: bool, relax_elf_relocations: bool, @@ -62,7 +62,7 @@ impl OwnedTargetMachine { data_sections, unique_section_names, trap_unreachable, - singletree, + singlethread, verbose_asm, emit_stack_size_section, relax_elf_relocations, @@ -86,15 +86,17 @@ impl Deref for OwnedTargetMachine { type Target = llvm::TargetMachine; fn deref(&self) -> &Self::Target { - // SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine + // SAFETY: constructing ensures we have a valid pointer created by + // llvm::LLVMRustCreateTargetMachine. unsafe { self.tm_unique.as_ref() } } } impl Drop for OwnedTargetMachine { fn drop(&mut self) { - // SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine - // OwnedTargetMachine is not copyable so there is no double free or use after free + // SAFETY: constructing ensures we have a valid pointer created by + // llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no + // double free or use after free. unsafe { llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_mut()); } diff --git a/compiler/rustc_codegen_llvm/src/back/profiling.rs b/compiler/rustc_codegen_llvm/src/back/profiling.rs index 79794775b7b66..73ae0072c424f 100644 --- a/compiler/rustc_codegen_llvm/src/back/profiling.rs +++ b/compiler/rustc_codegen_llvm/src/back/profiling.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_void, CStr}; +use std::ffi::{CStr, c_void}; use std::os::raw::c_char; use std::sync::Arc; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index a5c27d2282eaf..afdd2b581b86e 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -20,28 +20,28 @@ use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{DiagCtxtHandle, FatalError, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::ty::TyCtxt; +use rustc_session::Session; use rustc_session::config::{ self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath, }; -use rustc_session::Session; -use rustc_span::symbol::sym; use rustc_span::InnerSpan; +use rustc_span::symbol::sym; use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::debug; use crate::back::lto::ThinBuffer; use crate::back::owned_target_machine::OwnedTargetMachine; use crate::back::profiling::{ - selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler, + LlvmSelfProfiler, selfprofile_after_pass_callback, selfprofile_before_pass_callback, }; use crate::errors::{ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression, WithLlvmError, WriteBytecode, }; -use crate::llvm::diagnostic::OptimizationDiagnosticKind; +use crate::llvm::diagnostic::OptimizationDiagnosticKind::*; use crate::llvm::{self, DiagnosticInfo, PassManager}; use crate::type_::Type; -use crate::{base, common, llvm_util, LlvmCodegenBackend, ModuleLlvm}; +use crate::{LlvmCodegenBackend, ModuleLlvm, base, common, llvm_util}; pub(crate) fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> FatalError { match llvm::last_error() { @@ -157,7 +157,8 @@ fn to_pass_builder_opt_level(cfg: config::OptLevel) -> llvm::PassBuilderOptLevel fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel { match relocation_model { RelocModel::Static => llvm::RelocModel::Static, - // LLVM doesn't have a PIE relocation model, it represents PIE as PIC with an extra attribute. + // LLVM doesn't have a PIE relocation model, it represents PIE as PIC with an extra + // attribute. RelocModel::Pic | RelocModel::Pie => llvm::RelocModel::PIC, RelocModel::DynamicNoPic => llvm::RelocModel::DynamicNoPic, RelocModel::Ropi => llvm::RelocModel::ROPI, @@ -185,7 +186,13 @@ pub(crate) fn target_machine_factory( let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let (opt_level, _) = to_llvm_opt_settings(optlvl); - let use_softfp = sess.opts.cg.soft_float; + let use_softfp = if sess.target.arch == "arm" && sess.target.abi == "eabihf" { + sess.opts.cg.soft_float + } else { + // `validate_commandline_args_with_session_available` has already warned about this being + // ignored. Let's make sure LLVM doesn't suddenly start using this flag on more targets. + false + }; let ffunction_sections = sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections); @@ -440,13 +447,12 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void column: opt.column, pass_name: &opt.pass_name, kind: match opt.kind { - OptimizationDiagnosticKind::OptimizationRemark => "success", - OptimizationDiagnosticKind::OptimizationMissed - | OptimizationDiagnosticKind::OptimizationFailure => "missed", - OptimizationDiagnosticKind::OptimizationAnalysis - | OptimizationDiagnosticKind::OptimizationAnalysisFPCommute - | OptimizationDiagnosticKind::OptimizationAnalysisAliasing => "analysis", - OptimizationDiagnosticKind::OptimizationRemarkOther => "other", + OptimizationRemark => "success", + OptimizationMissed | OptimizationFailure => "missed", + OptimizationAnalysis + | OptimizationAnalysisFPCommute + | OptimizationAnalysisAliasing => "analysis", + OptimizationRemarkOther => "other", }, message: &opt.message, }); @@ -939,11 +945,12 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: } fn target_is_apple(cgcx: &CodegenContext) -> bool { - cgcx.opts.target_triple.triple().contains("-ios") - || cgcx.opts.target_triple.triple().contains("-darwin") - || cgcx.opts.target_triple.triple().contains("-tvos") - || cgcx.opts.target_triple.triple().contains("-watchos") - || cgcx.opts.target_triple.triple().contains("-visionos") + let triple = cgcx.opts.target_triple.triple(); + triple.contains("-ios") + || triple.contains("-darwin") + || triple.contains("-tvos") + || triple.contains("-watchos") + || triple.contains("-visionos") } fn target_is_aix(cgcx: &CodegenContext) -> bool { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 40783825cae57..4e0c62c8bf8c9 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -3,11 +3,11 @@ use std::ops::Deref; use std::{iter, ptr}; use libc::{c_char, c_uint}; +use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::MemFlags; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -26,13 +26,13 @@ use smallvec::SmallVec; use tracing::{debug, instrument}; use crate::abi::FnAbiLlvmExt; +use crate::attributes; use crate::common::Funclet; use crate::context::CodegenCx; use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; -use crate::{attributes, llvm_util}; // All Builders must have an llfn associated with them #[must_use] @@ -56,6 +56,7 @@ const UNNAMED: *const c_char = c"".as_ptr(); impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> { type Value = as BackendTypes>::Value; + type Metadata = as BackendTypes>::Metadata; type Function = as BackendTypes>::Function; type BasicBlock = as BackendTypes>::BasicBlock; type Type = as BackendTypes>::Type; @@ -93,8 +94,6 @@ impl HasTargetSpec for Builder<'_, '_, '_> { } impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { - type LayoutOfResult = TyAndLayout<'tcx>; - #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { self.cx.handle_layout_err(err, span, ty) @@ -102,8 +101,6 @@ impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { } impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { - type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; - #[inline] fn handle_fn_abi_err( &self, @@ -124,11 +121,7 @@ impl<'ll, 'tcx> Deref for Builder<'_, 'll, 'tcx> { } } -impl<'ll, 'tcx> HasCodegen<'tcx> for Builder<'_, 'll, 'tcx> { - type CodegenCx = CodegenCx<'ll, 'tcx>; -} - -macro_rules! builder_methods_for_value_instructions { +macro_rules! math_builder_methods { ($($name:ident($($arg:ident),*) => $llvm_capi:ident),+ $(,)?) => { $(fn $name(&mut self, $($arg: &'ll Value),*) -> &'ll Value { unsafe { @@ -138,7 +131,21 @@ macro_rules! builder_methods_for_value_instructions { } } +macro_rules! set_math_builder_methods { + ($($name:ident($($arg:ident),*) => ($llvm_capi:ident, $llvm_set_math:ident)),+ $(,)?) => { + $(fn $name(&mut self, $($arg: &'ll Value),*) -> &'ll Value { + unsafe { + let instr = llvm::$llvm_capi(self.llbuilder, $($arg,)* UNNAMED); + llvm::$llvm_set_math(instr); + instr + } + })+ + } +} + impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { + type CodegenCx = CodegenCx<'ll, 'tcx>; + fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Self { let bx = Builder::with_cx(cx); unsafe { @@ -273,7 +280,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - builder_methods_for_value_instructions! { + math_builder_methods! { add(a, b) => LLVMBuildAdd, fadd(a, b) => LLVMBuildFAdd, sub(a, b) => LLVMBuildSub, @@ -305,84 +312,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unchecked_umul(x, y) => LLVMBuildNUWMul, } - fn fadd_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetFastMath(instr); - instr - } - } - - fn fsub_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetFastMath(instr); - instr - } - } - - fn fmul_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetFastMath(instr); - instr - } - } - - fn fdiv_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetFastMath(instr); - instr - } - } - - fn frem_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetFastMath(instr); - instr - } - } - - fn fadd_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetAlgebraicMath(instr); - instr - } - } - - fn fsub_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetAlgebraicMath(instr); - instr - } - } - - fn fmul_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetAlgebraicMath(instr); - instr - } - } - - fn fdiv_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetAlgebraicMath(instr); - instr - } - } - - fn frem_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - unsafe { - let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, UNNAMED); - llvm::LLVMRustSetAlgebraicMath(instr); - instr - } + set_math_builder_methods! { + fadd_fast(x, y) => (LLVMBuildFAdd, LLVMRustSetFastMath), + fsub_fast(x, y) => (LLVMBuildFSub, LLVMRustSetFastMath), + fmul_fast(x, y) => (LLVMBuildFMul, LLVMRustSetFastMath), + fdiv_fast(x, y) => (LLVMBuildFDiv, LLVMRustSetFastMath), + frem_fast(x, y) => (LLVMBuildFRem, LLVMRustSetFastMath), + fadd_algebraic(x, y) => (LLVMBuildFAdd, LLVMRustSetAlgebraicMath), + fsub_algebraic(x, y) => (LLVMBuildFSub, LLVMRustSetAlgebraicMath), + fmul_algebraic(x, y) => (LLVMBuildFMul, LLVMRustSetAlgebraicMath), + fdiv_algebraic(x, y) => (LLVMBuildFDiv, LLVMRustSetAlgebraicMath), + frem_algebraic(x, y) => (LLVMBuildFRem, LLVMRustSetAlgebraicMath), } fn checked_binop( @@ -465,6 +405,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { val } } + fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value { if scalar.is_bool() { return self.trunc(val, self.cx().type_i1()); @@ -683,26 +624,19 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { let llty = self.cx.val_ty(load); - let v = [ - self.cx.const_uint_big(llty, range.start), - self.cx.const_uint_big(llty, range.end.wrapping_add(1)), + let md = [ + llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)), + llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))), ]; - - llvm::LLVMSetMetadata( - load, - llvm::MD_range as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, v.as_ptr(), v.len() as c_uint), - ); + let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len()); + self.set_metadata(load, llvm::MD_range, md); } } fn nonnull_metadata(&mut self, load: &'ll Value) { unsafe { - llvm::LLVMSetMetadata( - load, - llvm::MD_nonnull as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0), - ); + let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); + self.set_metadata(load, llvm::MD_nonnull, md); } } @@ -733,11 +667,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // for performance. LLVM doesn't seem to care about this, and will happily treat // `!nontemporal` stores as-if they were normal stores (for reordering optimizations // etc) even on x86, despite later lowering them to MOVNT which do *not* behave like - // regular stores but require special fences. - // So we keep a list of architectures where `!nontemporal` is known to be truly just - // a hint, and use regular stores everywhere else. - // (In the future, we could alternatively ensure that an sfence gets emitted after a sequence of movnt - // before any kind of synchronizing operation. But it's not clear how to do that with LLVM.) + // regular stores but require special fences. So we keep a list of architectures + // where `!nontemporal` is known to be truly just a hint, and use regular stores + // everywhere else. (In the future, we could alternatively ensure that an sfence + // gets emitted after a sequence of movnt before any kind of synchronizing + // operation. But it's not clear how to do that with LLVM.) // For more context, see and // . const WELL_BEHAVED_NONTEMPORAL_ARCHS: &[&str] = @@ -750,9 +684,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // *always* point to a metadata value of the integer 1. // // [1]: https://llvm.org/docs/LangRef.html#store-instruction - let one = self.cx.const_i32(1); - let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1); - llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node); + let one = llvm::LLVMValueAsMetadata(self.cx.const_i32(1)); + let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, &one, 1); + self.set_metadata(store, llvm::MD_nontemporal, md); } } store @@ -1166,6 +1100,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { (val, success) } } + fn atomic_rmw( &mut self, op: rustc_codegen_ssa::common::AtomicRmwBinOp, @@ -1216,11 +1151,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn set_invariant_load(&mut self, load: &'ll Value) { unsafe { - llvm::LLVMSetMetadata( - load, - llvm::MD_invariant_load as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0), - ); + let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); + self.set_metadata(load, llvm::MD_invariant_load, md); } } @@ -1317,15 +1249,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn apply_attrs_to_cleanup_callsite(&mut self, llret: &'ll Value) { - if llvm_util::get_version() < (17, 0, 2) { - // Work around https://github.com/llvm/llvm-project/issues/66984. - let noinline = llvm::AttributeKind::NoInline.create_attr(self.llcx); - attributes::apply_to_callsite(llret, llvm::AttributePlace::Function, &[noinline]); - } else { - // Cleanup is always the cold path. - let cold_inline = llvm::AttributeKind::Cold.create_attr(self.llcx); - attributes::apply_to_callsite(llret, llvm::AttributePlace::Function, &[cold_inline]); - } + // Cleanup is always the cold path. + let cold_inline = llvm::AttributeKind::Cold.create_attr(self.llcx); + attributes::apply_to_callsite(llret, llvm::AttributePlace::Function, &[cold_inline]); } } @@ -1355,33 +1281,23 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn align_metadata(&mut self, load: &'ll Value, align: Align) { unsafe { - let v = [self.cx.const_u64(align.bytes())]; - - llvm::LLVMSetMetadata( - load, - llvm::MD_align as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, v.as_ptr(), v.len() as c_uint), - ); + let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))]; + let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len()); + self.set_metadata(load, llvm::MD_align, md); } } fn noundef_metadata(&mut self, load: &'ll Value) { unsafe { - llvm::LLVMSetMetadata( - load, - llvm::MD_noundef as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0), - ); + let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); + self.set_metadata(load, llvm::MD_noundef, md); } } pub(crate) fn set_unpredictable(&mut self, inst: &'ll Value) { unsafe { - llvm::LLVMSetMetadata( - inst, - llvm::MD_unpredictable as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0), - ); + let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); + self.set_metadata(inst, llvm::MD_unpredictable, md); } } @@ -1767,8 +1683,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { ) { debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes); - assert!(llvm_util::get_version() >= (18, 0, 0), "MCDC intrinsics require LLVM 18 or later"); - let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) }; let llty = self.cx.type_func( &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()], @@ -1802,7 +1716,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp ); - assert!(llvm_util::get_version() >= (18, 0, 0), "MCDC intrinsics require LLVM 18 or later"); let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) }; @@ -1844,7 +1757,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { "mcdc_condbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})", fn_name, hash, cond_loc, mcdc_temp, bool_value ); - assert!(llvm_util::get_version() >= (18, 0, 0), "MCDC intrinsics require LLVM 18 or later"); let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(self.cx().llmod) }; let llty = self.cx.type_func( &[ diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 949fd1bc124f5..206a706979204 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -15,11 +15,6 @@ use crate::value::Value; /// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. -/// -/// # Parameters -/// -/// - `cx`: the crate context -/// - `instance`: the instance to be instantiated pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value { let tcx = cx.tcx(); @@ -106,62 +101,42 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t let is_generic = instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some(); - if is_generic { - // This is a monomorphization. Its expected visibility depends - // on whether we are in share-generics mode. - - if cx.tcx.sess.opts.share_generics() { - // We are in share_generics mode. - + let is_hidden = if is_generic { + // This is a monomorphization of a generic function. + if !cx.tcx.sess.opts.share_generics() { + // When not sharing generics, all instances are in the same + // crate and have hidden visibility. + true + } else { if let Some(instance_def_id) = instance_def_id.as_local() { - // This is a definition from the current crate. If the - // definition is unreachable for downstream crates or - // the current crate does not re-export generics, the - // definition of the instance will have been declared - // as `hidden`. - if cx.tcx.is_unreachable_local_definition(instance_def_id) + // This is a monomorphization of a generic function + // defined in the current crate. It is hidden if: + // - the definition is unreachable for downstream + // crates, or + // - the current crate does not re-export generics + // (because the crate is a C library or executable) + cx.tcx.is_unreachable_local_definition(instance_def_id) || !cx.tcx.local_crate_exports_generics() - { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } } else { // This is a monomorphization of a generic function - // defined in an upstream crate. - if instance.upstream_monomorphization(tcx).is_some() { - // This is instantiated in another crate. It cannot - // be `hidden`. - } else { - // This is a local instantiation of an upstream definition. - // If the current crate does not re-export it - // (because it is a C library or an executable), it - // will have been declared `hidden`. - if !cx.tcx.local_crate_exports_generics() { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } + // defined in an upstream crate. It is hidden if: + // - it is instantiated in this crate, and + // - the current crate does not re-export generics + instance.upstream_monomorphization(tcx).is_none() + && !cx.tcx.local_crate_exports_generics() } - } else { - // When not sharing generics, all instances are in the same - // crate and have hidden visibility - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } else { - // This is a non-generic function - if cx.tcx.is_codegened_item(instance_def_id) { - // This is a function that is instantiated in the local crate - - if instance_def_id.is_local() { - // This is function that is defined in the local crate. - // If it is not reachable, it is hidden. - if !cx.tcx.is_reachable_non_generic(instance_def_id) { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } else { - // This is a function from an upstream crate that has - // been instantiated here. These are always hidden. - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } + // This is a non-generic function. It is hidden if: + // - it is instantiated in the local crate, and + // - it is defined an upstream crate (non-local), or + // - it is not reachable + cx.tcx.is_codegened_item(instance_def_id) + && (!instance_def_id.is_local() + || !cx.tcx.is_reachable_non_generic(instance_def_id)) + }; + if is_hidden { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } // MinGW: For backward compatibility we rely on the linker to decide whether it diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index ef6560ecbe59e..31d59905446f3 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -14,7 +14,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; -use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, OperandBundleDef, True}; +use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, OperandBundleDef, True}; use crate::type_::Type; use crate::value::Value; @@ -79,6 +79,7 @@ impl<'ll> Funclet<'ll> { impl<'ll> BackendTypes for CodegenCx<'ll, '_> { type Value = &'ll Value; + type Metadata = &'ll Metadata; // FIXME(eddyb) replace this with a `Function` "subclass" of `Value`. type Function = &'ll Value; @@ -113,7 +114,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } -impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn const_null(&self, t: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMConstNull(t) } } @@ -126,25 +127,14 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMGetPoison(t) } } - fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value { - unsafe { llvm::LLVMConstInt(t, i as u64, True) } - } - - fn const_uint(&self, t: &'ll Type, i: u64) -> &'ll Value { - unsafe { llvm::LLVMConstInt(t, i, False) } - } - - fn const_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value { - unsafe { - let words = [u as u64, (u >> 64) as u64]; - llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr()) - } - } - fn const_bool(&self, val: bool) -> &'ll Value { self.const_uint(self.type_i1(), val as u64) } + fn const_i8(&self, i: i8) -> &'ll Value { + self.const_int(self.type_i8(), i as i64) + } + fn const_i16(&self, i: i16) -> &'ll Value { self.const_int(self.type_i16(), i as i64) } @@ -153,8 +143,12 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.const_int(self.type_i32(), i as i64) } - fn const_i8(&self, i: i8) -> &'ll Value { - self.const_int(self.type_i8(), i as i64) + fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value { + unsafe { llvm::LLVMConstInt(t, i as u64, True) } + } + + fn const_u8(&self, i: u8) -> &'ll Value { + self.const_uint(self.type_i8(), i as u64) } fn const_u32(&self, i: u32) -> &'ll Value { @@ -179,8 +173,15 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.const_uint(self.isize_ty, i) } - fn const_u8(&self, i: u8) -> &'ll Value { - self.const_uint(self.type_i8(), i as u64) + fn const_uint(&self, t: &'ll Type, i: u64) -> &'ll Value { + unsafe { llvm::LLVMConstInt(t, i, False) } + } + + fn const_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value { + unsafe { + let words = [u as u64, (u >> 64) as u64]; + llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr()) + } } fn const_real(&self, t: &'ll Type, val: f64) -> &'ll Value { @@ -290,10 +291,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.get_fn_addr(instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), - GlobalAlloc::VTable(ty, trait_ref) => { + GlobalAlloc::VTable(ty, dyn_ty) => { let alloc = self .tcx - .global_alloc(self.tcx.vtable_allocation((ty, trait_ref))) + .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal()))) .unwrap_memory(); let init = const_alloc_to_llvm(self, alloc, /*static*/ false); let value = self.static_addr_of(init, alloc.inner().align, None); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index b143e28c5f9cc..33a85adeb8781 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -6,8 +6,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ - read_target_uint, Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, - Scalar as InterpScalar, + Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar, + read_target_uint, }; use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::layout::LayoutOf; @@ -73,8 +73,8 @@ pub(crate) fn const_alloc_to_llvm<'ll>( // Generating partially-uninit consts is limited to small numbers of chunks, // to avoid the cost of generating large complex const expressions. - // For example, `[(u32, u8); 1024 * 1024]` contains uninit padding in each element, - // and would result in `{ [5 x i8] zeroinitializer, [3 x i8] undef, ...repeat 1M times... }`. + // For example, `[(u32, u8); 1024 * 1024]` contains uninit padding in each element, and + // would result in `{ [5 x i8] zeroinitializer, [3 x i8] undef, ...repeat 1M times... }`. let max = cx.sess().opts.unstable_opts.uninit_const_chunk_threshold; let allow_uninit_chunks = chunks.clone().take(max.saturating_add(1)).count() <= max; @@ -249,8 +249,8 @@ impl<'ll> CodegenCx<'ll, '_> { trace!(?instance); let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() }; - // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure out - // the llvm type from the actual evaluated initializer. + // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure + // out the llvm type from the actual evaluated initializer. let llty = if nested { self.type_i8() } else { @@ -262,7 +262,7 @@ impl<'ll> CodegenCx<'ll, '_> { } #[instrument(level = "debug", skip(self, llty))] - pub(crate) fn get_static_inner(&self, def_id: DefId, llty: &'ll Type) -> &'ll Value { + fn get_static_inner(&self, def_id: DefId, llty: &'ll Type) -> &'ll Value { let instance = Instance::mono(self.tcx, def_id); if let Some(&g) = self.instances.borrow().get(&instance) { trace!("used cached value"); @@ -320,15 +320,16 @@ impl<'ll> CodegenCx<'ll, '_> { } if !def_id.is_local() { - let needs_dll_storage_attr = self.use_dll_storage_attrs && !self.tcx.is_foreign_item(def_id) && + let needs_dll_storage_attr = self.use_dll_storage_attrs + && !self.tcx.is_foreign_item(def_id) // Local definitions can never be imported, so we must not apply // the DLLImport annotation. - !dso_local && + && !dso_local // 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.lto() != Lto::Thin; + && !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. @@ -390,7 +391,7 @@ impl<'ll> CodegenCx<'ll, '_> { let val_llty = self.val_ty(v); let g = self.get_static_inner(def_id, val_llty); - let llty = self.val_ty(g); + let llty = llvm::LLVMGlobalGetValueType(g); let g = if val_llty == llty { g @@ -442,58 +443,6 @@ impl<'ll> CodegenCx<'ll, '_> { if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { llvm::set_thread_local_mode(g, self.tls_model); - - // Do not allow LLVM to change the alignment of a TLS on macOS. - // - // By default a global's alignment can be freely increased. - // This allows LLVM to generate more performant instructions - // e.g., using load-aligned into a SIMD register. - // - // However, on macOS 10.10 or below, the dynamic linker does not - // respect any alignment given on the TLS (radar 24221680). - // This will violate the alignment assumption, and causing segfault at runtime. - // - // This bug is very easy to trigger. In `println!` and `panic!`, - // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS, - // which the values would be `mem::replace`d on initialization. - // The implementation of `mem::replace` will use SIMD - // whenever the size is 32 bytes or higher. LLVM notices SIMD is used - // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary, - // which macOS's dyld disregarded and causing crashes - // (see issues #51794, #51758, #50867, #48866 and #44056). - // - // To workaround the bug, we trick LLVM into not increasing - // the global's alignment by explicitly assigning a section to it - // (equivalent to automatically generating a `#[link_section]` attribute). - // See the comment in the `GlobalValue::canIncreaseAlignment()` function - // of `lib/IR/Globals.cpp` for why this works. - // - // When the alignment is not increased, the optimized `mem::replace` - // will use load-unaligned instructions instead, and thus avoiding the crash. - // - // We could remove this hack whenever we decide to drop macOS 10.10 support. - if self.tcx.sess.target.is_like_osx { - // The `inspect` method is okay here because we checked for provenance, and - // because we are doing this access to inspect the final interpreter state - // (not as part of the interpreter execution). - // - // FIXME: This check requires that the (arbitrary) value of undefined bytes - // happens to be zero. Instead, we should only check the value of defined bytes - // and set all undefined bytes to zero if this allocation is headed for the - // BSS. - let all_bytes_are_zero = alloc.provenance().ptrs().is_empty() - && alloc - .inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()) - .iter() - .all(|&byte| byte == 0); - - let sect_name = if all_bytes_are_zero { - c"__DATA,__thread_bss" - } else { - c"__DATA,__thread_data" - }; - llvm::LLVMSetSection(g, sect_name.as_ptr()); - } } // Wasm statics with custom link sections get special treatment as they @@ -551,8 +500,8 @@ impl<'ll> CodegenCx<'ll, '_> { // `#[used(compiler)]` is explicitly requested. This is to avoid similar breakage // on other targets, in particular MachO targets have *their* static constructor // lists broken if `llvm.compiler.used` is emitted rather than `llvm.used`. However, - // that check happens when assigning the `CodegenFnAttrFlags` in `rustc_hir_analysis`, - // so we don't need to take care of it here. + // that check happens when assigning the `CodegenFnAttrFlags` in + // `rustc_hir_analysis`, so we don't need to take care of it here. self.add_compiler_used_global(g); } if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { @@ -565,7 +514,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } -impl<'ll> StaticMethods for CodegenCx<'ll, '_> { +impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value { if let Some(&gv) = self.const_globals.borrow().get(&cv) { unsafe { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 01aae24ab56c2..2b8912d1db2ab 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1,13 +1,12 @@ use std::borrow::Borrow; use std::cell::{Cell, RefCell}; -use std::ffi::CStr; +use std::ffi::{CStr, c_uint}; use std::str; -use libc::c_uint; use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh}; use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::traits::*; -use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY}; +use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; @@ -15,30 +14,29 @@ use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers, - TyAndLayout, }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; +use rustc_session::Session; use rustc_session::config::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, PAuthKey, PacRet, }; -use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::call::FnAbi; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{HasDataLayout, TargetDataLayout, VariantIdx}; -use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; +use rustc_target::spec::{HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel}; use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; +use crate::llvm::{Metadata, MetadataType}; use crate::type_::Type; use crate::value::Value; use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util}; -/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM -/// `llvm::Context` so that several compilation units may be optimized in parallel. +/// There is one `CodegenCx` per codegen unit. Each one has its own LLVM +/// `llvm::Context` so that several codegen units may be processed in parallel. /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. pub(crate) struct CodegenCx<'ll, 'tcx> { pub tcx: TyCtxt<'tcx>, @@ -122,14 +120,6 @@ pub(crate) unsafe fn create_module<'ll>( let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); - if llvm_version < (18, 0, 0) { - if sess.target.arch == "x86" || sess.target.arch == "x86_64" { - // LLVM 18 adjusts i128 to be 128-bit aligned on x86 variants. - // Earlier LLVMs leave this as default alignment, so remove it. - // See https://reviews.llvm.org/D86310 - target_data_layout = target_data_layout.replace("-i128:128", ""); - } - } if llvm_version < (19, 0, 0) { if sess.target.arch == "aarch64" || sess.target.arch.starts_with("arm64") { @@ -241,7 +231,8 @@ pub(crate) unsafe fn create_module<'ll>( } } - // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.) + // Enable LTO unit splitting if specified or if CFI is enabled. (See + // https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr(); unsafe { @@ -387,6 +378,24 @@ pub(crate) unsafe fn create_module<'ll>( } } + match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support()) + { + // Set up the small-data optimization limit for architectures that use + // an LLVM module flag to control this. + (Some(threshold), SmallDataThresholdSupport::LlvmModuleFlag(flag)) => { + let flag = SmallCStr::new(flag.as_ref()); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Error, + flag.as_c_str().as_ptr(), + threshold as u32, + ) + } + } + _ => (), + }; + // Insert `llvm.ident` metadata. // // On the wasm targets it will get hooked up to the "producer" sections @@ -395,17 +404,17 @@ pub(crate) unsafe fn create_module<'ll>( let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); let name_metadata = unsafe { - llvm::LLVMMDStringInContext( + llvm::LLVMMDStringInContext2( llcx, rustc_producer.as_ptr().cast(), - rustc_producer.as_bytes().len() as c_uint, + rustc_producer.as_bytes().len(), ) }; unsafe { llvm::LLVMAddNamedMetadataOperand( llmod, c"llvm.ident".as_ptr(), - llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), + &llvm::LLVMMetadataAsValue(llcx, llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), ); } @@ -580,7 +589,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } } -impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn vtables( &self, ) -> &RefCell, Option>), &'ll Value>> @@ -1110,6 +1119,14 @@ impl CodegenCx<'_, '_> { name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY)); name } + + /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. + pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) { + unsafe { + let node = llvm::LLVMMetadataAsValue(&self.llcx, md); + llvm::LLVMSetMetadata(val, kind_id as c_uint, node); + } + } } impl HasDataLayout for CodegenCx<'_, '_> { @@ -1140,8 +1157,6 @@ impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { - type LayoutOfResult = TyAndLayout<'tcx>; - #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { @@ -1153,8 +1168,6 @@ impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { } impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { - type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; - #[inline] fn handle_fn_abi_err( &self, diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index d7a4f105f3c41..77821ca89bc14 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -121,7 +121,8 @@ mod mcdc { num_conditions: u16, } - // ConditionId in llvm is `unsigned int` at 18 while `int16_t` at [19](https://github.com/llvm/llvm-project/pull/81257) + // ConditionId in llvm is `unsigned int` at 18 while `int16_t` at + // [19](https://github.com/llvm/llvm-project/pull/81257). type LLVMConditionId = i16; /// Must match the layout of `LLVMRustMCDCBranchParameters`. diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 069b62af5e748..267a22449167d 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,12 +1,12 @@ use itertools::Itertools as _; -use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::IndexVec; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, mir}; -use rustc_span::def_id::DefIdSet; use rustc_span::Symbol; +use rustc_span::def_id::DefIdSet; use tracing::debug; use crate::common::CodegenCx; @@ -183,8 +183,8 @@ impl GlobalFileTable { // Since rustc generates coverage maps with relative paths, the // compilation directory can be combined with the relative paths // to get absolute paths, if needed. - use rustc_session::config::RemapPathScopeComponents; use rustc_session::RemapFileNameExt; + use rustc_session::config::RemapPathScopeComponents; let working_dir: &str = &tcx .sess .opts @@ -422,7 +422,7 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> { (instance.def_id(), body) }); - // Functions whose coverage statments were found inlined into other functions. + // Functions whose coverage statements were found inlined into other functions. let mut used_via_inlining = FxHashSet::default(); // Functions that were instrumented, but had all of their coverage statements // removed by later MIR transforms (e.g. UnreachablePropagation). diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 69babc7c9cf3e..3a80d216f47ee 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -2,15 +2,15 @@ use std::cell::RefCell; use libc::c_uint; use rustc_codegen_ssa::traits::{ - BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods, - StaticMethods, + BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, + MiscCodegenMethods, StaticCodegenMethods, }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_llvm::RustString; use rustc_middle::bug; use rustc_middle::mir::coverage::CoverageKind; -use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::Instance; +use rustc_middle::ty::layout::HasTyCtxt; use rustc_target::abi::{Align, Size}; use tracing::{debug, instrument}; @@ -48,11 +48,10 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { self.function_coverage_map.replace(FxIndexMap::default()) } - /// LLVM use a temp value to record evaluated mcdc test vector of each decision, which is called condition bitmap. - /// In order to handle nested decisions, several condition bitmaps can be - /// allocated for a function body. - /// These values are named `mcdc.addr.{i}` and are a 32-bit integers. - /// They respectively hold the condition bitmaps for decisions with a depth of `i`. + /// LLVM use a temp value to record evaluated mcdc test vector of each decision, which is + /// called condition bitmap. In order to handle nested decisions, several condition bitmaps can + /// be allocated for a function body. These values are named `mcdc.addr.{i}` and are a 32-bit + /// integers. They respectively hold the condition bitmaps for decisions with a depth of `i`. fn try_get_mcdc_condition_bitmap( &self, instance: &Instance<'tcx>, @@ -157,8 +156,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { ), CoverageKind::CounterIncrement { id } => { func_coverage.mark_counter_id_seen(id); - // We need to explicitly drop the `RefMut` before calling into `instrprof_increment`, - // as that needs an exclusive borrow. + // We need to explicitly drop the `RefMut` before calling into + // `instrprof_increment`, as that needs an exclusive borrow. drop(coverage_map); // The number of counters passed to `llvm.instrprof.increment` might diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index c3087d8ec3040..ac6c2fb1b83a6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -1,7 +1,7 @@ use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext}; use rustc_codegen_ssa::traits::*; -use rustc_index::bit_set::BitSet; use rustc_index::Idx; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::{Body, SourceScope}; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index dc228e9481167..f93d3e40b2051 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -44,7 +44,8 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( // Add the pretty printers for the standard library first. section_contents.extend_from_slice(b"\x01gdb_load_rust_pretty_printers.py\0"); - // Next, add the pretty printers that were specified via the `#[debugger_visualizer]` attribute. + // Next, add the pretty printers that were specified via the `#[debugger_visualizer]` + // attribute. let visualizers = collect_debugger_visualizers_transitive( cx.tcx, DebuggerVisualizerType::GdbPrettyPrinter, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 17a9630c6557b..964b83c0fa07a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::{iter, ptr}; use libc::{c_char, c_longlong, c_uint}; -use rustc_codegen_ssa::debuginfo::type_names::{cpp_like_debuginfo, VTableNameKind}; +use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; use rustc_fs_util::path_to_c_string; use rustc_hir::def::{CtorKind, DefKind}; @@ -18,7 +18,7 @@ use rustc_middle::ty::{ }; use rustc_session::config::{self, DebugInfo, Lto}; use rustc_span::symbol::Symbol; -use rustc_span::{hygiene, FileName, FileNameDisplayPreference, SourceFile, DUMMY_SP}; +use rustc_span::{DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, hygiene}; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::abi::{Align, Size}; use rustc_target::spec::DebuginfoKind; @@ -26,15 +26,15 @@ use smallvec::smallvec; use tracing::{debug, instrument}; use self::type_map::{DINodeCreationResult, Stub, UniqueTypeId}; +use super::CodegenUnitDebugContext; use super::namespace::mangled_name_of_instance; use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name}; use super::utils::{ - create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB, + DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, }; -use super::CodegenUnitDebugContext; use crate::common::CodegenCx; use crate::debuginfo::metadata::type_map::build_type_with_children; -use crate::debuginfo::utils::{fat_pointer_kind, FatPtrKind}; +use crate::debuginfo::utils::{FatPtrKind, fat_pointer_kind}; use crate::llvm::debuginfo::{ DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind, DebugNameTableKind, @@ -125,7 +125,9 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( let (size, align) = cx.size_and_align_of(array_type); - let upper_bound = len.eval_target_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong; + let upper_bound = len + .try_to_target_usize(cx.tcx) + .expect("expected monomorphic const in codegen") as c_longlong; let subrange = unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) }; @@ -216,8 +218,9 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( // need to make sure that we don't break existing debuginfo consumers // by doing that (at least not without a warning period). let layout_type = if ptr_type.is_box() { - // The assertion at the start of this function ensures we have a ZST allocator. - // We'll make debuginfo "skip" all ZST allocators, not just the default allocator. + // The assertion at the start of this function ensures we have a ZST + // allocator. We'll make debuginfo "skip" all ZST allocators, not just the + // default allocator. Ty::new_mut_ptr(cx.tcx, pointee_type) } else { ptr_type @@ -280,8 +283,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, ) -> DINodeCreationResult<'ll> { - // It's possible to create a self-referential - // type in Rust by using 'impl trait': + // It's possible to create a self-referential type in Rust by using 'impl trait': // // fn foo() -> impl Copy { foo } // @@ -456,7 +458,7 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> if def.is_box() && args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) => { - build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id) + build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id) } ty::FnDef(..) | ty::FnPtr(..) => build_subroutine_type_di_node(cx, unique_type_id), ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id), @@ -573,14 +575,14 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi { // If the compiler's working directory (which also is the DW_AT_comp_dir of // the compilation unit) is a prefix of the path we are about to emit, then - // only emit the part relative to the working directory. - // Because of path remapping we sometimes see strange things here: `abs_path` - // might actually look like a relative path - // (e.g. `/src/lib.rs`), so if we emit it without - // taking the working directory into account, downstream tooling will - // interpret it as `//src/lib.rs`, - // which makes no sense. Usually in such cases the working directory will also - // be remapped to `` or some other prefix of the path + // only emit the part relative to the working directory. Because of path + // remapping we sometimes see strange things here: `abs_path` might + // actually look like a relative path (e.g. + // `/src/lib.rs`), so if we emit it without taking + // the working directory into account, downstream tooling will interpret it + // as `//src/lib.rs`, which + // makes no sense. Usually in such cases the working directory will also be + // remapped to `` or some other prefix of the path // we are remapping, so we end up with // `//src/lib.rs`. // By moving the working directory portion into the `directory` part of the @@ -873,8 +875,8 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( codegen_unit_name: &str, debug_context: &CodegenUnitDebugContext<'ll, 'tcx>, ) -> &'ll DIDescriptor { - use rustc_session::config::RemapPathScopeComponents; use rustc_session::RemapFileNameExt; + use rustc_session::config::RemapPathScopeComponents; let mut name_in_debuginfo = tcx .sess .local_crate_source_file() @@ -1545,20 +1547,16 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); unsafe { - let typeid = llvm::LLVMMDStringInContext( + let typeid = llvm::LLVMMDStringInContext2( cx.llcx, trait_ref_typeid.as_ptr() as *const c_char, - trait_ref_typeid.as_bytes().len() as c_uint, + trait_ref_typeid.as_bytes().len(), ); - let v = [cx.const_usize(0), typeid]; + let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; llvm::LLVMRustGlobalAddMetadata( vtable, llvm::MD_type as c_uint, - llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext( - cx.llcx, - v.as_ptr(), - v.len() as c_uint, - )), + llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()), ); let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64)); let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 181022087f3bf..966788cf32f54 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use libc::c_uint; use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name; use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo}; -use rustc_codegen_ssa::traits::ConstMethods; +use rustc_codegen_ssa::traits::ConstCodegenMethods; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; @@ -15,9 +15,9 @@ use crate::common::CodegenCx; use crate::debuginfo::metadata::enums::DiscrResult; use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId}; use crate::debuginfo::metadata::{ + DINodeCreationResult, NO_GENERICS, NO_SCOPE_METADATA, SmallVec, UNKNOWN_LINE_NUMBER, build_field_di_node, file_metadata, size_and_align_of, type_di_node, unknown_file_metadata, - visibility_di_flags, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA, - UNKNOWN_LINE_NUMBER, + visibility_di_flags, }; use crate::debuginfo::utils::DIB; use crate::llvm::debuginfo::{DIFile, DIFlags, DIType}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index edaf73b74a2a0..fe1634146ff83 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -12,14 +12,14 @@ use rustc_span::Symbol; use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants}; use super::type_map::{DINodeCreationResult, UniqueTypeId}; -use super::{size_and_align_of, SmallVec}; +use super::{SmallVec, size_and_align_of}; use crate::common::CodegenCx; use crate::debuginfo::metadata::type_map::{self, Stub}; use crate::debuginfo::metadata::{ - build_field_di_node, build_generic_type_param_di_nodes, type_di_node, unknown_file_metadata, - UNKNOWN_LINE_NUMBER, + UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes, type_di_node, + unknown_file_metadata, }; -use crate::debuginfo::utils::{create_DIArray, get_namespace_for_item, DIB}; +use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item}; use crate::llvm::debuginfo::{DIFlags, DIType}; use crate::llvm::{self}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 238fbad4dfd64..5e7dbdd921abf 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use libc::c_uint; use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name; use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo}; -use rustc_codegen_ssa::traits::ConstMethods; +use rustc_codegen_ssa::traits::ConstCodegenMethods; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self}; @@ -13,10 +13,10 @@ use smallvec::smallvec; use crate::common::CodegenCx; use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId}; use crate::debuginfo::metadata::{ - file_metadata, size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags, - DINodeCreationResult, SmallVec, NO_GENERICS, UNKNOWN_LINE_NUMBER, + DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, file_metadata, + size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags, }; -use crate::debuginfo::utils::{create_DIArray, get_namespace_for_item, DIB}; +use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item}; use crate::llvm::debuginfo::{DIFile, DIFlags, DIType}; use crate::llvm::{self}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 6d21f4204e361..714e3c0b1458c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -8,9 +8,9 @@ use rustc_middle::bug; use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_target::abi::{Align, Size, VariantIdx}; -use super::{unknown_file_metadata, SmallVec, UNKNOWN_LINE_NUMBER}; +use super::{SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata}; use crate::common::CodegenCx; -use crate::debuginfo::utils::{create_DIArray, debug_context, DIB}; +use crate::debuginfo::utils::{DIB, create_DIArray, debug_context}; use crate::llvm::debuginfo::{DIFlags, DIScope, DIType}; use crate::llvm::{self}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index f5d6fc6f08073..1a8153a54e837 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -1,8 +1,8 @@ #![doc = include_str!("doc.md")] use std::cell::{OnceCell, RefCell}; -use std::iter; use std::ops::Range; +use std::{iter, ptr}; use libc::c_uint; use rustc_codegen_ssa::debuginfo::type_names; @@ -16,8 +16,8 @@ use rustc_index::IndexVec; use rustc_middle::mir; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, GenericArgsRef, Instance, ParamEnv, Ty, TypeVisitableExt}; -use rustc_session::config::{self, DebugInfo}; use rustc_session::Session; +use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::Symbol; use rustc_span::{ BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, @@ -26,9 +26,9 @@ use rustc_target::abi::Size; use smallvec::SmallVec; use tracing::debug; -use self::metadata::{file_metadata, type_di_node, UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER}; +use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, type_di_node}; use self::namespace::mangled_name_of_instance; -use self::utils::{create_DIArray, is_node_local_to_unit, DIB}; +use self::utils::{DIB, create_DIArray, is_node_local_to_unit}; use crate::abi::FnAbi; use crate::builder::Builder; use crate::common::CodegenCx; @@ -209,6 +209,12 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { } } + fn clear_dbg_loc(&mut self) { + unsafe { + llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null()); + } + } + fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { gdb::insert_reference_to_gdb_debug_scripts_section_global(self) } @@ -280,7 +286,7 @@ impl CodegenCx<'_, '_> { } } -impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn create_function_debug_context( &self, instance: Instance<'tcx>, @@ -549,17 +555,14 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - let scope = namespace::item_namespace( - cx, - DefId { - krate: instance.def_id().krate, - index: cx - .tcx - .def_key(instance.def_id()) - .parent - .expect("get_containing_scope: missing parent?"), - }, - ); + let scope = namespace::item_namespace(cx, DefId { + krate: instance.def_id().krate, + index: cx + .tcx + .def_key(instance.def_id()) + .parent + .expect("get_containing_scope: missing parent?"), + }); (scope, false) } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index 83d7a82dadc4d..3578755aae059 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -4,7 +4,7 @@ use rustc_codegen_ssa::debuginfo::type_names; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, Instance}; -use super::utils::{debug_context, DIB}; +use super::utils::{DIB, debug_context}; use crate::common::CodegenCx; use crate::llvm; use crate::llvm::debuginfo::DIScope; @@ -13,8 +13,7 @@ pub(crate) fn mangled_name_of_instance<'a, 'tcx>( cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>, ) -> ty::SymbolName<'tcx> { - let tcx = cx.tcx; - tcx.symbol_name(instance) + cx.tcx.symbol_name(instance) } pub(crate) fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index 321553a3df0bd..acb15449ce323 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -5,8 +5,8 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty}; use tracing::trace; -use super::namespace::item_namespace; use super::CodegenUnitDebugContext; +use super::namespace::item_namespace; use crate::common::CodegenCx; use crate::llvm; use crate::llvm::debuginfo::{DIArray, DIBuilder, DIDescriptor, DIScope}; diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 4e4500b637328..b0b29ca1280d5 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -12,7 +12,7 @@ //! * When in doubt, define. use itertools::Itertools; -use rustc_codegen_ssa::traits::TypeMembershipMethods; +use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{Instance, Ty}; use rustc_sanitizers::{cfi, kcfi}; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index a300f5f707a88..c66c80da9fcca 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::BinOp; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::abi::{self, Align, Float, HasDataLayout, Primitive, Size}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use tracing::debug; @@ -20,7 +20,7 @@ use tracing::debug; use crate::abi::{Abi, FnAbi, FnAbiLlvmExt, LlvmType, PassMode}; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::llvm; +use crate::llvm::{self, Metadata}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::va_arg::emit_va_arg; @@ -148,7 +148,7 @@ fn get_simple_intrinsic<'ll>( Some(cx.get_intrinsic(llvm_name)) } -impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { +impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, @@ -187,9 +187,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { Some(instance), ) } - sym::likely => { - self.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(true)]) - } + sym::likely => self.expect(args[0].immediate(), true), sym::is_val_statically_known => { let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx); let kind = self.type_kind(intrinsic_type); @@ -210,8 +208,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.const_bool(false) } } - sym::unlikely => self - .call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]), + sym::unlikely => self.expect(args[0].immediate(), false), sym::select_unpredictable => { let cond = args[0].immediate(); assert_eq!(args[1].layout, args[2].layout); @@ -333,15 +330,12 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::prefetch_write_instruction => (1, 0), _ => bug!(), }; - self.call_intrinsic( - "llvm.prefetch", - &[ - args[0].immediate(), - self.const_i32(rw), - args[1].immediate(), - self.const_i32(cache_type), - ], - ) + self.call_intrinsic("llvm.prefetch", &[ + args[0].immediate(), + self.const_i32(rw), + args[1].immediate(), + self.const_i32(cache_type), + ]) } sym::ctlz | sym::ctlz_nonzero @@ -359,10 +353,10 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { Some((width, signed)) => match name { sym::ctlz | sym::cttz => { let y = self.const_bool(false); - let ret = self.call_intrinsic( - &format!("llvm.{name}.i{width}"), - &[args[0].immediate(), y], - ); + let ret = self.call_intrinsic(&format!("llvm.{name}.i{width}"), &[ + args[0].immediate(), + y, + ]); self.intcast(ret, llret_ty, false) } @@ -379,26 +373,24 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.intcast(ret, llret_ty, false) } sym::ctpop => { - let ret = self.call_intrinsic( - &format!("llvm.ctpop.i{width}"), - &[args[0].immediate()], - ); + let ret = self.call_intrinsic(&format!("llvm.ctpop.i{width}"), &[args + [0] + .immediate()]); self.intcast(ret, llret_ty, false) } sym::bswap => { if width == 8 { args[0].immediate() // byte swap a u8/i8 is just a no-op } else { - self.call_intrinsic( - &format!("llvm.bswap.i{width}"), - &[args[0].immediate()], - ) + self.call_intrinsic(&format!("llvm.bswap.i{width}"), &[ + args[0].immediate() + ]) } } - sym::bitreverse => self.call_intrinsic( - &format!("llvm.bitreverse.i{width}"), - &[args[0].immediate()], - ), + sym::bitreverse => self + .call_intrinsic(&format!("llvm.bitreverse.i{width}"), &[ + args[0].immediate() + ]), sym::rotate_left | sym::rotate_right => { let is_left = name == sym::rotate_left; let val = args[0].immediate(); @@ -407,7 +399,8 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { let llvm_name = &format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width); - // llvm expects shift to be the same type as the values, but rust always uses `u32` + // llvm expects shift to be the same type as the values, but rust + // always uses `u32`. let raw_shift = self.intcast(raw_shift, self.val_ty(val), false); self.call_intrinsic(llvm_name, &[val, val, raw_shift]) @@ -473,10 +466,11 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::compare_bytes => { // Here we assume that the `memcmp` provided by the target is a NOP for size 0. - let cmp = self.call_intrinsic( - "memcmp", - &[args[0].immediate(), args[1].immediate(), args[2].immediate()], - ); + let cmp = self.call_intrinsic("memcmp", &[ + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ]); // Some targets have `memcmp` returning `i16`, but the intrinsic is always `i32`. self.sext(cmp, self.type_ix(32)) } @@ -576,6 +570,8 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { span, ) { Ok(llval) => llval, + // If there was an error, just skip this invocation... we'll abort compilation + // anyway, but we can keep codegen'ing to find more errors. Err(()) => return Ok(()), } } @@ -604,16 +600,23 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } fn assume(&mut self, val: Self::Value) { - self.call_intrinsic("llvm.assume", &[val]); + if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No { + self.call_intrinsic("llvm.assume", &[val]); + } } fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value { - self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)]) + if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No { + self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)]) + } else { + cond + } } - fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value { + fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value { // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time // optimization pass replaces calls to this intrinsic with code to test type membership. + let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) }; self.call_intrinsic("llvm.type.test", &[pointer, typeid]) } @@ -621,8 +624,9 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { &mut self, llvtable: &'ll Value, vtable_byte_offset: u64, - typeid: &'ll Value, + typeid: &'ll Metadata, ) -> Self::Value { + let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) }; let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32); let type_checked_load = self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]); @@ -1210,17 +1214,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if let Some(cmp_op) = comparison { let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); require!( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty } @@ -1246,14 +1247,21 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let n = idx.len() as u64; let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); - require!( - out_len == n, - InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len } - ); - require!( - in_elem == out_ty, - InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty } - ); + require!(out_len == n, InvalidMonomorphization::ReturnLength { + span, + name, + in_len: n, + ret_ty, + out_len + }); + require!(in_elem == out_ty, InvalidMonomorphization::ReturnElement { + span, + name, + in_elem, + in_ty, + ret_ty, + out_ty + }); let total_len = in_len * 2; @@ -1287,94 +1295,73 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } if name == sym::simd_shuffle { - // Make sure this is actually an array or SIMD vector, since typeck only checks the length-suffixed - // version of this intrinsic. + // Make sure this is actually a SIMD vector. let idx_ty = args[2].layout.ty; - let n: u64 = match idx_ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { - len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( - || span_bug!(span, "could not evaluate shuffle index array length"), - ) - } - _ if idx_ty.is_simd() - && matches!( - idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), - ty::Uint(ty::UintTy::U32) - ) => - { - idx_ty.simd_size_and_type(bx.cx.tcx).0 - } - _ => return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }), + let n: u64 = if idx_ty.is_simd() + && matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32)) + { + idx_ty.simd_size_and_type(bx.cx.tcx).0 + } else { + return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }) }; let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); - require!( - out_len == n, - InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len } - ); - require!( - in_elem == out_ty, - InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty } - ); + require!(out_len == n, InvalidMonomorphization::ReturnLength { + span, + name, + in_len: n, + ret_ty, + out_len + }); + require!(in_elem == out_ty, InvalidMonomorphization::ReturnElement { + span, + name, + in_elem, + in_ty, + ret_ty, + out_ty + }); let total_len = u128::from(in_len) * 2; - let vector = args[2].immediate(); - - let indices: Option> = (0..n) - .map(|i| { - let arg_idx = i; - let val = bx.const_get_elt(vector, i as u64); - match bx.const_to_opt_u128(val, true) { - None => { - bug!("typeck should have already ensured that these are const") - } - Some(idx) if idx >= total_len => { - bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { - span, - name, - arg_idx, - total_len, - }); - None - } - Some(idx) => Some(bx.const_i32(idx as i32)), - } - }) - .collect(); - let Some(indices) = indices else { - return Ok(bx.const_null(llret_ty)); - }; + // Check that the indices are in-bounds. + let indices = args[2].immediate(); + for i in 0..n { + let val = bx.const_get_elt(indices, i as u64); + let idx = bx + .const_to_opt_u128(val, true) + .unwrap_or_else(|| bug!("typeck should have already ensured that these are const")); + if idx >= total_len { + return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { + span, + name, + arg_idx: i, + total_len, + }); + } + } - return Ok(bx.shuffle_vector( - args[0].immediate(), - args[1].immediate(), - bx.const_vector(&indices), - )); + return Ok(bx.shuffle_vector(args[0].immediate(), args[1].immediate(), indices)); } if name == sym::simd_insert { - require!( - in_elem == arg_tys[2], - InvalidMonomorphization::InsertedType { - span, - name, - in_elem, - in_ty, - out_ty: arg_tys[2] - } - ); + require!(in_elem == arg_tys[2], InvalidMonomorphization::InsertedType { + span, + name, + in_elem, + in_ty, + out_ty: arg_tys[2] + }); let idx = bx .const_to_opt_u128(args[1].immediate(), false) .expect("typeck should have ensure that this is a const"); if idx >= in_len.into() { - bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { + return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { span, name, arg_idx: 1, total_len: in_len.into(), }); - return Ok(bx.const_null(llret_ty)); } return Ok(bx.insert_element( args[0].immediate(), @@ -1383,21 +1370,23 @@ fn generic_simd_intrinsic<'ll, 'tcx>( )); } if name == sym::simd_extract { - require!( - ret_ty == in_elem, - InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } - ); + require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType { + span, + name, + in_elem, + in_ty, + ret_ty + }); let idx = bx .const_to_opt_u128(args[1].immediate(), false) .expect("typeck should have ensure that this is a const"); if idx >= in_len.into() { - bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { + return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { span, name, arg_idx: 1, total_len: in_len.into(), }); - return Ok(bx.const_null(llret_ty)); } return Ok(bx.extract_element(args[0].immediate(), bx.const_i32(idx as i32))); } @@ -1406,10 +1395,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let m_elem_ty = in_elem; let m_len = in_len; let (v_len, _) = require_simd!(arg_tys[1], SimdArgument); - require!( - m_len == v_len, - InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } - ); + require!(m_len == v_len, InvalidMonomorphization::MismatchedLengths { + span, + name, + m_len, + v_len + }); match m_elem_ty.kind() { ty::Int(_) => {} _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }), @@ -1636,34 +1627,30 @@ fn generic_simd_intrinsic<'ll, 'tcx>( require_simd!(ret_ty, SimdReturn); // Of the same length: - require!( - in_len == out_len, - InvalidMonomorphization::SecondArgumentLength { - span, - name, - in_len, - in_ty, - arg_ty: arg_tys[1], - out_len - } - ); - require!( - in_len == out_len2, - InvalidMonomorphization::ThirdArgumentLength { - span, - name, - in_len, - in_ty, - arg_ty: arg_tys[2], - out_len: out_len2 - } - ); + require!(in_len == out_len, InvalidMonomorphization::SecondArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[1], + out_len + }); + require!(in_len == out_len2, InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[2], + out_len: out_len2 + }); // The return type must match the first argument type - require!( - ret_ty == in_ty, - InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty } - ); + require!(ret_ty == in_ty, InvalidMonomorphization::ExpectedReturnType { + span, + name, + in_ty, + ret_ty + }); require!( matches!( @@ -1754,23 +1741,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>( require_simd!(ret_ty, SimdReturn); // Of the same length: - require!( - values_len == mask_len, - InvalidMonomorphization::ThirdArgumentLength { - span, - name, - in_len: mask_len, - in_ty: mask_ty, - arg_ty: values_ty, - out_len: values_len - } - ); + require!(values_len == mask_len, InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len: mask_len, + in_ty: mask_ty, + arg_ty: values_ty, + out_len: values_len + }); // The return type must match the last argument type - require!( - ret_ty == values_ty, - InvalidMonomorphization::ExpectedReturnType { span, name, in_ty: values_ty, ret_ty } - ); + require!(ret_ty == values_ty, InvalidMonomorphization::ExpectedReturnType { + span, + name, + in_ty: values_ty, + ret_ty + }); require!( matches!( @@ -1852,23 +1838,21 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let (values_len, values_elem) = require_simd!(values_ty, SimdThird); // Of the same length: - require!( - values_len == mask_len, - InvalidMonomorphization::ThirdArgumentLength { - span, - name, - in_len: mask_len, - in_ty: mask_ty, - arg_ty: values_ty, - out_len: values_len - } - ); + require!(values_len == mask_len, InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len: mask_len, + in_ty: mask_ty, + arg_ty: values_ty, + out_len: values_len + }); // The second argument must be a mutable pointer type matching the element type require!( matches!( *pointer_ty.kind(), - ty::RawPtr(p_ty, p_mutbl) if p_ty == values_elem && p_ty.kind() == values_elem.kind() && p_mutbl.is_mut() + ty::RawPtr(p_ty, p_mutbl) + if p_ty == values_elem && p_ty.kind() == values_elem.kind() && p_mutbl.is_mut() ), InvalidMonomorphization::ExpectedElementType { span, @@ -1940,28 +1924,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let (element_len2, element_ty2) = require_simd!(arg_tys[2], SimdThird); // Of the same length: - require!( - in_len == element_len1, - InvalidMonomorphization::SecondArgumentLength { - span, - name, - in_len, - in_ty, - arg_ty: arg_tys[1], - out_len: element_len1 - } - ); - require!( - in_len == element_len2, - InvalidMonomorphization::ThirdArgumentLength { - span, - name, - in_len, - in_ty, - arg_ty: arg_tys[2], - out_len: element_len2 - } - ); + require!(in_len == element_len1, InvalidMonomorphization::SecondArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[1], + out_len: element_len1 + }); + require!(in_len == element_len2, InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[2], + out_len: element_len2 + }); require!( matches!( @@ -2035,10 +2013,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>( ($name:ident : $integer_reduce:ident, $float_reduce:ident, $ordered:expr, $op:ident, $identity:expr) => { if name == sym::$name { - require!( - ret_ty == in_elem, - InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } - ); + require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType { + span, + name, + in_elem, + in_ty, + ret_ty + }); return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => { let r = bx.$integer_reduce(args[0].immediate()); @@ -2087,14 +2068,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }; } - arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, 0.0); + arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, -0.0); arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0); arith_red!( simd_reduce_add_unordered: vector_reduce_add, vector_reduce_fadd_reassoc, false, add, - 0.0 + -0.0 ); arith_red!( simd_reduce_mul_unordered: vector_reduce_mul, @@ -2107,10 +2088,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>( macro_rules! minmax_red { ($name:ident: $int_red:ident, $float_red:ident) => { if name == sym::$name { - require!( - ret_ty == in_elem, - InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } - ); + require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType { + span, + name, + in_elem, + in_ty, + ret_ty + }); return match in_elem.kind() { ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)), ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)), @@ -2135,10 +2119,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>( ($name:ident : $red:ident, $boolean:expr) => { if name == sym::$name { let input = if !$boolean { - require!( - ret_ty == in_elem, - InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } - ); + require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType { + span, + name, + in_elem, + in_ty, + ret_ty + }); args[0].immediate() } else { match in_elem.kind() { @@ -2184,27 +2171,25 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_cast_ptr { let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); match in_elem.kind() { ty::RawPtr(p_ty, _) => { let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!( - metadata.is_unit(), - InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem } - ); + require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + span, + name, + ty: in_elem + }); } _ => { return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem }) @@ -2215,10 +2200,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!( - metadata.is_unit(), - InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem } - ); + require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + span, + name, + ty: out_elem + }); } _ => { return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem }) @@ -2230,17 +2216,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_expose_provenance { let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); match in_elem.kind() { ty::RawPtr(_, _) => {} @@ -2258,17 +2241,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_with_exposed_provenance { let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); match in_elem.kind() { ty::Uint(ty::UintTy::Usize) => {} @@ -2286,17 +2266,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_cast || name == sym::simd_as { let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn); - require!( - in_len == out_len, - InvalidMonomorphization::ReturnLengthInputType { - span, - name, - in_len, - in_ty, - ret_ty, - out_len - } - ); + require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + }); // casting cares about nominal type, not just structural type if in_elem == out_elem { return Ok(args[0].immediate()); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 6a303e1e6024b..bdfc0f626f801 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -6,12 +6,12 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(unsafe_extern_blocks))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(exact_size_is_empty)] #![feature(extern_types)] +#![feature(file_buffered)] #![feature(hash_raw_entry)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] @@ -42,8 +42,8 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; -use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; use rustc_session::Session; +use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; use rustc_span::symbol::Symbol; mod back { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 138cc3219aa08..9aabfd794bad7 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -5,13 +5,13 @@ use std::marker::PhantomData; use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t}; +use super::RustString; use super::debuginfo::{ DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DILocation, DINameSpace, DISPFlags, DIScope, DISubprogram, DISubrange, DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind, }; -use super::RustString; pub type Bool = c_uint; @@ -220,17 +220,18 @@ pub enum IntPredicate { impl IntPredicate { pub fn from_generic(intpre: rustc_codegen_ssa::common::IntPredicate) -> Self { + use rustc_codegen_ssa::common::IntPredicate as Common; match intpre { - rustc_codegen_ssa::common::IntPredicate::IntEQ => IntPredicate::IntEQ, - rustc_codegen_ssa::common::IntPredicate::IntNE => IntPredicate::IntNE, - rustc_codegen_ssa::common::IntPredicate::IntUGT => IntPredicate::IntUGT, - rustc_codegen_ssa::common::IntPredicate::IntUGE => IntPredicate::IntUGE, - rustc_codegen_ssa::common::IntPredicate::IntULT => IntPredicate::IntULT, - rustc_codegen_ssa::common::IntPredicate::IntULE => IntPredicate::IntULE, - rustc_codegen_ssa::common::IntPredicate::IntSGT => IntPredicate::IntSGT, - rustc_codegen_ssa::common::IntPredicate::IntSGE => IntPredicate::IntSGE, - rustc_codegen_ssa::common::IntPredicate::IntSLT => IntPredicate::IntSLT, - rustc_codegen_ssa::common::IntPredicate::IntSLE => IntPredicate::IntSLE, + Common::IntEQ => Self::IntEQ, + Common::IntNE => Self::IntNE, + Common::IntUGT => Self::IntUGT, + Common::IntUGE => Self::IntUGE, + Common::IntULT => Self::IntULT, + Common::IntULE => Self::IntULE, + Common::IntSGT => Self::IntSGT, + Common::IntSGE => Self::IntSGE, + Common::IntSLT => Self::IntSLT, + Common::IntSLE => Self::IntSLE, } } } @@ -259,27 +260,24 @@ pub enum RealPredicate { impl RealPredicate { pub fn from_generic(realp: rustc_codegen_ssa::common::RealPredicate) -> Self { + use rustc_codegen_ssa::common::RealPredicate as Common; match realp { - rustc_codegen_ssa::common::RealPredicate::RealPredicateFalse => { - RealPredicate::RealPredicateFalse - } - rustc_codegen_ssa::common::RealPredicate::RealOEQ => RealPredicate::RealOEQ, - rustc_codegen_ssa::common::RealPredicate::RealOGT => RealPredicate::RealOGT, - rustc_codegen_ssa::common::RealPredicate::RealOGE => RealPredicate::RealOGE, - rustc_codegen_ssa::common::RealPredicate::RealOLT => RealPredicate::RealOLT, - rustc_codegen_ssa::common::RealPredicate::RealOLE => RealPredicate::RealOLE, - rustc_codegen_ssa::common::RealPredicate::RealONE => RealPredicate::RealONE, - rustc_codegen_ssa::common::RealPredicate::RealORD => RealPredicate::RealORD, - rustc_codegen_ssa::common::RealPredicate::RealUNO => RealPredicate::RealUNO, - rustc_codegen_ssa::common::RealPredicate::RealUEQ => RealPredicate::RealUEQ, - rustc_codegen_ssa::common::RealPredicate::RealUGT => RealPredicate::RealUGT, - rustc_codegen_ssa::common::RealPredicate::RealUGE => RealPredicate::RealUGE, - rustc_codegen_ssa::common::RealPredicate::RealULT => RealPredicate::RealULT, - rustc_codegen_ssa::common::RealPredicate::RealULE => RealPredicate::RealULE, - rustc_codegen_ssa::common::RealPredicate::RealUNE => RealPredicate::RealUNE, - rustc_codegen_ssa::common::RealPredicate::RealPredicateTrue => { - RealPredicate::RealPredicateTrue - } + Common::RealPredicateFalse => Self::RealPredicateFalse, + Common::RealOEQ => Self::RealOEQ, + Common::RealOGT => Self::RealOGT, + Common::RealOGE => Self::RealOGE, + Common::RealOLT => Self::RealOLT, + Common::RealOLE => Self::RealOLE, + Common::RealONE => Self::RealONE, + Common::RealORD => Self::RealORD, + Common::RealUNO => Self::RealUNO, + Common::RealUEQ => Self::RealUEQ, + Common::RealUGT => Self::RealUGT, + Common::RealUGE => Self::RealUGE, + Common::RealULT => Self::RealULT, + Common::RealULE => Self::RealULE, + Common::RealUNE => Self::RealUNE, + Common::RealPredicateTrue => Self::RealPredicateTrue, } } } @@ -311,26 +309,27 @@ pub enum TypeKind { impl TypeKind { pub fn to_generic(self) -> rustc_codegen_ssa::common::TypeKind { + use rustc_codegen_ssa::common::TypeKind as Common; match self { - TypeKind::Void => rustc_codegen_ssa::common::TypeKind::Void, - TypeKind::Half => rustc_codegen_ssa::common::TypeKind::Half, - TypeKind::Float => rustc_codegen_ssa::common::TypeKind::Float, - TypeKind::Double => rustc_codegen_ssa::common::TypeKind::Double, - TypeKind::X86_FP80 => rustc_codegen_ssa::common::TypeKind::X86_FP80, - TypeKind::FP128 => rustc_codegen_ssa::common::TypeKind::FP128, - TypeKind::PPC_FP128 => rustc_codegen_ssa::common::TypeKind::PPC_FP128, - TypeKind::Label => rustc_codegen_ssa::common::TypeKind::Label, - TypeKind::Integer => rustc_codegen_ssa::common::TypeKind::Integer, - TypeKind::Function => rustc_codegen_ssa::common::TypeKind::Function, - TypeKind::Struct => rustc_codegen_ssa::common::TypeKind::Struct, - TypeKind::Array => rustc_codegen_ssa::common::TypeKind::Array, - TypeKind::Pointer => rustc_codegen_ssa::common::TypeKind::Pointer, - TypeKind::Vector => rustc_codegen_ssa::common::TypeKind::Vector, - TypeKind::Metadata => rustc_codegen_ssa::common::TypeKind::Metadata, - TypeKind::Token => rustc_codegen_ssa::common::TypeKind::Token, - TypeKind::ScalableVector => rustc_codegen_ssa::common::TypeKind::ScalableVector, - TypeKind::BFloat => rustc_codegen_ssa::common::TypeKind::BFloat, - TypeKind::X86_AMX => rustc_codegen_ssa::common::TypeKind::X86_AMX, + Self::Void => Common::Void, + Self::Half => Common::Half, + Self::Float => Common::Float, + Self::Double => Common::Double, + Self::X86_FP80 => Common::X86_FP80, + Self::FP128 => Common::FP128, + Self::PPC_FP128 => Common::PPC_FP128, + Self::Label => Common::Label, + Self::Integer => Common::Integer, + Self::Function => Common::Function, + Self::Struct => Common::Struct, + Self::Array => Common::Array, + Self::Pointer => Common::Pointer, + Self::Vector => Common::Vector, + Self::Metadata => Common::Metadata, + Self::Token => Common::Token, + Self::ScalableVector => Common::ScalableVector, + Self::BFloat => Common::BFloat, + Self::X86_AMX => Common::X86_AMX, } } } @@ -354,18 +353,19 @@ pub enum AtomicRmwBinOp { impl AtomicRmwBinOp { pub fn from_generic(op: rustc_codegen_ssa::common::AtomicRmwBinOp) -> Self { + use rustc_codegen_ssa::common::AtomicRmwBinOp as Common; match op { - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicXchg => AtomicRmwBinOp::AtomicXchg, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicAdd => AtomicRmwBinOp::AtomicAdd, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicSub => AtomicRmwBinOp::AtomicSub, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicAnd => AtomicRmwBinOp::AtomicAnd, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicNand => AtomicRmwBinOp::AtomicNand, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicOr => AtomicRmwBinOp::AtomicOr, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicXor => AtomicRmwBinOp::AtomicXor, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicMax => AtomicRmwBinOp::AtomicMax, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicMin => AtomicRmwBinOp::AtomicMin, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicUMax => AtomicRmwBinOp::AtomicUMax, - rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicUMin => AtomicRmwBinOp::AtomicUMin, + Common::AtomicXchg => Self::AtomicXchg, + Common::AtomicAdd => Self::AtomicAdd, + Common::AtomicSub => Self::AtomicSub, + Common::AtomicAnd => Self::AtomicAnd, + Common::AtomicNand => Self::AtomicNand, + Common::AtomicOr => Self::AtomicOr, + Common::AtomicXor => Self::AtomicXor, + Common::AtomicMax => Self::AtomicMax, + Common::AtomicMin => Self::AtomicMin, + Common::AtomicUMax => Self::AtomicUMax, + Common::AtomicUMin => Self::AtomicUMin, } } } @@ -387,17 +387,14 @@ pub enum AtomicOrdering { impl AtomicOrdering { pub fn from_generic(ao: rustc_codegen_ssa::common::AtomicOrdering) -> Self { + use rustc_codegen_ssa::common::AtomicOrdering as Common; match ao { - rustc_codegen_ssa::common::AtomicOrdering::Unordered => AtomicOrdering::Unordered, - rustc_codegen_ssa::common::AtomicOrdering::Relaxed => AtomicOrdering::Monotonic, - rustc_codegen_ssa::common::AtomicOrdering::Acquire => AtomicOrdering::Acquire, - rustc_codegen_ssa::common::AtomicOrdering::Release => AtomicOrdering::Release, - rustc_codegen_ssa::common::AtomicOrdering::AcquireRelease => { - AtomicOrdering::AcquireRelease - } - rustc_codegen_ssa::common::AtomicOrdering::SequentiallyConsistent => { - AtomicOrdering::SequentiallyConsistent - } + Common::Unordered => Self::Unordered, + Common::Relaxed => Self::Monotonic, + Common::Acquire => Self::Acquire, + Common::Release => Self::Release, + Common::AcquireRelease => Self::AcquireRelease, + Common::SequentiallyConsistent => Self::SequentiallyConsistent, } } } @@ -563,13 +560,11 @@ pub enum ArchiveKind { K_AIXBIG, } -// LLVMRustThinLTOData unsafe extern "C" { + // LLVMRustThinLTOData pub type ThinLTOData; -} -// LLVMRustThinLTOBuffer -unsafe extern "C" { + // LLVMRustThinLTOBuffer pub type ThinLTOBuffer; } @@ -633,26 +628,12 @@ struct InvariantOpaque<'a> { // Opaque pointer types unsafe extern "C" { pub type Module; -} -unsafe extern "C" { pub type Context; -} -unsafe extern "C" { pub type Type; -} -unsafe extern "C" { pub type Value; -} -unsafe extern "C" { pub type ConstantInt; -} -unsafe extern "C" { pub type Attribute; -} -unsafe extern "C" { pub type Metadata; -} -unsafe extern "C" { pub type BasicBlock; } #[repr(C)] @@ -661,11 +642,7 @@ pub struct Builder<'a>(InvariantOpaque<'a>); pub struct PassManager<'a>(InvariantOpaque<'a>); unsafe extern "C" { pub type Pass; -} -unsafe extern "C" { pub type TargetMachine; -} -unsafe extern "C" { pub type Archive; } #[repr(C)] @@ -674,11 +651,7 @@ pub struct ArchiveIterator<'a>(InvariantOpaque<'a>); pub struct ArchiveChild<'a>(InvariantOpaque<'a>); unsafe extern "C" { pub type Twine; -} -unsafe extern "C" { pub type DiagnosticInfo; -} -unsafe extern "C" { pub type SMDiagnostic; } #[repr(C)] @@ -912,17 +885,7 @@ unsafe extern "C" { pub fn LLVMGetPoison(Ty: &Type) -> &Value; // Operations on metadata - // FIXME: deprecated, replace with LLVMMDStringInContext2 - pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value; - pub fn LLVMMDStringInContext2(C: &Context, Str: *const c_char, SLen: size_t) -> &Metadata; - - // FIXME: deprecated, replace with LLVMMDNodeInContext2 - pub fn LLVMMDNodeInContext<'a>( - C: &'a Context, - Vals: *const &'a Value, - Count: c_uint, - ) -> &'a Value; pub fn LLVMMDNodeInContext2<'a>( C: &'a Context, Vals: *const &'a Metadata, @@ -974,6 +937,7 @@ unsafe extern "C" { pub fn LLVMGetAlignment(Global: &Value) -> c_uint; pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass); + pub fn LLVMGlobalGetValueType(Global: &Value) -> &Type; // Operations on global variables pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; @@ -1040,7 +1004,7 @@ unsafe extern "C" { pub fn LLVMDisposeBuilder<'a>(Builder: &'a mut Builder<'a>); // Metadata - pub fn LLVMSetCurrentDebugLocation2<'a>(Builder: &Builder<'a>, Loc: &'a Metadata); + pub fn LLVMSetCurrentDebugLocation2<'a>(Builder: &Builder<'a>, Loc: *const Metadata); // Terminators pub fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; @@ -2176,7 +2140,8 @@ unsafe extern "C" { pub fn LLVMRustGetHostCPUName(len: *mut usize) -> *const c_char; - // This function makes copies of pointed to data, so the data's lifetime may end after this function returns + // This function makes copies of pointed to data, so the data's lifetime may end after this + // function returns. pub fn LLVMRustCreateTargetMachine( Triple: *const c_char, CPU: *const c_char, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 6b2a47c493f6c..21caaaec8449e 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_char, c_void, CStr, CString}; +use std::ffi::{CStr, CString, c_char, c_void}; use std::fmt::Write; use std::path::Path; use std::sync::Once; @@ -11,10 +11,10 @@ use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::unord::UnordSet; use rustc_fs_util::path_to_c_string; use rustc_middle::bug; -use rustc_session::config::{PrintKind, PrintRequest}; use rustc_session::Session; +use rustc_session::config::{PrintKind, PrintRequest}; use rustc_span::symbol::Symbol; -use rustc_target::spec::{MergeFunctions, PanicStrategy}; +use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; use crate::back::write::create_informational_target_machine; @@ -125,6 +125,18 @@ unsafe fn configure_llvm(sess: &Session) { for arg in sess_args { add(&(*arg), true); } + + match ( + sess.opts.unstable_opts.small_data_threshold, + sess.target.small_data_threshold_support(), + ) { + // Set up the small-data optimization limit for architectures that use + // an LLVM argument to control this. + (Some(threshold), SmallDataThresholdSupport::LlvmArg(arg)) => { + add(&format!("--{arg}={threshold}"), false) + } + _ => (), + }; } if sess.opts.unstable_opts.llvm_time_trace { @@ -205,10 +217,10 @@ impl<'a> IntoIterator for LLVMFeature<'a> { // where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. // // Check the current rustc fork of LLVM in the repo at https://github.com/rust-lang/llvm-project/. -// The commit in use can be found via the `llvm-project` submodule in https://github.com/rust-lang/rust/tree/master/src -// Though note that Rust can also be build with an external precompiled version of LLVM -// which might lead to failures if the oldest tested / supported LLVM version -// doesn't yet support the relevant intrinsics +// The commit in use can be found via the `llvm-project` submodule in +// https://github.com/rust-lang/rust/tree/master/src Though note that Rust can also be build with +// an external precompiled version of LLVM which might lead to failures if the oldest tested / +// supported LLVM version doesn't yet support the relevant intrinsics. pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option> { let arch = if sess.target.arch == "x86_64" { "x86" @@ -248,28 +260,14 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("fp16fml")), ("aarch64", "fp16") => Some(LLVMFeature::new("fullfp16")), // Filter out features that are not supported by the current LLVM version - ("aarch64", "faminmax") if get_version().0 < 18 => None, - ("aarch64", "fp8") if get_version().0 < 18 => None, - ("aarch64", "fp8dot2") if get_version().0 < 18 => None, - ("aarch64", "fp8dot4") if get_version().0 < 18 => None, - ("aarch64", "fp8fma") if get_version().0 < 18 => None, ("aarch64", "fpmr") if get_version().0 != 18 => None, - ("aarch64", "lut") if get_version().0 < 18 => None, - ("aarch64", "sme-f8f16") if get_version().0 < 18 => None, - ("aarch64", "sme-f8f32") if get_version().0 < 18 => None, - ("aarch64", "sme-fa64") if get_version().0 < 18 => None, - ("aarch64", "sme-lutv2") if get_version().0 < 18 => None, - ("aarch64", "ssve-fp8dot2") if get_version().0 < 18 => None, - ("aarch64", "ssve-fp8dot4") if get_version().0 < 18 => None, - ("aarch64", "ssve-fp8fma") if get_version().0 < 18 => None, - ("aarch64", "v9.5a") if get_version().0 < 18 => None, - // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called - // `fast-unaligned-access`. In LLVM 19, it was split back out. + // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single + // feature called `fast-unaligned-access`. In LLVM 19, it was split back out. ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => { Some(LLVMFeature::new("fast-unaligned-access")) } - // For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled. - ("x86", s) if get_version().0 >= 18 && s.starts_with("avx512") => { + // Enable the evex512 target feature if an avx512 target feature is enabled. + ("x86", s) if s.starts_with("avx512") => { Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512"))) } (_, s) => Some(LLVMFeature::new(s)), @@ -292,7 +290,7 @@ pub(crate) fn check_tied_features( } } } - return None; + None } /// Used to generate cfg variables and apply features @@ -355,9 +353,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { None } }) - .filter(|feature| { - RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature)) - }) + .filter(|feature| features.contains(&Symbol::intern(feature))) .map(|feature| Symbol::intern(feature)) .collect() } @@ -412,7 +408,8 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach .supported_target_features() .iter() .filter_map(|(feature, _gate, _implied)| { - // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. + // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these + // strings. let llvm_feature = to_llvm_features(sess, *feature)?.llvm_feature_name; let desc = match llvm_target_features.binary_search_by_key(&llvm_feature, |(f, _d)| f).ok() { @@ -579,7 +576,6 @@ pub(crate) fn global_llvm_features( // -Ctarget-features if !only_base_features { let supported_features = sess.target.supported_target_features(); - let (llvm_major, _, _) = get_version(); let mut featsmap = FxHashMap::default(); // insert implied features @@ -656,12 +652,6 @@ pub(crate) fn global_llvm_features( return None; } - // if the target-feature is "backchain" and LLVM version is greater than 18 - // then we also need to add "+backchain" to the target-features attribute. - // otherwise, we will only add the naked `backchain` attribute to the attribute-group. - if feature == "backchain" && llvm_major < 18 { - return None; - } // ... otherwise though we run through `to_llvm_features` when // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index f1ef359594b4b..02e1995620bdb 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -14,7 +14,7 @@ use crate::errors::SymbolAlreadyDefined; use crate::type_of::LayoutLlvmExt; use crate::{base, llvm}; -impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> { +impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { fn predefine_static( &self, def_id: DefId, @@ -24,8 +24,8 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> { ) { let instance = Instance::mono(self.tcx, def_id); let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() }; - // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure out - // the llvm type from the actual evaluated initializer. + // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure + // out the llvm type from the actual evaluated initializer. let ty = if nested { self.tcx.types.unit } else { diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index ec1e2cb809421..f1efc7a3dacb8 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -13,7 +13,7 @@ use rustc_target::abi::{AddressSpace, Align, Integer, Size}; use crate::abi::{FnAbiLlvmExt, LlvmType}; use crate::context::CodegenCx; pub(crate) use crate::llvm::Type; -use crate::llvm::{Bool, False, True}; +use crate::llvm::{Bool, False, Metadata, True}; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use crate::{common, llvm}; @@ -141,7 +141,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } -impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn type_i8(&self) -> &'ll Type { unsafe { llvm::LLVMInt8TypeInContext(self.llcx) } } @@ -245,7 +245,7 @@ impl Type { } } -impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn backend_type(&self, layout: TyAndLayout<'tcx>) -> &'ll Type { layout.llvm_type(self) } @@ -280,46 +280,34 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } -impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn add_type_metadata(&self, function: &'ll Value, typeid: String) { let typeid_metadata = self.typeid_metadata(typeid).unwrap(); - let v = [self.const_usize(0), typeid_metadata]; unsafe { + let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMRustGlobalAddMetadata( function, llvm::MD_type as c_uint, - llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext( - self.llcx, - v.as_ptr(), - v.len() as c_uint, - )), + llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), ) } } fn set_type_metadata(&self, function: &'ll Value, typeid: String) { let typeid_metadata = self.typeid_metadata(typeid).unwrap(); - let v = [self.const_usize(0), typeid_metadata]; unsafe { + let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMGlobalSetMetadata( function, llvm::MD_type as c_uint, - llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext( - self.llcx, - v.as_ptr(), - v.len() as c_uint, - )), + llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), ) } } - fn typeid_metadata(&self, typeid: String) -> Option<&'ll Value> { + fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { Some(unsafe { - llvm::LLVMMDStringInContext( - self.llcx, - typeid.as_ptr() as *const c_char, - typeid.len() as c_uint, - ) + llvm::LLVMMDStringInContext2(self.llcx, typeid.as_ptr() as *const c_char, typeid.len()) }) } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 94e77c5bd70d6..f12b94d5887ea 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1,8 +1,8 @@ use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::OperandRef; -use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods, ConstMethods}; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods}; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_target::abi::{Align, Endian, HasDataLayout, Size}; use crate::builder::Builder; diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 8a6a2acd87d44..9091602d75b71 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -132,7 +132,7 @@ codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of ` codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}` -codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` +codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be a SIMD vector of `u32`, got `{$ty}` codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}` diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 76a94de54339c..2f48c1fbf0d7d 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -6,9 +6,9 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use ar_archive_writer::{ - write_archive_to_stream, ArchiveKind, COFFShortExport, MachineTypes, NewArchiveMember, + ArchiveKind, COFFShortExport, MachineTypes, NewArchiveMember, write_archive_to_stream, }; -pub use ar_archive_writer::{ObjectReader, DEFAULT_OBJECT_READER}; +pub use ar_archive_writer::{DEFAULT_OBJECT_READER, ObjectReader}; use object::read::archive::ArchiveFile; use object::read::macho::FatArch; use rustc_data_structures::fx::FxIndexSet; @@ -157,7 +157,7 @@ pub trait ArchiveBuilderBuilder { } } -pub fn create_mingw_dll_import_lib( +fn create_mingw_dll_import_lib( sess: &Session, lib_name: &str, import_name_and_ordinal_vector: Vec<(String, Option)>, @@ -395,10 +395,10 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> { let member_path = archive_path.parent().unwrap().join(Path::new(&file_name)); self.entries.push((file_name.into_bytes(), ArchiveEntry::File(member_path))); } else { - self.entries.push(( - file_name.into_bytes(), - ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, - )); + self.entries.push((file_name.into_bytes(), ArchiveEntry::FromArchive { + archive_index, + file_range: entry.file_range(), + })); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 95c4af2e59ea9..b3c5b86ccf430 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -8,7 +8,7 @@ use std::{fmt, io, mem}; use rustc_target::spec::LldFlavor; #[derive(Clone)] -pub struct Command { +pub(crate) struct Command { program: Program, args: Vec, env: Vec<(OsString, OsString)>, @@ -23,15 +23,15 @@ enum Program { } impl Command { - pub fn new>(program: P) -> Command { + pub(crate) fn new>(program: P) -> Command { Command::_new(Program::Normal(program.as_ref().to_owned())) } - pub fn bat_script>(program: P) -> Command { + pub(crate) fn bat_script>(program: P) -> Command { Command::_new(Program::CmdBatScript(program.as_ref().to_owned())) } - pub fn lld>(program: P, flavor: LldFlavor) -> Command { + pub(crate) fn lld>(program: P, flavor: LldFlavor) -> Command { Command::_new(Program::Lld(program.as_ref().to_owned(), flavor)) } @@ -39,12 +39,12 @@ impl Command { Command { program, args: Vec::new(), env: Vec::new(), env_remove: Vec::new() } } - pub fn arg>(&mut self, arg: P) -> &mut Command { + pub(crate) fn arg>(&mut self, arg: P) -> &mut Command { self._arg(arg.as_ref()); self } - pub fn args(&mut self, args: I) -> &mut Command + pub(crate) fn args(&mut self, args: I) -> &mut Command where I: IntoIterator>, { @@ -58,7 +58,7 @@ impl Command { self.args.push(arg.to_owned()); } - pub fn env(&mut self, key: K, value: V) -> &mut Command + pub(crate) fn env(&mut self, key: K, value: V) -> &mut Command where K: AsRef, V: AsRef, @@ -71,7 +71,7 @@ impl Command { self.env.push((key.to_owned(), value.to_owned())); } - pub fn env_remove(&mut self, key: K) -> &mut Command + pub(crate) fn env_remove(&mut self, key: K) -> &mut Command where K: AsRef, { @@ -83,11 +83,11 @@ impl Command { self.env_remove.push(key.to_owned()); } - pub fn output(&mut self) -> io::Result { + pub(crate) fn output(&mut self) -> io::Result { self.command().output() } - pub fn command(&self) -> process::Command { + pub(crate) fn command(&self) -> process::Command { let mut ret = match self.program { Program::Normal(ref p) => process::Command::new(p), Program::CmdBatScript(ref p) => { @@ -111,17 +111,17 @@ impl Command { // extensions - pub fn get_args(&self) -> &[OsString] { + pub(crate) fn get_args(&self) -> &[OsString] { &self.args } - pub fn take_args(&mut self) -> Vec { + pub(crate) fn take_args(&mut self) -> Vec { mem::take(&mut self.args) } /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits, /// or `false` if we should attempt to spawn and see what the OS says. - pub fn very_likely_to_exceed_some_spawn_limit(&self) -> bool { + pub(crate) fn very_likely_to_exceed_some_spawn_limit(&self) -> bool { // We mostly only care about Windows in this method, on Unix the limits // can be gargantuan anyway so we're pretty unlikely to hit them if cfg!(unix) { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e8143b9a5f38f..69693230ce070 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,6 +1,6 @@ use std::collections::BTreeSet; use std::ffi::OsString; -use std::fs::{read, File, OpenOptions}; +use std::fs::{File, OpenOptions, read}; use std::io::{BufWriter, Write}; use std::ops::{ControlFlow, Deref}; use std::path::{Path, PathBuf}; @@ -18,7 +18,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME}; +use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs}; use rustc_middle::bug; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -34,7 +34,7 @@ use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. -use rustc_session::{filesearch, Session}; +use rustc_session::{Session, filesearch}; use rustc_span::symbol::Symbol; use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ @@ -48,11 +48,11 @@ use tracing::{debug, info, warn}; use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use super::command::Command; use super::linker::{self, Linker}; -use super::metadata::{create_wrapper_file, MetadataPosition}; +use super::metadata::{MetadataPosition, create_wrapper_file}; use super::rpath::{self, RPathConfig}; use crate::{ - common, errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, - NativeLib, + CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors, + looks_like_rust_object_file, }; pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { @@ -281,12 +281,10 @@ pub fn each_linked_rlib( let used_crate_source = &info.used_crate_source[&cnum]; if let Some((path, _)) = &used_crate_source.rlib { f(cnum, path); + } else if used_crate_source.rmeta.is_some() { + return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name }); } else { - if used_crate_source.rmeta.is_some() { - return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name }); - } else { - return Err(errors::LinkRlibError::NotFound { crate_name }); - } + return Err(errors::LinkRlibError::NotFound { crate_name }); } } Ok(()) @@ -438,7 +436,7 @@ fn link_rlib<'a>( ab.add_file(&lib) } - return Ok(ab); + Ok(ab) } /// Extract all symbols defined in raw-dylib libraries, collated by library name. @@ -628,12 +626,10 @@ fn link_staticlib( let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum]; if let Some((path, _)) = &used_crate_source.dylib { all_rust_dylibs.push(&**path); + } else if used_crate_source.rmeta.is_some() { + sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name }); } else { - if used_crate_source.rmeta.is_some() { - sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name }); - } else { - sess.dcx().emit_fatal(errors::LinkRlibError::NotFound { crate_name }); - } + sess.dcx().emit_fatal(errors::LinkRlibError::NotFound { crate_name }); } } @@ -1091,16 +1087,17 @@ fn link_natively( let strip = sess.opts.cg.strip; if sess.target.is_like_osx { + let stripcmd = "/usr/bin/strip"; match (strip, crate_type) { (Strip::Debuginfo, _) => { - strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-S")) + strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S")) } // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988) (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => { - strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-x")) + strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-x")) } (Strip::Symbols, _) => { - strip_symbols_with_external_utility(sess, "strip", out_filename, None) + strip_symbols_with_external_utility(sess, stripcmd, out_filename, None) } (Strip::None, _) => {} } @@ -1201,8 +1198,8 @@ fn escape_linker_output(s: &[u8], flavour: LinkerFlavor) -> String { #[cfg(windows)] mod win { use windows::Win32::Globalization::{ - GetLocaleInfoEx, MultiByteToWideChar, CP_OEMCP, LOCALE_IUSEUTF8LEGACYOEMCP, - LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_RETURN_NUMBER, MB_ERR_INVALID_CHARS, + CP_OEMCP, GetLocaleInfoEx, LOCALE_IUSEUTF8LEGACYOEMCP, LOCALE_NAME_SYSTEM_DEFAULT, + LOCALE_RETURN_NUMBER, MB_ERR_INVALID_CHARS, MultiByteToWideChar, }; /// Get the Windows system OEM code page. This is most notably the code page @@ -1319,7 +1316,7 @@ fn link_sanitizer_runtime( fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf { let path = sess.target_tlib_path.dir.join(filename); if path.exists() { - return sess.target_tlib_path.dir.clone(); + sess.target_tlib_path.dir.clone() } else { let default_sysroot = filesearch::get_or_default_sysroot().expect("Failed finding sysroot"); @@ -1327,7 +1324,7 @@ fn link_sanitizer_runtime( &default_sysroot, sess.opts.target_triple.triple(), ); - return default_tlib; + default_tlib } } @@ -1972,10 +1969,8 @@ fn add_late_link_args( if let Some(args) = sess.target.late_link_args_dynamic.get(&flavor) { cmd.verbatim_args(args.iter().map(Deref::deref)); } - } else { - if let Some(args) = sess.target.late_link_args_static.get(&flavor) { - cmd.verbatim_args(args.iter().map(Deref::deref)); - } + } else if let Some(args) = sess.target.late_link_args_static.get(&flavor) { + cmd.verbatim_args(args.iter().map(Deref::deref)); } if let Some(args) = sess.target.late_link_args.get(&flavor) { cmd.verbatim_args(args.iter().map(Deref::deref)); @@ -2635,10 +2630,8 @@ fn add_native_libs_from_crate( if link_static { cmd.link_staticlib_by_name(name, verbatim, false); } - } else { - if link_dynamic { - cmd.link_dylib_by_name(name, verbatim, true); - } + } else if link_dynamic { + cmd.link_dylib_by_name(name, verbatim, true); } } NativeLibKind::Framework { as_needed } => { @@ -3052,7 +3045,7 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result { } - "macosx10.15" + "macosx" if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") => {} "watchos" diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index cb266247e0dde..a73ec83ee62cc 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1,20 +1,21 @@ use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::io::prelude::*; -use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; -use std::{env, iter, mem, str}; +use std::{env, io, iter, mem, str}; use cc::windows_registry; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_metadata::{find_native_static_library, try_find_native_static_library}; +use rustc_metadata::{ + find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, +}; use rustc_middle::bug; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; use rustc_session::Session; +use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; use rustc_span::symbol::sym; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld}; use tracing::{debug, warn}; @@ -28,7 +29,7 @@ use crate::errors; /// and prevent inspection of linker output in case of errors, which we occasionally do. /// This should be acceptable because other messages from rustc are in English anyway, /// and may also be desirable to improve searchability of the linker diagnostics. -pub fn disable_localization(linker: &mut Command) { +pub(crate) fn disable_localization(linker: &mut Command) { // No harm in setting both env vars simultaneously. // Unix-style linkers. linker.env("LC_ALL", "C"); @@ -39,7 +40,7 @@ pub fn disable_localization(linker: &mut Command) { /// The third parameter is for env vars, used on windows to set up the /// path for MSVC to find its DLLs, and gcc to find its bundled /// toolchain -pub fn get_linker<'a>( +pub(crate) fn get_linker<'a>( sess: &'a Session, linker: &Path, flavor: LinkerFlavor, @@ -213,28 +214,36 @@ fn link_or_cc_args( macro_rules! generate_arg_methods { ($($ty:ty)*) => { $( impl $ty { - pub fn verbatim_args(&mut self, args: impl IntoIterator>) -> &mut Self { + #[allow(unused)] + pub(crate) fn verbatim_args(&mut self, args: impl IntoIterator>) -> &mut Self { verbatim_args(self, args) } - pub fn verbatim_arg(&mut self, arg: impl AsRef) -> &mut Self { + #[allow(unused)] + pub(crate) fn verbatim_arg(&mut self, arg: impl AsRef) -> &mut Self { verbatim_args(self, iter::once(arg)) } - pub fn link_args(&mut self, args: impl IntoIterator, IntoIter: ExactSizeIterator>) -> &mut Self { + #[allow(unused)] + pub(crate) fn link_args(&mut self, args: impl IntoIterator, IntoIter: ExactSizeIterator>) -> &mut Self { link_args(self, args) } - pub fn link_arg(&mut self, arg: impl AsRef) -> &mut Self { + #[allow(unused)] + pub(crate) fn link_arg(&mut self, arg: impl AsRef) -> &mut Self { link_args(self, iter::once(arg)) } - pub fn cc_args(&mut self, args: impl IntoIterator>) -> &mut Self { + #[allow(unused)] + pub(crate) fn cc_args(&mut self, args: impl IntoIterator>) -> &mut Self { cc_args(self, args) } - pub fn cc_arg(&mut self, arg: impl AsRef) -> &mut Self { + #[allow(unused)] + pub(crate) fn cc_arg(&mut self, arg: impl AsRef) -> &mut Self { cc_args(self, iter::once(arg)) } - pub fn link_or_cc_args(&mut self, args: impl IntoIterator>) -> &mut Self { + #[allow(unused)] + pub(crate) fn link_or_cc_args(&mut self, args: impl IntoIterator>) -> &mut Self { link_or_cc_args(self, args) } - pub fn link_or_cc_arg(&mut self, arg: impl AsRef) -> &mut Self { + #[allow(unused)] + pub(crate) fn link_or_cc_arg(&mut self, arg: impl AsRef) -> &mut Self { link_or_cc_args(self, iter::once(arg)) } } @@ -261,7 +270,7 @@ generate_arg_methods! { /// represents the meaning of each option being passed down. This trait is then /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an /// MSVC linker (e.g., `link.exe`) is being used. -pub trait Linker { +pub(crate) trait Linker { fn cmd(&mut self) -> &mut Command; fn is_cc(&self) -> bool { false @@ -312,12 +321,12 @@ pub trait Linker { } impl dyn Linker + '_ { - pub fn take_cmd(&mut self) -> Command { + pub(crate) fn take_cmd(&mut self) -> Command { mem::replace(self.cmd(), Command::new("")) } } -pub struct GccLinker<'a> { +struct GccLinker<'a> { cmd: Command, sess: &'a Session, target_cpu: &'a str, @@ -744,7 +753,7 @@ impl<'a> Linker for GccLinker<'a> { if self.sess.target.is_like_osx { // Write a plain, newline-separated list of symbols let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; for sym in symbols { debug!(" _{sym}"); writeln!(f, "_{sym}")?; @@ -755,7 +764,7 @@ impl<'a> Linker for GccLinker<'a> { } } else if is_windows { let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; // .def file similar to MSVC one but without LIBRARY section // because LD doesn't like when it's empty @@ -771,7 +780,7 @@ impl<'a> Linker for GccLinker<'a> { } else { // Write an LD version script let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; writeln!(f, "{{")?; if !symbols.is_empty() { writeln!(f, " global:")?; @@ -791,14 +800,12 @@ impl<'a> Linker for GccLinker<'a> { self.link_arg("-exported_symbols_list").link_arg(path); } else if self.sess.target.is_like_solaris { self.link_arg("-M").link_arg(path); + } else if is_windows { + self.link_arg(path); } else { - if is_windows { - self.link_arg(path); - } else { - let mut arg = OsString::from("--version-script="); - arg.push(path); - self.link_arg(arg).link_arg("--no-undefined-version"); - } + let mut arg = OsString::from("--version-script="); + arg.push(path); + self.link_arg(arg).link_arg("--no-undefined-version"); } } @@ -849,7 +856,7 @@ impl<'a> Linker for GccLinker<'a> { } } -pub struct MsvcLinker<'a> { +struct MsvcLinker<'a> { cmd: Command, sess: &'a Session, } @@ -878,7 +885,13 @@ impl<'a> Linker for MsvcLinker<'a> { } fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { - self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + // On MSVC-like targets rustc supports import libraries using alternative naming + // scheme (`libfoo.a`) unsupported by linker, search for such libraries manually. + if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) { + self.link_arg(path); + } else { + self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + } } fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { @@ -1045,7 +1058,7 @@ impl<'a> Linker for MsvcLinker<'a> { let path = tmpdir.join("lib.def"); let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; // Start off with the standard module name header and then go // straight to exports. @@ -1097,7 +1110,7 @@ impl<'a> Linker for MsvcLinker<'a> { } } -pub struct EmLinker<'a> { +struct EmLinker<'a> { cmd: Command, sess: &'a Session, } @@ -1214,7 +1227,7 @@ impl<'a> Linker for EmLinker<'a> { } } -pub struct WasmLd<'a> { +struct WasmLd<'a> { cmd: Command, sess: &'a Session, } @@ -1398,7 +1411,7 @@ impl<'a> WasmLd<'a> { } /// Linker shepherd script for L4Re (Fiasco) -pub struct L4Bender<'a> { +struct L4Bender<'a> { cmd: Command, sess: &'a Session, hinted_static: bool, @@ -1484,7 +1497,6 @@ impl<'a> Linker for L4Bender<'a> { fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { // ToDo, not implemented, copy from GCC self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented); - return; } fn subsystem(&mut self, subsystem: &str) { @@ -1505,7 +1517,7 @@ impl<'a> Linker for L4Bender<'a> { } impl<'a> L4Bender<'a> { - pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { + fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { L4Bender { cmd, sess, hinted_static: false } } @@ -1518,14 +1530,14 @@ impl<'a> L4Bender<'a> { } /// Linker for AIX. -pub struct AixLinker<'a> { +struct AixLinker<'a> { cmd: Command, sess: &'a Session, hinted_static: Option, } impl<'a> AixLinker<'a> { - pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { + fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { AixLinker { cmd, sess, hinted_static: None } } @@ -1635,7 +1647,7 @@ impl<'a> Linker for AixLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { let path = tmpdir.join("list.exp"); let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; // FIXME: use llvm-nm to generate export list. for symbol in symbols { debug!(" _{symbol}"); @@ -1753,7 +1765,7 @@ pub(crate) fn linked_symbols( /// Much simplified and explicit CLI for the NVPTX linker. The linker operates /// with bitcode and uses LLVM backend to generate a PTX assembly. -pub struct PtxLinker<'a> { +struct PtxLinker<'a> { cmd: Command, sess: &'a Session, } @@ -1819,7 +1831,7 @@ impl<'a> Linker for PtxLinker<'a> { } /// The `self-contained` LLVM bitcode linker -pub struct LlbcLinker<'a> { +struct LlbcLinker<'a> { cmd: Command, sess: &'a Session, } @@ -1890,7 +1902,7 @@ impl<'a> Linker for LlbcLinker<'a> { fn linker_plugin_lto(&mut self) {} } -pub struct BpfLinker<'a> { +struct BpfLinker<'a> { cmd: Command, sess: &'a Session, } @@ -1948,7 +1960,7 @@ impl<'a> Linker for BpfLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { let path = tmpdir.join("symbols"); let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; for sym in symbols { writeln!(f, "{sym}")?; } diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index 8b6f6b5a220a4..ab8b06a05fc74 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -5,8 +5,8 @@ use rustc_data_structures::memmap::Mmap; use rustc_errors::FatalError; use super::write::CodegenContext; -use crate::traits::*; use crate::ModuleCodegen; +use crate::traits::*; pub struct ThinModule { pub shared: Arc>, @@ -41,18 +41,14 @@ pub struct ThinShared { } pub enum LtoModuleCodegen { - Fat { - module: ModuleCodegen, - _serialized_bitcode: Vec>, - }, - + Fat(ModuleCodegen), Thin(ThinModule), } impl LtoModuleCodegen { pub fn name(&self) -> &str { match *self { - LtoModuleCodegen::Fat { .. } => "everything", + LtoModuleCodegen::Fat(_) => "everything", LtoModuleCodegen::Thin(ref m) => m.name(), } } @@ -68,7 +64,7 @@ impl LtoModuleCodegen { cgcx: &CodegenContext, ) -> Result, FatalError> { match self { - LtoModuleCodegen::Fat { mut module, .. } => { + LtoModuleCodegen::Fat(mut module) => { B::optimize_fat(cgcx, &mut module)?; Ok(module) } @@ -81,7 +77,7 @@ impl LtoModuleCodegen { pub fn cost(&self) -> u64 { match *self { // Only one module with fat LTO, so the cost doesn't matter. - LtoModuleCodegen::Fat { .. } => 0, + LtoModuleCodegen::Fat(_) => 0, LtoModuleCodegen::Thin(ref m) => m.cost(), } } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 9b5a797ad5106..06433484ea3cd 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -7,19 +7,20 @@ use std::path::Path; use object::write::{self, StandardSegment, Symbol, SymbolSection}; use object::{ - elf, pe, xcoff, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, - ObjectSymbol, SectionFlags, SectionKind, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, + Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, ObjectSymbol, + SectionFlags, SectionKind, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, elf, pe, + xcoff, }; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; +use rustc_data_structures::owned_slice::{OwnedSlice, try_slice_owned}; +use rustc_metadata::EncodedMetadata; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::fs::METADATA_FILENAME; -use rustc_metadata::EncodedMetadata; use rustc_middle::bug; use rustc_session::Session; use rustc_span::sym; use rustc_target::abi::Endian; -use rustc_target::spec::{ef_avr_arch, RelocModel, Target}; +use rustc_target::spec::{RelocModel, Target, ef_avr_arch}; /// The default metadata loader. This is used by cg_llvm and cg_clif. /// @@ -32,7 +33,7 @@ use rustc_target::spec::{ef_avr_arch, RelocModel, Target}; ///
The metadata can be found in the `.rustc` section of the shared library.
/// #[derive(Debug)] -pub struct DefaultMetadataLoader; +pub(crate) struct DefaultMetadataLoader; static AIX_METADATA_SYMBOL_NAME: &'static str = "__aix_rust_metadata"; @@ -171,10 +172,10 @@ pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a "Metadata at offset {offset} with size {len} is beyond .info section" )); } - return Ok(&info_data[offset..(offset + len)]); + Ok(&info_data[offset..(offset + len)]) } else { - return Err(format!("Unable to find symbol {AIX_METADATA_SYMBOL_NAME}")); - }; + Err(format!("Unable to find symbol {AIX_METADATA_SYMBOL_NAME}")) + } } pub(crate) fn create_object_file(sess: &Session) -> Option> { @@ -372,36 +373,51 @@ pub(crate) fn create_object_file(sess: &Session) -> Option object::write::MachOBuildVersion { /// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz" /// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200 - fn pack_version((major, minor): (u32, u32)) -> u32 { - (major << 16) | (minor << 8) + fn pack_version((major, minor, patch): (u16, u8, u8)) -> u32 { + let (major, minor, patch) = (major as u32, minor as u32, patch as u32); + (major << 16) | (minor << 8) | patch } let platform = rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS"); - let min_os = rustc_target::spec::current_apple_deployment_target(target) - .expect("unknown Apple target OS"); - let sdk = + let min_os = rustc_target::spec::current_apple_deployment_target(target); + let (sdk_major, sdk_minor) = rustc_target::spec::current_apple_sdk_version(platform).expect("unknown Apple target OS"); let mut build_version = object::write::MachOBuildVersion::default(); build_version.platform = platform; build_version.minos = pack_version(min_os); - build_version.sdk = pack_version(sdk); + build_version.sdk = pack_version((sdk_major, sdk_minor, 0)); build_version } /// Is Apple's CPU subtype `arm64e`s fn macho_is_arm64e(target: &Target) -> bool { - return target.llvm_target.starts_with("arm64e"); + target.llvm_target.starts_with("arm64e") } -pub enum MetadataPosition { +pub(crate) enum MetadataPosition { First, Last, } @@ -437,7 +453,7 @@ pub enum MetadataPosition { /// * ELF - All other targets are similar to Windows in that there's a /// `SHF_EXCLUDE` flag we can set on sections in an object file to get /// automatically removed from the final output. -pub fn create_wrapper_file( +pub(crate) fn create_wrapper_file( sess: &Session, section_name: String, data: &[u8], @@ -653,17 +669,13 @@ pub fn create_metadata_file_for_wasm(sess: &Session, data: &[u8], section_name: let mut imports = wasm_encoder::ImportSection::new(); if sess.target.pointer_width == 64 { - imports.import( - "env", - "__linear_memory", - wasm_encoder::MemoryType { - minimum: 0, - maximum: None, - memory64: true, - shared: false, - page_size_log2: None, - }, - ); + imports.import("env", "__linear_memory", wasm_encoder::MemoryType { + minimum: 0, + maximum: None, + memory64: true, + shared: false, + page_size_log2: None, + }); } if imports.len() > 0 { diff --git a/compiler/rustc_codegen_ssa/src/back/mod.rs b/compiler/rustc_codegen_ssa/src/back/mod.rs index d11ed54eb209f..2b3a2e3a369bb 100644 --- a/compiler/rustc_codegen_ssa/src/back/mod.rs +++ b/compiler/rustc_codegen_ssa/src/back/mod.rs @@ -1,9 +1,9 @@ pub mod archive; -pub mod command; +pub(crate) mod command; pub mod link; -pub mod linker; +pub(crate) mod linker; pub mod lto; pub mod metadata; -pub mod rpath; +pub(crate) mod rpath; pub mod symbol_export; pub mod write; diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 42f8c3114ff50..56a808df6b0bd 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -6,14 +6,14 @@ use rustc_data_structures::fx::FxHashSet; use rustc_fs_util::try_canonicalize; use tracing::debug; -pub struct RPathConfig<'a> { +pub(super) struct RPathConfig<'a> { pub libs: &'a [&'a Path], pub out_filename: PathBuf, pub is_like_osx: bool, pub linker_is_gnu: bool, } -pub fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec { +pub(super) fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec { debug!("preparing the RPATH!"); let rpaths = get_rpaths(config); diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index 0de0b8a52b192..39034842d1086 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -1,7 +1,7 @@ use std::ffi::OsString; use std::path::{Path, PathBuf}; -use super::{get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags, RPathConfig}; +use super::{RPathConfig, get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags}; #[test] fn test_rpaths_to_flags() { @@ -74,13 +74,10 @@ fn test_rpath_relative_issue_119571() { fn test_xlinker() { let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]); - assert_eq!( - args, - vec![ - OsString::from("-Wl,-rpath,a/normal/path"), - OsString::from("-Wl,-rpath"), - OsString::from("-Xlinker"), - OsString::from("a,comma,path") - ] - ); + assert_eq!(args, vec![ + OsString::from("-Wl,-rpath,a/normal/path"), + OsString::from("-Wl,-rpath"), + OsString::from("-Xlinker"), + OsString::from("a,comma,path") + ]); } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index d2f11d48140c9..77c35a1fe79e9 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -3,11 +3,11 @@ use std::collections::hash_map::Entry::*; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE}; use rustc_data_structures::unord::UnordMap; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId}; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ - metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, + ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, metadata_symbol_name, }; use rustc_middle::query::LocalCrate; use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, TyCtxt}; @@ -18,7 +18,7 @@ use tracing::debug; use crate::base::allocator_kind_for_codegen; -pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { +fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(tcx.crate_types()) } @@ -140,14 +140,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap { if args.non_erasable_generics(tcx, def).next().is_some() { let symbol = ExportedSymbol::Generic(def, args); - symbols.push(( - symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); + symbols.push((symbol, SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + })); } } MonoItem::Fn(Instance { def: InstanceKind::DropGlue(def_id, Some(ty)), args }) => { @@ -354,14 +327,11 @@ fn exported_symbols_provider_local( args.non_erasable_generics(tcx, def_id).next(), Some(GenericArgKind::Type(ty)) ); - symbols.push(( - ExportedSymbol::DropGlue(ty), - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); + symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + })); } MonoItem::Fn(Instance { def: InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)), @@ -372,14 +342,11 @@ fn exported_symbols_provider_local( args.non_erasable_generics(tcx, def_id).next(), Some(GenericArgKind::Type(ty)) ); - symbols.push(( - ExportedSymbol::AsyncDropGlueCtorShim(ty), - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); + symbols.push((ExportedSymbol::AsyncDropGlueCtorShim(ty), SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + })); } _ => { // Any other symbols don't qualify for sharing @@ -484,7 +451,7 @@ fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) !tcx.reachable_set(()).contains(&def_id) } -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { providers.reachable_non_generics = reachable_non_generics_provider; providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; providers.exported_symbols = exported_symbols_provider_local; @@ -525,7 +492,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel } /// This is the symbol name of the given instance instantiated in a specific crate. -pub fn symbol_name_for_instance_in_crate<'tcx>( +pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, instantiating_crate: CrateNum, @@ -582,7 +549,7 @@ pub fn symbol_name_for_instance_in_crate<'tcx>( /// This is the symbol name of the given instance as seen by the linker. /// /// On 32-bit Windows symbols are decorated according to their calling conventions. -pub fn linking_symbol_name_for_instance_in_crate<'tcx>( +pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, instantiating_crate: CrateNum, @@ -661,7 +628,7 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>( format!("{prefix}{undecorated}{suffix}{args_in_bytes}") } -pub fn exporting_symbol_name_for_instance_in_crate<'tcx>( +pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>( tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, cnum: CrateNum, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index feb27c148a188..4d81ff933dded 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -2,8 +2,8 @@ use std::any::Any; use std::assert_matches::assert_matches; use std::marker::PhantomData; use std::path::{Path, PathBuf}; -use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::Arc; +use std::sync::mpsc::{Receiver, Sender, channel}; use std::{fs, io, mem, str, thread}; use jobserver::{Acquired, Client}; @@ -16,23 +16,23 @@ use rustc_errors::emitter::Emitter; use rustc_errors::translation::Translate; use rustc_errors::{ Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, FluentBundle, Level, MultiSpan, - Style, + Style, Suggestions, }; use rustc_fs_util::link_or_copy; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_incremental::{ copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess, }; -use rustc_metadata::fs::copy_to_stdout; use rustc_metadata::EncodedMetadata; +use rustc_metadata::fs::copy_to_stdout; use rustc_middle::bug; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::exported_symbols::SymbolExportInfo; use rustc_middle::ty::TyCtxt; +use rustc_session::Session; use rustc_session::config::{ self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath, }; -use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span}; @@ -45,8 +45,8 @@ use super::symbol_export::symbol_name_for_instance_in_crate; use crate::errors::ErrorCreatingRemarkDir; use crate::traits::*; use crate::{ - errors, CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, - ModuleKind, + CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, + errors, }; const PRE_LTO_BC_EXT: &str = "pre-lto.bc"; @@ -335,7 +335,7 @@ pub type TargetMachineFactoryFn = Arc< + Sync, >; -pub type ExportedSymbols = FxHashMap>>; +type ExportedSymbols = FxHashMap>>; /// Additional resources used by optimize_and_codegen (not module specific) #[derive(Clone)] @@ -437,9 +437,9 @@ fn generate_lto_work( } } -pub struct CompiledModules { - pub modules: Vec, - pub allocator_module: Option, +struct CompiledModules { + modules: Vec, + allocator_module: Option, } fn need_bitcode_in_object(tcx: TyCtxt<'_>) -> bool { @@ -462,7 +462,7 @@ fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool { } } -pub fn start_async_codegen( +pub(crate) fn start_async_codegen( backend: B, tcx: TyCtxt<'_>, target_cpu: String, @@ -836,13 +836,13 @@ pub enum FatLtoInput { } /// Actual LTO type we end up choosing based on multiple factors. -pub enum ComputedLtoType { +pub(crate) enum ComputedLtoType { No, Thin, Fat, } -pub fn compute_per_cgu_lto_type( +pub(crate) fn compute_per_cgu_lto_type( sess_lto: &Lto, opts: &config::Options, sess_crate_types: &[CrateType], @@ -1087,7 +1087,7 @@ struct Diagnostic { // A cut-down version of `rustc_errors::Subdiag` that impls `Send`. It's // missing the following fields from `rustc_errors::Subdiag`. // - `span`: it doesn't impl `Send`. -pub struct Subdiagnostic { +pub(crate) struct Subdiagnostic { level: Level, messages: Vec<(DiagMessage, Style)>, } @@ -1779,7 +1779,7 @@ fn start_executing_work( /// `FatalError` is explicitly not `Send`. #[must_use] -pub struct WorkerFatalError; +pub(crate) struct WorkerFatalError; fn spawn_work<'a, B: ExtraBackendMethods>( cgcx: &'a CodegenContext, @@ -1867,7 +1867,7 @@ pub struct SharedEmitterMain { } impl SharedEmitter { - pub fn new() -> (SharedEmitter, SharedEmitterMain) { + fn new() -> (SharedEmitter, SharedEmitterMain) { let (sender, receiver) = channel(); (SharedEmitter { sender }, SharedEmitterMain { receiver }) @@ -1883,7 +1883,7 @@ impl SharedEmitter { drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source))); } - pub fn fatal(&self, msg: &str) { + fn fatal(&self, msg: &str) { drop(self.sender.send(SharedEmitterMessage::Fatal(msg.to_string()))); } } @@ -1903,7 +1903,7 @@ impl Emitter for SharedEmitter { // Check that we aren't missing anything interesting when converting to // the cut-down local `DiagInner`. assert_eq!(diag.span, MultiSpan::new()); - assert_eq!(diag.suggestions, Ok(vec![])); + assert_eq!(diag.suggestions, Suggestions::Enabled(vec![])); assert_eq!(diag.sort_span, rustc_span::DUMMY_SP); assert_eq!(diag.is_lint, None); // No sensible check for `diag.emitted_at`. @@ -1930,7 +1930,7 @@ impl Emitter for SharedEmitter { } impl SharedEmitterMain { - pub fn check(&self, sess: &Session, blocking: bool) { + fn check(&self, sess: &Session, blocking: bool) { loop { let message = if blocking { match self.receiver.recv() { @@ -2087,17 +2087,17 @@ impl OngoingCodegen { ) } - pub fn codegen_finished(&self, tcx: TyCtxt<'_>) { + pub(crate) fn codegen_finished(&self, tcx: TyCtxt<'_>) { self.wait_for_signal_to_codegen_item(); self.check_for_errors(tcx.sess); drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::))); } - pub fn check_for_errors(&self, sess: &Session) { + pub(crate) fn check_for_errors(&self, sess: &Session) { self.shared_emitter_main.check(sess, false); } - pub fn wait_for_signal_to_codegen_item(&self) { + pub(crate) fn wait_for_signal_to_codegen_item(&self) { match self.codegen_worker_receive.recv() { Ok(CguMessage) => { // Ok to proceed. @@ -2110,7 +2110,7 @@ impl OngoingCodegen { } } -pub fn submit_codegened_module_to_llvm( +pub(crate) fn submit_codegened_module_to_llvm( _backend: &B, tx_to_llvm_workers: &Sender>, module: ModuleCodegen, @@ -2120,7 +2120,7 @@ pub fn submit_codegened_module_to_llvm( drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone:: { llvm_work_item, cost }))); } -pub fn submit_post_lto_module_to_llvm( +pub(crate) fn submit_post_lto_module_to_llvm( _backend: &B, tx_to_llvm_workers: &Sender>, module: CachedModuleCodegen, @@ -2129,7 +2129,7 @@ pub fn submit_post_lto_module_to_llvm( drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone:: { llvm_work_item, cost: 0 }))); } -pub fn submit_pre_lto_module_to_llvm( +pub(crate) fn submit_pre_lto_module_to_llvm( _backend: &B, tcx: TyCtxt<'_>, tx_to_llvm_workers: &Sender>, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f1e7f87f56767..5c67600e4eec1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -3,7 +3,7 @@ use std::collections::BTreeSet; use std::time::{Duration, Instant}; use itertools::Itertools; -use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS}; +use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name}; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; @@ -17,15 +17,15 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::{exported_symbols, lang_items}; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::mir::BinOp; +use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_session::Session; +use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; -use rustc_span::{Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Symbol}; use rustc_target::abi::FIRST_VARIANT; use tracing::{debug, info}; @@ -33,58 +33,35 @@ use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; use crate::back::metadata::create_compressed_metadata_file; use crate::back::write::{ - compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm, - submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen, + ComputedLtoType, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen, + submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, }; use crate::common::{self, IntPredicate, RealPredicate, TypeKind}; +use crate::meth::load_vtable; use crate::mir::operand::OperandValue; use crate::mir::place::PlaceRef; use crate::traits::*; use crate::{ - errors, meth, mir, CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, + CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir, }; -pub fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate { - match op { - BinOp::Eq => IntPredicate::IntEQ, - BinOp::Ne => IntPredicate::IntNE, - BinOp::Lt => { - if signed { - IntPredicate::IntSLT - } else { - IntPredicate::IntULT - } - } - BinOp::Le => { - if signed { - IntPredicate::IntSLE - } else { - IntPredicate::IntULE - } - } - BinOp::Gt => { - if signed { - IntPredicate::IntSGT - } else { - IntPredicate::IntUGT - } - } - BinOp::Ge => { - if signed { - IntPredicate::IntSGE - } else { - IntPredicate::IntUGE - } - } - op => bug!( - "comparison_op_to_icmp_predicate: expected comparison operator, \ - found {:?}", - op - ), +pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate { + match (op, signed) { + (BinOp::Eq, _) => IntPredicate::IntEQ, + (BinOp::Ne, _) => IntPredicate::IntNE, + (BinOp::Lt, true) => IntPredicate::IntSLT, + (BinOp::Lt, false) => IntPredicate::IntULT, + (BinOp::Le, true) => IntPredicate::IntSLE, + (BinOp::Le, false) => IntPredicate::IntULE, + (BinOp::Gt, true) => IntPredicate::IntSGT, + (BinOp::Gt, false) => IntPredicate::IntUGT, + (BinOp::Ge, true) => IntPredicate::IntSGE, + (BinOp::Ge, false) => IntPredicate::IntUGE, + op => bug!("bin_op_to_icmp_predicate: expected comparison operator, found {:?}", op), } } -pub fn bin_op_to_fcmp_predicate(op: BinOp) -> RealPredicate { +pub(crate) fn bin_op_to_fcmp_predicate(op: BinOp) -> RealPredicate { match op { BinOp::Eq => RealPredicate::RealOEQ, BinOp::Ne => RealPredicate::RealUNE, @@ -92,13 +69,7 @@ pub fn bin_op_to_fcmp_predicate(op: BinOp) -> RealPredicate { BinOp::Le => RealPredicate::RealOLE, BinOp::Gt => RealPredicate::RealOGT, BinOp::Ge => RealPredicate::RealOGE, - op => { - bug!( - "comparison_op_to_fcmp_predicate: expected comparison operator, \ - found {:?}", - op - ); - } + op => bug!("bin_op_to_fcmp_predicate: expected comparison operator, found {:?}", op), } } @@ -135,7 +106,7 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /// /// The `old_info` argument is a bit odd. It is intended for use in an upcast, /// where the new vtable for an object will be derived from the old one. -pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, source: Ty<'tcx>, target: Ty<'tcx>, @@ -145,16 +116,37 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let (source, target) = cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.param_env()); match (source.kind(), target.kind()) { - (&ty::Array(_, len), &ty::Slice(_)) => { - cx.const_usize(len.eval_target_usize(cx.tcx(), ty::ParamEnv::reveal_all())) - } + (&ty::Array(_, len), &ty::Slice(_)) => cx.const_usize( + len.try_to_target_usize(cx.tcx()).expect("expected monomorphic const in codegen"), + ), (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind)) if src_dyn_kind == target_dyn_kind => { let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { - // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables. + // Codegen takes advantage of the additional assumption, where if the + // principal trait def id of what's being casted doesn't change, + // then we don't need to adjust the vtable at all. This + // corresponds to the fact that `dyn Tr
: Unsize>` + // requires that `A = B`; we don't allow *upcasting* objects + // between the same trait with different args. If we, for + // some reason, were to relax the `Unsize` trait, it could become + // unsound, so let's assert here that the trait refs are *equal*. + // + // We can use `assert_eq` because the binders should have been anonymized, + // and because higher-ranked equality now requires the binders are equal. + debug_assert_eq!( + data_a.principal(), + data_b.principal(), + "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" + ); + + // A NOP cast that doesn't actually change anything, let's avoid any + // unnecessary work. This relies on the assumption that if the principal + // traits are equal, then the associated type bounds (`dyn Trait`) + // are also equal, which is ensured by the fact that normalization is + // a function and we do not allow overlapping impls. return old_info; } @@ -164,14 +156,8 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if let Some(entry_idx) = vptr_entry_idx { let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes(); - let gep = bx.inbounds_ptradd(old_info, bx.const_usize(vtable_byte_offset)); - let new_vptr = bx.load(bx.type_ptr(), gep, ptr_align); - bx.nonnull_metadata(new_vptr); - // VTable loads are invariant. - bx.set_invariant_load(new_vptr); - new_vptr + load_vtable(bx, old_info, bx.type_ptr(), vtable_byte_offset, source, true) } else { old_info } @@ -182,7 +168,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer. -pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, src: Bx::Value, src_ty: Ty<'tcx>, @@ -227,7 +213,7 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } /// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type. -pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +pub(crate) fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, src: Bx::Value, src_ty_and_layout: TyAndLayout<'tcx>, @@ -250,7 +236,7 @@ pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /// Coerces `src`, which is a reference to a value of type `src_ty`, /// to a value of type `dst_ty`, and stores the result in `dst`. -pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +pub(crate) fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, src: PlaceRef<'tcx, Bx::Value>, dst: PlaceRef<'tcx, Bx::Value>, @@ -305,7 +291,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /// /// If `is_unchecked` is true, this does no masking, and adds sufficient `assume` /// calls or operation flags to preserve as much freedom to optimize as possible. -pub fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, lhs: Bx::Value, mut rhs: Bx::Value, @@ -369,11 +355,11 @@ pub fn wants_msvc_seh(sess: &Session) -> bool { /// Returns `true` if this session's target requires the new exception /// handling LLVM IR instructions (catchpad / cleanuppad / ... instead /// of landingpad) -pub fn wants_new_eh_instructions(sess: &Session) -> bool { +pub(crate) fn wants_new_eh_instructions(sess: &Session) -> bool { wants_wasm_eh(sess) || wants_msvc_seh(sess) } -pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub(crate) fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, instance: Instance<'tcx>, ) { @@ -454,7 +440,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let isize_ty = cx.type_isize(); let ptr_ty = cx.type_ptr(); - let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx); + let (arg_argc, arg_argv) = get_argc_argv(&mut bx); let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type { @@ -497,33 +483,30 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } /// Obtain the `argc` and `argv` values to pass to the rust start function. -fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx, - bx: &mut Bx, -) -> (Bx::Value, Bx::Value) { - if cx.sess().target.os.contains("uefi") { +fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) { + if bx.cx().sess().target.os.contains("uefi") { // Params for UEFI let param_handle = bx.get_param(0); let param_system_table = bx.get_param(1); let ptr_size = bx.tcx().data_layout.pointer_size; let ptr_align = bx.tcx().data_layout.pointer_align.abi; - let arg_argc = bx.const_int(cx.type_isize(), 2); + let arg_argc = bx.const_int(bx.cx().type_isize(), 2); let arg_argv = bx.alloca(2 * ptr_size, ptr_align); bx.store(param_handle, arg_argv, ptr_align); let arg_argv_el1 = bx.inbounds_ptradd(arg_argv, bx.const_usize(ptr_size.bytes())); bx.store(param_system_table, arg_argv_el1, ptr_align); (arg_argc, arg_argv) - } else if cx.sess().target.main_needs_argc_argv { + } else if bx.cx().sess().target.main_needs_argc_argv { // Params from native `main()` used as args for rust start function let param_argc = bx.get_param(0); let param_argv = bx.get_param(1); - let arg_argc = bx.intcast(param_argc, cx.type_isize(), true); + let arg_argc = bx.intcast(param_argc, bx.cx().type_isize(), true); let arg_argv = param_argv; (arg_argc, arg_argv) } else { // The Rust start function doesn't need `argc` and `argv`, so just pass zeros. - let arg_argc = bx.const_int(cx.type_int(), 0); - let arg_argv = bx.const_null(cx.type_ptr()); + let arg_argc = bx.const_int(bx.cx().type_int(), 0); + let arg_argv = bx.const_null(bx.cx().type_ptr()); (arg_argc, arg_argv) } } @@ -985,7 +968,8 @@ impl CrateInfo { false } CrateType::Staticlib | CrateType::Rlib => { - // We don't invoke the linker for these, so we don't need to collect the NatVis for them. + // We don't invoke the linker for these, so we don't need to collect the NatVis for + // them. false } }); @@ -999,7 +983,7 @@ impl CrateInfo { } } -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { providers.backend_optimization_level = |tcx, cratenum| { let for_speed = match tcx.sess.opts.optimize { // If globally no optimisation is done, #[optimize] has no effect. diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 4ab20c154ccd0..e99c3a462711c 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,12 +1,12 @@ -use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; -use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_ast::{MetaItemKind, NestedMetaItem, ast, attr}; +use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name}; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, DiagMessage, SubdiagMessage}; +use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{lang_items, LangItem}; +use rustc_hir::{LangItem, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -16,8 +16,8 @@ use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; -use rustc_target::spec::{abi, SanitizerSet}; +use rustc_span::{Span, sym}; +use rustc_target::spec::{SanitizerSet, abi}; use crate::errors; use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature}; @@ -195,24 +195,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } } - sym::cmse_nonsecure_entry => { - if let Some(fn_sig) = fn_sig() - && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. }) - { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0776, - "`#[cmse_nonsecure_entry]` requires C ABI" - ) - .emit(); - } - if !tcx.sess.target.llvm_target.contains("thumbv8m") { - struct_span_code_err!(tcx.dcx(), attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY - } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::track_caller => { let is_closure = tcx.is_closure_like(did.to_def_id()); @@ -317,9 +299,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { "extern mutable statics are not allowed with `#[linkage]`", ); diag.note( - "marking the extern static mutable would allow changing which symbol \ - the static references rather than make the target of the symbol \ - mutable", + "marking the extern static mutable would allow changing which \ + symbol the static references rather than make the target of the \ + symbol mutable", ); diag.emit(); } @@ -617,32 +599,29 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // purpose functions as they wouldn't have the right target features // enabled. For that reason we also forbid #[inline(always)] as it can't be // respected. - if !codegen_fn_attrs.target_features.is_empty() { - if codegen_fn_attrs.inline == InlineAttr::Always { - if let Some(span) = inline_span { - tcx.dcx().span_err( - span, - "cannot use `#[inline(always)]` with \ + if !codegen_fn_attrs.target_features.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always + { + if let Some(span) = inline_span { + tcx.dcx().span_err( + span, + "cannot use `#[inline(always)]` with \ `#[target_feature]`", - ); - } + ); } } - if !codegen_fn_attrs.no_sanitize.is_empty() { - if codegen_fn_attrs.inline == InlineAttr::Always { - if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { - let hir_id = tcx.local_def_id_to_hir_id(did); - tcx.node_span_lint( - lint::builtin::INLINE_NO_SANITIZE, - hir_id, - no_sanitize_span, - |lint| { - lint.primary_message("`no_sanitize` will have no effect after inlining"); - lint.span_note(inline_span, "inlining requested here"); - }, - ) - } + if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always { + if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { + let hir_id = tcx.local_def_id_to_hir_id(did); + tcx.node_span_lint( + lint::builtin::INLINE_NO_SANITIZE, + hir_id, + no_sanitize_span, + |lint| { + lint.primary_message("`no_sanitize` will have no effect after inlining"); + lint.span_note(inline_span, "inlining requested here"); + }, + ) } } @@ -714,18 +693,19 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list { - // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, - // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined - // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information - // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t. + // According to the table at + // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the + // ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined + // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import + // information to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t. // - // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this: - // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies - // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library - // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import - // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet - // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment - // about LINK.EXE failing.) + // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for + // this: both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that + // specifies a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import + // library for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an + // import library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I + // don't know yet if the resulting EXE runs, as I haven't yet built the necessary DLL -- + // see earlier comment about LINK.EXE failing.) if *ordinal <= u16::MAX as u128 { Some(ordinal.get() as u16) } else { @@ -758,6 +738,6 @@ fn check_link_name_xor_ordinal( } } -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; } diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index bfb1d217eae8a..582a2a87e4867 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -118,7 +118,7 @@ mod temp_stable_hash_impls { } } -pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &Bx, span: Option, li: LangItem, @@ -129,7 +129,7 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance) } -pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, llty: Bx::Type, mask_llty: Bx::Type, @@ -200,7 +200,8 @@ pub fn i686_decorated_name( let mut decorated_name = String::with_capacity(name.len() + 6); if disable_name_mangling { - // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled. + // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be + // disabled. decorated_name.push('\x01'); } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs index 0918660e6be88..bfd1b94c7903f 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs @@ -54,7 +54,7 @@ pub fn tag_base_type<'tcx>(tcx: TyCtxt<'tcx>, enum_type_and_layout: TyAndLayout< }) } -pub fn tag_base_type_opt<'tcx>( +fn tag_base_type_opt<'tcx>( tcx: TyCtxt<'tcx>, enum_type_and_layout: TyAndLayout<'tcx>, ) -> Option> { @@ -76,9 +76,9 @@ pub fn tag_base_type_opt<'tcx>( Primitive::Float(f) => Integer::from_size(f.size()).unwrap(), // FIXME(erikdesjardins): handle non-default addrspace ptr sizes Primitive::Pointer(_) => { - // If the niche is the NULL value of a reference, then `discr_enum_ty` will be - // a RawPtr. CodeView doesn't know what to do with enums whose base type is a - // pointer so we fix this up to just be `usize`. + // If the niche is the NULL value of a reference, then `discr_enum_ty` will + // be a RawPtr. CodeView doesn't know what to do with enums whose base type + // is a pointer so we fix this up to just be `usize`. // DWARF might be able to deal with this but with an integer type we are on // the safe side there too. tcx.data_layout.ptr_sized_integer() diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index f0bc4354f9a75..369ab387bea58 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -95,7 +95,8 @@ fn push_debuginfo_type_name<'tcx>( } Err(e) => { // Computing the layout can still fail here, e.g. if the target architecture - // cannot represent the type. See https://github.com/rust-lang/rust/issues/94961. + // cannot represent the type. See + // https://github.com/rust-lang/rust/issues/94961. tcx.dcx().emit_fatal(e.into_diagnostic()); } } @@ -187,7 +188,8 @@ fn push_debuginfo_type_name<'tcx>( _ => write!( output, ",{}>", - len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()) + len.try_to_target_usize(tcx) + .expect("expected monomorphic const in codegen") ) .unwrap(), } @@ -199,7 +201,8 @@ fn push_debuginfo_type_name<'tcx>( _ => write!( output, "; {}]", - len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()) + len.try_to_target_usize(tcx) + .expect("expected monomorphic const in codegen") ) .unwrap(), } @@ -236,15 +239,13 @@ fn push_debuginfo_type_name<'tcx>( let has_enclosing_parens = if cpp_like_debuginfo { output.push_str("dyn$<"); false + } else if trait_data.len() > 1 && auto_traits.len() != 0 { + // We need enclosing parens because there is more than one trait + output.push_str("(dyn "); + true } else { - if trait_data.len() > 1 && auto_traits.len() != 0 { - // We need enclosing parens because there is more than one trait - output.push_str("(dyn "); - true - } else { - output.push_str("dyn "); - false - } + output.push_str("dyn "); + false }; if let Some(principal) = trait_data.principal() { @@ -577,33 +578,20 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: & } fn coroutine_kind_label(coroutine_kind: Option) -> &'static str { + use CoroutineDesugaring::*; + use CoroutineKind::*; + use CoroutineSource::*; match coroutine_kind { - Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Block)) => { - "gen_block" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Closure)) => { - "gen_closure" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Fn)) => "gen_fn", - Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) => { - "async_block" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) => { - "async_closure" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) => { - "async_fn" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Block)) => { - "async_gen_block" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Closure)) => { - "async_gen_closure" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Fn)) => { - "async_gen_fn" - } - Some(CoroutineKind::Coroutine(_)) => "coroutine", + Some(Desugared(Gen, Block)) => "gen_block", + Some(Desugared(Gen, Closure)) => "gen_closure", + Some(Desugared(Gen, Fn)) => "gen_fn", + Some(Desugared(Async, Block)) => "async_block", + Some(Desugared(Async, Closure)) => "async_closure", + Some(Desugared(Async, Fn)) => "async_fn", + Some(Desugared(AsyncGen, Block)) => "async_gen_block", + Some(Desugared(AsyncGen, Closure)) => "async_gen_closure", + Some(Desugared(AsyncGen, Fn)) => "async_gen_fn", + Some(Coroutine(_)) => "coroutine", None => "closure", } } @@ -701,7 +689,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S match ty.kind() { ty::Int(ity) => { // FIXME: directly extract the bits from a valtree instead of evaluating an - // alreay evaluated `Const` in order to get the bits. + // already evaluated `Const` in order to get the bits. let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; write!(output, "{val}") diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 573a8cf7cbe42..08b326e3ac3c6 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -10,8 +10,8 @@ use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; use rustc_macros::Diagnostic; -use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutError; use rustc_span::{Span, Symbol}; use rustc_type_ir::FloatTy; @@ -21,7 +21,7 @@ use crate::fluent_generated as fluent; #[derive(Diagnostic)] #[diag(codegen_ssa_incorrect_cgu_reuse_type)] -pub struct IncorrectCguReuseType<'a> { +pub(crate) struct IncorrectCguReuseType<'a> { #[primary_span] pub span: Span, pub cgu_user_name: &'a str, @@ -32,14 +32,14 @@ pub struct IncorrectCguReuseType<'a> { #[derive(Diagnostic)] #[diag(codegen_ssa_cgu_not_recorded)] -pub struct CguNotRecorded<'a> { +pub(crate) struct CguNotRecorded<'a> { pub cgu_user_name: &'a str, pub cgu_name: &'a str, } #[derive(Diagnostic)] #[diag(codegen_ssa_unknown_reuse_kind)] -pub struct UnknownReuseKind { +pub(crate) struct UnknownReuseKind { #[primary_span] pub span: Span, pub kind: Symbol, @@ -47,14 +47,14 @@ pub struct UnknownReuseKind { #[derive(Diagnostic)] #[diag(codegen_ssa_missing_query_depgraph)] -pub struct MissingQueryDepGraph { +pub(crate) struct MissingQueryDepGraph { #[primary_span] pub span: Span, } #[derive(Diagnostic)] #[diag(codegen_ssa_malformed_cgu_name)] -pub struct MalformedCguName { +pub(crate) struct MalformedCguName { #[primary_span] pub span: Span, pub user_path: String, @@ -63,7 +63,7 @@ pub struct MalformedCguName { #[derive(Diagnostic)] #[diag(codegen_ssa_no_module_named)] -pub struct NoModuleNamed<'a> { +pub(crate) struct NoModuleNamed<'a> { #[primary_span] pub span: Span, pub user_path: &'a str, @@ -73,7 +73,7 @@ pub struct NoModuleNamed<'a> { #[derive(Diagnostic)] #[diag(codegen_ssa_field_associated_value_expected)] -pub struct FieldAssociatedValueExpected { +pub(crate) struct FieldAssociatedValueExpected { #[primary_span] pub span: Span, pub name: Symbol, @@ -81,7 +81,7 @@ pub struct FieldAssociatedValueExpected { #[derive(Diagnostic)] #[diag(codegen_ssa_no_field)] -pub struct NoField { +pub(crate) struct NoField { #[primary_span] pub span: Span, pub name: Symbol, @@ -89,49 +89,49 @@ pub struct NoField { #[derive(Diagnostic)] #[diag(codegen_ssa_lib_def_write_failure)] -pub struct LibDefWriteFailure { +pub(crate) struct LibDefWriteFailure { pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_version_script_write_failure)] -pub struct VersionScriptWriteFailure { +pub(crate) struct VersionScriptWriteFailure { pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_symbol_file_write_failure)] -pub struct SymbolFileWriteFailure { +pub(crate) struct SymbolFileWriteFailure { pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_ld64_unimplemented_modifier)] -pub struct Ld64UnimplementedModifier; +pub(crate) struct Ld64UnimplementedModifier; #[derive(Diagnostic)] #[diag(codegen_ssa_linker_unsupported_modifier)] -pub struct LinkerUnsupportedModifier; +pub(crate) struct LinkerUnsupportedModifier; #[derive(Diagnostic)] #[diag(codegen_ssa_L4Bender_exporting_symbols_unimplemented)] -pub struct L4BenderExportingSymbolsUnimplemented; +pub(crate) struct L4BenderExportingSymbolsUnimplemented; #[derive(Diagnostic)] #[diag(codegen_ssa_no_natvis_directory)] -pub struct NoNatvisDirectory { +pub(crate) struct NoNatvisDirectory { pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_no_saved_object_file)] -pub struct NoSavedObjectFile<'a> { +pub(crate) struct NoSavedObjectFile<'a> { pub cgu_name: &'a str, } #[derive(Diagnostic)] #[diag(codegen_ssa_copy_path_buf)] -pub struct CopyPathBuf { +pub(crate) struct CopyPathBuf { pub source_file: PathBuf, pub output_path: PathBuf, pub error: Error, @@ -180,20 +180,20 @@ pub struct IgnoringOutput { #[derive(Diagnostic)] #[diag(codegen_ssa_create_temp_dir)] -pub struct CreateTempDir { +pub(crate) struct CreateTempDir { pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_add_native_library)] -pub struct AddNativeLibrary { +pub(crate) struct AddNativeLibrary { pub library_path: PathBuf, pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_multiple_external_func_decl)] -pub struct MultipleExternalFuncDecl<'a> { +pub(crate) struct MultipleExternalFuncDecl<'a> { #[primary_span] pub span: Span, pub function: Symbol, @@ -215,7 +215,7 @@ pub enum LinkRlibError { IncompatibleDependencyFormats { ty1: String, ty2: String, list1: String, list2: String }, } -pub struct ThorinErrorWrapper(pub thorin::Error); +pub(crate) struct ThorinErrorWrapper(pub thorin::Error); impl Diagnostic<'_, G> for ThorinErrorWrapper { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { @@ -343,7 +343,7 @@ impl Diagnostic<'_, G> for ThorinErrorWrapper { } } -pub struct LinkingFailed<'a> { +pub(crate) struct LinkingFailed<'a> { pub linker_path: &'a PathBuf, pub exit_status: ExitStatus, pub command: &'a Command, @@ -376,28 +376,28 @@ impl Diagnostic<'_, G> for LinkingFailed<'_> { #[derive(Diagnostic)] #[diag(codegen_ssa_link_exe_unexpected_error)] -pub struct LinkExeUnexpectedError; +pub(crate) struct LinkExeUnexpectedError; #[derive(Diagnostic)] #[diag(codegen_ssa_repair_vs_build_tools)] -pub struct RepairVSBuildTools; +pub(crate) struct RepairVSBuildTools; #[derive(Diagnostic)] #[diag(codegen_ssa_missing_cpp_build_tool_component)] -pub struct MissingCppBuildToolComponent; +pub(crate) struct MissingCppBuildToolComponent; #[derive(Diagnostic)] #[diag(codegen_ssa_select_cpp_build_tool_workload)] -pub struct SelectCppBuildToolWorkload; +pub(crate) struct SelectCppBuildToolWorkload; #[derive(Diagnostic)] #[diag(codegen_ssa_visual_studio_not_installed)] -pub struct VisualStudioNotInstalled; +pub(crate) struct VisualStudioNotInstalled; #[derive(Diagnostic)] #[diag(codegen_ssa_linker_not_found)] #[note] -pub struct LinkerNotFound { +pub(crate) struct LinkerNotFound { pub linker_path: PathBuf, pub error: Error, } @@ -406,7 +406,7 @@ pub struct LinkerNotFound { #[diag(codegen_ssa_unable_to_exe_linker)] #[note] #[note(codegen_ssa_command_note)] -pub struct UnableToExeLinker { +pub(crate) struct UnableToExeLinker { pub linker_path: PathBuf, pub error: Error, pub command_formatted: String, @@ -414,38 +414,38 @@ pub struct UnableToExeLinker { #[derive(Diagnostic)] #[diag(codegen_ssa_msvc_missing_linker)] -pub struct MsvcMissingLinker; +pub(crate) struct MsvcMissingLinker; #[derive(Diagnostic)] #[diag(codegen_ssa_self_contained_linker_missing)] -pub struct SelfContainedLinkerMissing; +pub(crate) struct SelfContainedLinkerMissing; #[derive(Diagnostic)] #[diag(codegen_ssa_check_installed_visual_studio)] -pub struct CheckInstalledVisualStudio; +pub(crate) struct CheckInstalledVisualStudio; #[derive(Diagnostic)] #[diag(codegen_ssa_insufficient_vs_code_product)] -pub struct InsufficientVSCodeProduct; +pub(crate) struct InsufficientVSCodeProduct; #[derive(Diagnostic)] #[diag(codegen_ssa_processing_dymutil_failed)] #[note] -pub struct ProcessingDymutilFailed { +pub(crate) struct ProcessingDymutilFailed { pub status: ExitStatus, pub output: String, } #[derive(Diagnostic)] #[diag(codegen_ssa_unable_to_run_dsymutil)] -pub struct UnableToRunDsymutil { +pub(crate) struct UnableToRunDsymutil { pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_stripping_debug_info_failed)] #[note] -pub struct StrippingDebugInfoFailed<'a> { +pub(crate) struct StrippingDebugInfoFailed<'a> { pub util: &'a str, pub status: ExitStatus, pub output: String, @@ -453,58 +453,59 @@ pub struct StrippingDebugInfoFailed<'a> { #[derive(Diagnostic)] #[diag(codegen_ssa_unable_to_run)] -pub struct UnableToRun<'a> { +pub(crate) struct UnableToRun<'a> { pub util: &'a str, pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_linker_file_stem)] -pub struct LinkerFileStem; +pub(crate) struct LinkerFileStem; #[derive(Diagnostic)] #[diag(codegen_ssa_static_library_native_artifacts)] -pub struct StaticLibraryNativeArtifacts; +pub(crate) struct StaticLibraryNativeArtifacts; #[derive(Diagnostic)] #[diag(codegen_ssa_static_library_native_artifacts_to_file)] -pub struct StaticLibraryNativeArtifactsToFile<'a> { +pub(crate) struct StaticLibraryNativeArtifactsToFile<'a> { pub path: &'a Path, } #[derive(Diagnostic)] #[diag(codegen_ssa_link_script_unavailable)] -pub struct LinkScriptUnavailable; +pub(crate) struct LinkScriptUnavailable; #[derive(Diagnostic)] #[diag(codegen_ssa_link_script_write_failure)] -pub struct LinkScriptWriteFailure { +pub(crate) struct LinkScriptWriteFailure { pub path: PathBuf, pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_failed_to_write)] -pub struct FailedToWrite { +pub(crate) struct FailedToWrite { pub path: PathBuf, pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_unable_to_write_debugger_visualizer)] -pub struct UnableToWriteDebuggerVisualizer { +pub(crate) struct UnableToWriteDebuggerVisualizer { pub path: PathBuf, pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_rlib_archive_build_failure)] -pub struct RlibArchiveBuildFailure { +pub(crate) struct RlibArchiveBuildFailure { pub path: PathBuf, pub error: Error, } #[derive(Diagnostic)] +// Public for rustc_codegen_llvm::back::archive pub enum ExtractBundledLibsError<'a> { #[diag(codegen_ssa_extract_bundled_libs_open_file)] OpenFile { rlib: &'a Path, error: Box }, @@ -533,26 +534,26 @@ pub enum ExtractBundledLibsError<'a> { #[derive(Diagnostic)] #[diag(codegen_ssa_unsupported_arch)] -pub struct UnsupportedArch<'a> { +pub(crate) struct UnsupportedArch<'a> { pub arch: &'a str, pub os: &'a str, } #[derive(Diagnostic)] -pub enum AppleSdkRootError<'a> { +pub(crate) enum AppleSdkRootError<'a> { #[diag(codegen_ssa_apple_sdk_error_sdk_path)] SdkPath { sdk_name: &'a str, error: Error }, } #[derive(Diagnostic)] #[diag(codegen_ssa_read_file)] -pub struct ReadFileError { +pub(crate) struct ReadFileError { pub message: std::io::Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_unsupported_link_self_contained)] -pub struct UnsupportedLinkSelfContained; +pub(crate) struct UnsupportedLinkSelfContained; #[derive(Diagnostic)] #[diag(codegen_ssa_archive_build_failure)] @@ -571,7 +572,7 @@ pub struct UnknownArchiveKind<'a> { #[derive(Diagnostic)] #[diag(codegen_ssa_expected_used_symbol)] -pub struct ExpectedUsedSymbol { +pub(crate) struct ExpectedUsedSymbol { #[primary_span] pub span: Span, } @@ -579,45 +580,45 @@ pub struct ExpectedUsedSymbol { #[derive(Diagnostic)] #[diag(codegen_ssa_multiple_main_functions)] #[help] -pub struct MultipleMainFunctions { +pub(crate) struct MultipleMainFunctions { #[primary_span] pub span: Span, } #[derive(Diagnostic)] #[diag(codegen_ssa_metadata_object_file_write)] -pub struct MetadataObjectFileWrite { +pub(crate) struct MetadataObjectFileWrite { pub error: Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_invalid_windows_subsystem)] -pub struct InvalidWindowsSubsystem { +pub(crate) struct InvalidWindowsSubsystem { pub subsystem: Symbol, } #[derive(Diagnostic)] #[diag(codegen_ssa_shuffle_indices_evaluation)] -pub struct ShuffleIndicesEvaluation { +pub(crate) struct ShuffleIndicesEvaluation { #[primary_span] pub span: Span, } #[derive(Diagnostic)] #[diag(codegen_ssa_missing_memory_ordering)] -pub struct MissingMemoryOrdering; +pub(crate) struct MissingMemoryOrdering; #[derive(Diagnostic)] #[diag(codegen_ssa_unknown_atomic_ordering)] -pub struct UnknownAtomicOrdering; +pub(crate) struct UnknownAtomicOrdering; #[derive(Diagnostic)] #[diag(codegen_ssa_atomic_compare_exchange)] -pub struct AtomicCompareExchange; +pub(crate) struct AtomicCompareExchange; #[derive(Diagnostic)] #[diag(codegen_ssa_unknown_atomic_operation)] -pub struct UnknownAtomicOperation; +pub(crate) struct UnknownAtomicOperation; #[derive(Diagnostic)] pub enum InvalidMonomorphization<'tcx> { @@ -986,7 +987,7 @@ impl IntoDiagArg for ExpectedPointerMutability { #[derive(Diagnostic)] #[diag(codegen_ssa_invalid_no_sanitize)] #[note] -pub struct InvalidNoSanitize { +pub(crate) struct InvalidNoSanitize { #[primary_span] pub span: Span, } @@ -994,7 +995,7 @@ pub struct InvalidNoSanitize { #[derive(Diagnostic)] #[diag(codegen_ssa_invalid_link_ordinal_nargs)] #[note] -pub struct InvalidLinkOrdinalNargs { +pub(crate) struct InvalidLinkOrdinalNargs { #[primary_span] pub span: Span, } @@ -1002,14 +1003,14 @@ pub struct InvalidLinkOrdinalNargs { #[derive(Diagnostic)] #[diag(codegen_ssa_illegal_link_ordinal_format)] #[note] -pub struct InvalidLinkOrdinalFormat { +pub(crate) struct InvalidLinkOrdinalFormat { #[primary_span] pub span: Span, } #[derive(Diagnostic)] #[diag(codegen_ssa_target_feature_safe_trait)] -pub struct TargetFeatureSafeTrait { +pub(crate) struct TargetFeatureSafeTrait { #[primary_span] #[label] pub span: Span, @@ -1050,7 +1051,7 @@ pub(crate) struct ErrorCallingDllTool<'a> { #[derive(Diagnostic)] #[diag(codegen_ssa_error_creating_remark_dir)] -pub struct ErrorCreatingRemarkDir { +pub(crate) struct ErrorCreatingRemarkDir { pub error: std::io::Error, } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index c89bfca668789..162d14272a555 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -6,11 +6,13 @@ #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(negative_impls)] #![feature(rustdoc_internals)] #![feature(strict_provenance)] +#![feature(trait_alias)] #![feature(try_blocks)] #![warn(unreachable_pub)] // tidy-alphabetical-end @@ -36,10 +38,10 @@ use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::util::Providers; use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_session::Session; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_session::cstore::{self, CrateSource}; use rustc_session::utils::NativeLibKind; -use rustc_session::Session; use rustc_span::symbol::Symbol; pub mod assert_module_sources; @@ -128,7 +130,7 @@ impl CompiledModule { } } -pub struct CachedModuleCodegen { +pub(crate) struct CachedModuleCodegen { pub name: String, pub source: WorkProduct, } diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index c9602d9cdae1e..7eb0ecd12ffec 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -8,10 +8,10 @@ use tracing::{debug, instrument}; use crate::traits::*; #[derive(Copy, Clone, Debug)] -pub struct VirtualIndex(u64); +pub(crate) struct VirtualIndex(u64); impl<'a, 'tcx> VirtualIndex { - pub fn from_index(index: usize) -> Self { + pub(crate) fn from_index(index: usize) -> Self { VirtualIndex(index as u64) } @@ -28,30 +28,12 @@ impl<'a, 'tcx> VirtualIndex { let llty = bx.fn_ptr_backend_type(fn_abi); let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; let vtable_byte_offset = self.0 * ptr_size.bytes(); - if bx.cx().sess().opts.unstable_opts.virtual_function_elimination - && bx.cx().sess().lto() == Lto::Fat - { - let typeid = bx - .typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty))) - .unwrap(); - let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); - func - } else { - let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); - let ptr = bx.load(llty, gep, ptr_align); - // VTable loads are invariant. - bx.set_invariant_load(ptr); - if nonnull { - bx.nonnull_metadata(ptr); - } - ptr - } + load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, nonnull) } - pub fn get_optional_fn>( + pub(crate) fn get_optional_fn>( self, bx: &mut Bx, llvtable: Bx::Value, @@ -61,7 +43,7 @@ impl<'a, 'tcx> VirtualIndex { self.get_fn_inner(bx, llvtable, ty, fn_abi, false) } - pub fn get_fn>( + pub(crate) fn get_fn>( self, bx: &mut Bx, llvtable: Bx::Value, @@ -71,35 +53,31 @@ impl<'a, 'tcx> VirtualIndex { self.get_fn_inner(bx, llvtable, ty, fn_abi, true) } - pub fn get_usize>( + pub(crate) fn get_usize>( self, bx: &mut Bx, llvtable: Bx::Value, + ty: Ty<'tcx>, ) -> Bx::Value { // Load the data pointer from the object. debug!("get_int({:?}, {:?})", llvtable, self); let llty = bx.type_isize(); let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; let vtable_byte_offset = self.0 * ptr_size.bytes(); - let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); - let ptr = bx.load(llty, gep, ptr_align); - // VTable loads are invariant. - bx.set_invariant_load(ptr); - ptr + load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, false) } } /// This takes a valid `self` receiver type and extracts the principal trait -/// ref of the type. -fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> { +/// ref of the type. Return `None` if there is no principal trait. +fn dyn_trait_in_self(ty: Ty<'_>) -> Option> { for arg in ty.peel_refs().walk() { if let GenericArgKind::Type(ty) = arg.unpack() && let ty::Dynamic(data, _, _) = ty.kind() { - return data.principal().expect("expected principal trait object"); + return data.principal(); } } @@ -115,7 +93,7 @@ fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> { /// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T: Trait`. #[instrument(level = "debug", skip(cx))] -pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( +pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx: &Cx, ty: Ty<'tcx>, trait_ref: Option>, @@ -138,3 +116,36 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable } + +/// Call this function whenever you need to load a vtable. +pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + llvtable: Bx::Value, + llty: Bx::Type, + vtable_byte_offset: u64, + ty: Ty<'tcx>, + nonnull: bool, +) -> Bx::Value { + let ptr_align = bx.data_layout().pointer_align.abi; + + if bx.cx().sess().opts.unstable_opts.virtual_function_elimination + && bx.cx().sess().lto() == Lto::Fat + { + if let Some(trait_ref) = dyn_trait_in_self(ty) { + let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap(); + let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); + return func; + } else if nonnull { + bug!("load nonnull value from a vtable without a principal trait") + } + } + + let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); + let ptr = bx.load(llty, gep, ptr_align); + // VTable loads are invariant. + bx.set_invariant_load(ptr); + if nonnull { + bx.nonnull_metadata(ptr); + } + ptr +} diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 386e1f91e7f0c..43b8230c679e1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -5,7 +5,7 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, traversal, DefLocation, Location, TerminatorKind}; +use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind, traversal}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::{bug, span_bug}; use tracing::debug; @@ -15,6 +15,7 @@ use crate::traits::*; pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx: &FunctionCx<'a, 'tcx, Bx>, + traversal_order: &[mir::BasicBlock], ) -> BitSet { let mir = fx.mir; let dominators = mir.basic_blocks.dominators(); @@ -24,13 +25,7 @@ pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( .map(|decl| { let ty = fx.monomorphize(decl.ty); let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span); - if layout.is_zst() { - LocalKind::ZST - } else if fx.cx.is_backend_immediate(layout) || fx.cx.is_backend_scalar_pair(layout) { - LocalKind::Unused - } else { - LocalKind::Memory - } + if layout.is_zst() { LocalKind::ZST } else { LocalKind::Unused } }) .collect(); @@ -44,7 +39,8 @@ pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // If there exists a local definition that dominates all uses of that local, // the definition should be visited first. Traverse blocks in an order that // is a topological sort of dominance partial order. - for (bb, data) in traversal::reverse_postorder(mir) { + for bb in traversal_order.iter().copied() { + let data = &mir.basic_blocks[bb]; analyzer.visit_basic_block_data(bb, data); } @@ -69,19 +65,30 @@ enum LocalKind { SSA(DefLocation), } -struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { - fx: &'mir FunctionCx<'a, 'tcx, Bx>, - dominators: &'mir Dominators, +struct LocalAnalyzer<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> { + fx: &'a FunctionCx<'b, 'tcx, Bx>, + dominators: &'a Dominators, locals: IndexVec, } -impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { +impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx> { fn define(&mut self, local: mir::Local, location: DefLocation) { + let fx = self.fx; let kind = &mut self.locals[local]; + let decl = &fx.mir.local_decls[local]; match *kind { LocalKind::ZST => {} LocalKind::Memory => {} - LocalKind::Unused => *kind = LocalKind::SSA(location), + LocalKind::Unused => { + let ty = fx.monomorphize(decl.ty); + let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span); + *kind = + if fx.cx.is_backend_immediate(layout) || fx.cx.is_backend_scalar_pair(layout) { + LocalKind::SSA(location) + } else { + LocalKind::Memory + }; + } LocalKind::SSA(_) => *kind = LocalKind::Memory, } } @@ -152,9 +159,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, } } -impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> - for LocalAnalyzer<'mir, 'a, 'tcx, Bx> -{ +impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer<'a, 'b, 'tcx, Bx> { fn visit_assign( &mut self, place: &mir::Place<'tcx>, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 817e2ca72ec12..125d3b908c733 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg}; use rustc_target::abi::{self, HasDataLayout, WrappingRange}; use rustc_target::spec::abi::Abi; @@ -24,7 +24,7 @@ use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphizat use crate::common::{self, IntPredicate}; use crate::errors::CompilerBuiltinsCannotCall; use crate::traits::*; -use crate::{meth, MemFlags}; +use crate::{MemFlags, meth}; // Indicates if we are in the middle of merging a BB's successor into it. This // can happen when BB jumps directly to its successor and the successor has no @@ -915,32 +915,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; - let args: Vec<_> = args - .iter() - .enumerate() - .map(|(i, arg)| { - // The indices passed to simd_shuffle in the - // third argument must be constant. This is - // checked by the type-checker. - if i == 2 && intrinsic.name == sym::simd_shuffle { - // FIXME: the simd_shuffle argument is actually an array, - // not a vector, so we need this special hack to make sure - // it is passed as an immediate. We should pass the - // shuffle indices as a vector instead to avoid this hack. - if let mir::Operand::Constant(constant) = &arg.node { - let (llval, ty) = self.immediate_const_vector(bx, constant); - return OperandRef { - val: Immediate(llval), - layout: bx.layout_of(ty), - }; - } else { - span_bug!(span, "shuffle indices must be constant"); - } - } - - self.codegen_operand(bx, &arg.node) - }) - .collect(); + let args: Vec<_> = + args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { let location = self @@ -1020,7 +996,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // To get a `*mut RcBox`, we just keep unwrapping newtypes until // we get a value of a built-in pointer type. // - // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`. + // This is also relevant for `Pin<&mut Self>`, where we need to peel the + // `Pin`. while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", @@ -1028,9 +1005,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { op = op.extract_field(bx, idx); } - // now that we have `*dyn Trait` or `&dyn Trait`, split it up into its + // Now that we have `*dyn Trait` or `&dyn Trait`, split it up into its // data pointer and vtable. Look up the method in the vtable, and pass - // the data pointer as the first argument + // the data pointer as the first argument. llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( bx, meta, @@ -1236,10 +1213,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mergeable_succ, ) } -} -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn codegen_block(&mut self, mut bb: mir::BasicBlock) { + pub(crate) fn codegen_block(&mut self, mut bb: mir::BasicBlock) { let llbb = match self.try_llbb(bb) { Some(llbb) => llbb, None => return, @@ -1279,7 +1254,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - pub fn codegen_block_as_unreachable(&mut self, bb: mir::BasicBlock) { + pub(crate) fn codegen_block_as_unreachable(&mut self, bb: mir::BasicBlock) { let llbb = match self.try_llbb(bb) { Some(llbb) => llbb, None => return, @@ -1464,8 +1439,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (mut llval, align, by_ref) = match op.val { Immediate(_) | Pair(..) => match arg.mode { PassMode::Indirect { attrs, .. } => { - // Indirect argument may have higher alignment requirements than the type's alignment. - // This can happen, e.g. when passing types with <4 byte alignment on the stack on x86. + // Indirect argument may have higher alignment requirements than the type's + // alignment. This can happen, e.g. when passing types with <4 byte alignment + // on the stack on x86. let required_align = match attrs.pointee_align { Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi), None => arg.layout.align.abi, @@ -1614,10 +1590,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let Some(slot) = self.personality_slot { slot } else { - let layout = cx.layout_of(Ty::new_tup( - cx.tcx(), - &[Ty::new_mut_ptr(cx.tcx(), cx.tcx().types.u8), cx.tcx().types.i32], - )); + let layout = cx.layout_of(Ty::new_tup(cx.tcx(), &[ + Ty::new_mut_ptr(cx.tcx(), cx.tcx().types.u8), + cx.tcx().types.i32, + ])); let slot = PlaceRef::alloca(bx, layout); self.personality_slot = Some(slot); slot @@ -1764,7 +1740,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } /// Like `llbb`, but may fail if the basic block should be skipped. - pub fn try_llbb(&mut self, bb: mir::BasicBlock) -> Option { + pub(crate) fn try_llbb(&mut self, bb: mir::BasicBlock) -> Option { match self.cached_llbbs[bb] { CachedLlbb::None => { let llbb = Bx::append_block(self.cx, self.llfn, &format!("{bb:?}")); diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 0aa85b8203825..15f45b226f5e4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::HasTyCtxt; -use rustc_middle::ty::{self, Ty, ValTree}; +use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_target::abi::Abi; @@ -10,7 +10,7 @@ use crate::mir::operand::OperandRef; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn eval_mir_constant_to_operand( + pub(crate) fn eval_mir_constant_to_operand( &self, bx: &mut Bx, constant: &mir::ConstOperand<'tcx>, @@ -32,27 +32,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// that the given `constant` is an `Const::Unevaluated` and must be convertible to /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip. /// - /// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees! - pub fn eval_unevaluated_mir_constant_to_valtree( + /// Note that this function is cursed, since usually MIR consts should not be evaluated to + /// valtrees! + fn eval_unevaluated_mir_constant_to_valtree( &self, constant: &mir::ConstOperand<'tcx>, ) -> Result, Ty<'tcx>>, ErrorHandled> { let uv = match self.monomorphize(constant.const_) { mir::Const::Unevaluated(uv, _) => uv.shrink(), mir::Const::Ty(_, c) => match c.kind() { - // A constant that came from a const generic but was then used as an argument to old-style - // simd_shuffle (passing as argument instead of as a generic param). + // A constant that came from a const generic but was then used as an argument to + // old-style simd_shuffle (passing as argument instead of as a generic param). rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)), other => span_bug!(constant.span, "{other:#?}"), }, // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate - // a constant and write that value back into `Operand`s. This could happen, but is unlikely. - // Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care - // around intrinsics. For an issue to happen here, it would require a macro expanding to a - // `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but - // the user pass through arbitrary expressions. - // FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real - // const generic, and get rid of this entire function. + // a constant and write that value back into `Operand`s. This could happen, but is + // unlikely. Also: all users of `simd_shuffle` are on unstable and already need to take + // a lot of care around intrinsics. For an issue to happen here, it would require a + // macro expanding to a `simd_shuffle` call without wrapping the constant argument in a + // `const {}` block, but the user pass through arbitrary expressions. + // FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a + // real const generic, and get rid of this entire function. other => span_bug!(constant.span, "{other:#?}"), }; let uv = self.monomorphize(uv); @@ -66,15 +67,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant: &mir::ConstOperand<'tcx>, ) -> (Bx::Value, Ty<'tcx>) { let ty = self.monomorphize(constant.ty()); - let ty_is_simd = ty.is_simd(); - // FIXME: ideally we'd assert that this is a SIMD type, but simd_shuffle - // in its current form relies on a regular array being passed as an - // immediate argument. This hack can be removed once that is fixed. - let field_ty = if ty_is_simd { - ty.simd_size_and_type(bx.tcx()).1 - } else { - ty.builtin_index().unwrap() - }; + assert!(ty.is_simd()); + let field_ty = ty.simd_size_and_type(bx.tcx()).1; let val = self .eval_unevaluated_mir_constant_to_valtree(constant) @@ -82,19 +76,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .map(|x| x.ok()) .flatten() .map(|val| { - // Depending on whether this is a SIMD type with an array field - // or a type with many fields (one for each elements), the valtree - // is either a single branch with N children, or a root node - // with exactly one child which then in turn has many children. - // So we look at the first child to determine whether it is a - // leaf or whether we have to go one more layer down. - let branch_or_leaf = val.unwrap_branch(); - let first = branch_or_leaf.get(0).unwrap(); - let field_iter = match first { - ValTree::Branch(_) => first.unwrap_branch().iter(), - ValTree::Leaf(_) => branch_or_leaf.iter(), - }; - let values: Vec<_> = field_iter + // A SIMD type has a single field, which is an array. + let fields = val.unwrap_branch(); + assert_eq!(fields.len(), 1); + let array = fields[0].unwrap_branch(); + // Iterate over the array elements to obtain the values in the vector. + let values: Vec<_> = array + .iter() .map(|field| { if let Some(prim) = field.try_to_scalar() { let layout = bx.layout_of(field_ty); @@ -107,7 +95,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }) .collect(); - if ty_is_simd { bx.const_vector(&values) } else { bx.const_struct(&values, false) } + bx.const_vector(&values) }) .unwrap_or_else(|| { bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span }); diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index 67f1ef5d9449c..33a050ef2804f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -1,11 +1,11 @@ -use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::SourceScope; +use rustc_middle::mir::coverage::CoverageKind; use super::FunctionCx; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn codegen_coverage(&self, bx: &mut Bx, kind: &CoverageKind, scope: SourceScope) { + pub(crate) fn codegen_coverage(&self, bx: &mut Bx, kind: &CoverageKind, scope: SourceScope) { // Determine the instance that coverage data was originally generated for. let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) { self.monomorphize(inlined) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 75692540c0345..146f55f95c21a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -1,4 +1,5 @@ use std::collections::hash_map::Entry; +use std::marker::PhantomData; use std::ops::Range; use rustc_data_structures::fx::FxHashMap; @@ -8,13 +9,13 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty}; use rustc_middle::{bug, mir, ty}; use rustc_session::config::DebugInfo; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{hygiene, BytePos, Span}; +use rustc_span::symbol::{Symbol, kw}; +use rustc_span::{BytePos, Span, hygiene}; use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; use super::place::{PlaceRef, PlaceValue}; -use super::{FunctionCx, LocalRef}; +use super::{FunctionCx, LocalRef, PerLocalVarDebugInfoIndexVec}; use crate::traits::*; pub struct FunctionDebugContext<'tcx, S, L> { @@ -24,6 +25,7 @@ pub struct FunctionDebugContext<'tcx, S, L> { /// Maps from an inlined function to its debug info declaration. pub inlined_function_scopes: FxHashMap, S>, } + #[derive(Copy, Clone)] pub enum VariableKind { ArgumentVariable(usize /*index*/), @@ -47,6 +49,17 @@ pub struct PerLocalVarDebugInfo<'tcx, D> { pub projection: &'tcx ty::List>, } +/// Information needed to emit a constant. +pub struct ConstDebugInfo<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { + pub name: String, + pub source_info: mir::SourceInfo, + pub operand: OperandRef<'tcx, Bx::Value>, + pub dbg_var: Bx::DIVariable, + pub dbg_loc: Bx::DILocation, + pub fragment: Option>, + pub _phantom: PhantomData<&'a ()>, +} + #[derive(Clone, Copy, Debug)] pub struct DebugScope { pub dbg_scope: S, @@ -243,7 +256,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// Apply debuginfo and/or name, after creating the `alloca` for a local, /// or initializing the local with an operand (whichever applies). - pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { + pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; let vars = match &self.per_local_var_debug_info { @@ -426,19 +439,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - pub fn debug_introduce_locals(&self, bx: &mut Bx) { + pub(crate) fn debug_introduce_locals( + &self, + bx: &mut Bx, + consts: Vec>, + ) { if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() { for local in self.locals.indices() { self.debug_introduce_local(bx, local); } + + for ConstDebugInfo { name, source_info, operand, dbg_var, dbg_loc, fragment, .. } in + consts.into_iter() + { + self.set_debug_loc(bx, source_info); + let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx); + bx.clear_dbg_loc(); + + bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], fragment); + } } } /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`. - pub fn compute_per_local_var_debug_info( + pub(crate) fn compute_per_local_var_debug_info( &self, bx: &mut Bx, - ) -> Option>>> { + ) -> Option<( + PerLocalVarDebugInfoIndexVec<'tcx, Bx::DIVariable>, + Vec>, + )> { let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full; let target_is_msvc = self.cx.sess().target.is_like_msvc; @@ -448,6 +478,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls); + let mut constants = vec![]; let mut params_seen: FxHashMap<_, Bx::DIVariable> = Default::default(); for var in &self.mir.var_debug_info { let dbg_scope_and_span = if full_debug_info { @@ -544,22 +575,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; let operand = self.eval_mir_constant_to_operand(bx, &c); - self.set_debug_loc(bx, var.source_info); - let base = - Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx); - - bx.dbg_var_addr( + constants.push(ConstDebugInfo { + name: var.name.to_string(), + source_info: var.source_info, + operand, dbg_var, dbg_loc, - base.val.llval, - Size::ZERO, - &[], fragment, - ); + _phantom: PhantomData, + }); } } } } - Some(per_local) + Some((per_local, constants)) } } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 4acbc04c505e8..32cc78187b9eb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,16 +1,16 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; -use rustc_span::{sym, Span}; -use rustc_target::abi::call::{FnAbi, PassMode}; +use rustc_span::{Span, sym}; use rustc_target::abi::WrappingRange; +use rustc_target::abi::call::{FnAbi, PassMode}; +use super::FunctionCx; use super::operand::OperandRef; use super::place::PlaceRef; -use super::FunctionCx; use crate::errors::InvalidMonomorphization; use crate::traits::*; -use crate::{errors, meth, size_of_val, MemFlags}; +use crate::{MemFlags, errors, meth, size_of_val}; fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, @@ -126,7 +126,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, _ => bug!(), }; - let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable); + let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable, callee_ty); match name { // Size is always <= isize::MAX. sym::vtable_size => { diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index de94d87bcea7a..c4fb24aa625d9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -1,9 +1,9 @@ use std::iter; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::{traversal, UnwindTerminateReason}; +use rustc_middle::mir::{UnwindTerminateReason, traversal}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::{bug, mir, span_bug}; @@ -15,8 +15,8 @@ use crate::traits::*; mod analyze; mod block; -pub mod constant; -pub mod coverageinfo; +mod constant; +mod coverageinfo; pub mod debuginfo; mod intrinsic; mod locals; @@ -41,6 +41,9 @@ enum CachedLlbb { Skip, } +type PerLocalVarDebugInfoIndexVec<'tcx, V> = + IndexVec>>; + /// Master context for codegenning from MIR. pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { instance: Instance<'tcx>, @@ -107,8 +110,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// All `VarDebugInfo` from the MIR body, partitioned by `Local`. /// This is `None` if no variable debuginfo/names are needed. - per_local_var_debug_info: - Option>>>, + per_local_var_debug_info: Option>, /// Caller location propagated if this function has `#[track_caller]`. caller_location: Option>, @@ -216,9 +218,12 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // monomorphization, and if there is an error during collection then codegen never starts -- so // we don't have to do it again. - fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx); + let (per_local_var_debug_info, consts_debug_info) = + fx.compute_per_local_var_debug_info(&mut start_bx).unzip(); + fx.per_local_var_debug_info = per_local_var_debug_info; - let memory_locals = analyze::non_ssa_locals(&fx); + let traversal_order = traversal::mono_reachable_reverse_postorder(mir, cx.tcx(), instance); + let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order); // Allocate variable and temp allocas let local_values = { @@ -267,7 +272,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx.initialize_locals(local_values); // Apply debuginfo to the newly allocated locals. - fx.debug_introduce_locals(&mut start_bx); + fx.debug_introduce_locals(&mut start_bx, consts_debug_info.unwrap_or_default()); // If the backend supports coverage, and coverage is enabled for this function, // do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps). @@ -277,17 +282,20 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // So drop the builder of `start_llbb` to avoid having two at the same time. drop(start_bx); - let reachable_blocks = traversal::mono_reachable_as_bitset(mir, cx.tcx(), instance); + let mut unreached_blocks = BitSet::new_filled(mir.basic_blocks.len()); + // Codegen the body of each reachable block using our reverse postorder list. + for bb in traversal_order { + fx.codegen_block(bb); + unreached_blocks.remove(bb); + } - // Codegen the body of each block using reverse postorder - for (bb, _) in traversal::reverse_postorder(mir) { - if reachable_blocks.contains(bb) { - fx.codegen_block(bb); - } else { - // We want to skip this block, because it's not reachable. But we still create - // the block so terminators in other blocks can reference it. - fx.codegen_block_as_unreachable(bb); - } + // FIXME: These empty unreachable blocks are *mostly* a waste. They are occasionally + // targets for a SwitchInt terminator, but the reimplementation of the mono-reachable + // simplification in SwitchInt lowering sometimes misses cases that + // mono_reachable_reverse_postorder manages to figure out. + // The solution is to do something like post-mono GVN. But for now we have this hack. + for bb in unreached_blocks.iter() { + fx.codegen_block_as_unreachable(bb); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 1891de8c0eb37..17f66c12a0332 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -4,17 +4,17 @@ use std::fmt; use arrayvec::ArrayVec; use either::Either; use rustc_middle::bug; -use rustc_middle::mir::interpret::{alloc_range, Pointer, Scalar}; +use rustc_middle::mir::interpret::{Pointer, Scalar, alloc_range}; use rustc_middle::mir::{self, ConstValue}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_target::abi::{self, Abi, Align, Size}; use tracing::debug; use super::place::{PlaceRef, PlaceValue}; use super::{FunctionCx, LocalRef}; use crate::traits::*; -use crate::{size_of_val, MemFlags}; +use crate::{MemFlags, size_of_val}; /// The representation of a Rust value. The enum variant is in fact /// uniquely determined by the value's type, but is kept as a @@ -27,32 +27,32 @@ pub enum OperandValue { /// which indicates that it refers to an unsized rvalue. /// /// An `OperandValue` *must* be this variant for any type for which - /// [`LayoutTypeMethods::is_backend_ref`] returns `true`. + /// [`LayoutTypeCodegenMethods::is_backend_ref`] returns `true`. /// (That basically amounts to "isn't one of the other variants".) /// /// This holds a [`PlaceValue`] (like a [`PlaceRef`] does) with a pointer /// to the location holding the value. The type behind that pointer is the - /// one returned by [`LayoutTypeMethods::backend_type`]. + /// one returned by [`LayoutTypeCodegenMethods::backend_type`]. Ref(PlaceValue), /// A single LLVM immediate value. /// /// An `OperandValue` *must* be this variant for any type for which - /// [`LayoutTypeMethods::is_backend_immediate`] returns `true`. + /// [`LayoutTypeCodegenMethods::is_backend_immediate`] returns `true`. /// The backend value in this variant must be the *immediate* backend type, - /// as returned by [`LayoutTypeMethods::immediate_backend_type`]. + /// as returned by [`LayoutTypeCodegenMethods::immediate_backend_type`]. Immediate(V), /// A pair of immediate LLVM values. Used by fat pointers too. /// /// An `OperandValue` *must* be this variant for any type for which - /// [`LayoutTypeMethods::is_backend_scalar_pair`] returns `true`. + /// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`. /// The backend values in this variant must be the *immediate* backend types, - /// as returned by [`LayoutTypeMethods::scalar_pair_element_backend_type`] + /// as returned by [`LayoutTypeCodegenMethods::scalar_pair_element_backend_type`] /// with `immediate: true`. Pair(V, V), /// A value taking no bytes, and which therefore needs no LLVM value at all. /// /// If you ever need a `V` to pass to something, get a fresh poison value - /// from [`ConstMethods::const_poison`]. + /// from [`ConstCodegenMethods::const_poison`]. /// /// An `OperandValue` *must* be this variant for any type for which /// `is_zst` on its `Layout` returns `true`. Note however that @@ -64,7 +64,7 @@ impl OperandValue { /// If this is ZeroSized/Immediate/Pair, return an array of the 0/1/2 values. /// If this is Ref, return the place. #[inline] - pub fn immediates_or_place(self) -> Either, PlaceValue> { + pub(crate) fn immediates_or_place(self) -> Either, PlaceValue> { match self { OperandValue::ZeroSized => Either::Left(ArrayVec::new()), OperandValue::Immediate(a) => Either::Left(ArrayVec::from_iter([a])), @@ -75,7 +75,7 @@ impl OperandValue { /// Given an array of 0/1/2 immediate values, return ZeroSized/Immediate/Pair. #[inline] - pub fn from_immediates(immediates: ArrayVec) -> Self { + pub(crate) fn from_immediates(immediates: ArrayVec) -> Self { let mut it = immediates.into_iter(); let Some(a) = it.next() else { return OperandValue::ZeroSized; @@ -90,7 +90,7 @@ impl OperandValue { /// optional metadata as backend values. /// /// If you're making a place, use [`Self::deref`] instead. - pub fn pointer_parts(self) -> (V, Option) { + pub(crate) fn pointer_parts(self) -> (V, Option) { match self { OperandValue::Immediate(llptr) => (llptr, None), OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)), @@ -105,12 +105,12 @@ impl OperandValue { /// alignment, then maybe you want [`OperandRef::deref`] instead. /// /// This is the inverse of [`PlaceValue::address`]. - pub fn deref(self, align: Align) -> PlaceValue { + pub(crate) fn deref(self, align: Align) -> PlaceValue { let (llval, llextra) = self.pointer_parts(); PlaceValue { llval, llextra, align } } - pub(crate) fn is_expected_variant_for_type<'tcx, Cx: LayoutTypeMethods<'tcx>>( + pub(crate) fn is_expected_variant_for_type<'tcx, Cx: LayoutTypeCodegenMethods<'tcx>>( &self, cx: &Cx, ty: TyAndLayout<'tcx>, @@ -153,7 +153,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { OperandRef { val: OperandValue::ZeroSized, layout } } - pub fn from_const>( + pub(crate) fn from_const>( bx: &mut Bx, val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, @@ -280,7 +280,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { /// /// If you don't need the type, see [`OperandValue::pointer_parts`] /// or [`OperandValue::deref`]. - pub fn deref>(self, cx: &Cx) -> PlaceRef<'tcx, V> { + pub fn deref>(self, cx: &Cx) -> PlaceRef<'tcx, V> { if self.layout.ty.is_box() { // Derefer should have removed all Box derefs bug!("dereferencing {:?} in codegen", self.layout.ty); @@ -334,7 +334,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { OperandRef { val, layout } } - pub fn extract_field>( + pub(crate) fn extract_field>( &self, bx: &mut Bx, i: usize, @@ -478,8 +478,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); match self { OperandValue::ZeroSized => { - // Avoid generating stores of zero-sized values, because the only way to have a zero-sized - // value is through `undef`/`poison`, and the store itself is useless. + // Avoid generating stores of zero-sized values, because the only way to have a + // zero-sized value is through `undef`/`poison`, and the store itself is useless. } OperandValue::Ref(val) => { assert!(dest.layout.is_sized(), "cannot directly store unsized values"); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 0fad4d169edd5..0b764ae7747d8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { Self::alloca(bx, ptr_layout) } - pub fn len>(&self, cx: &Cx) -> V { + pub fn len>(&self, cx: &Cx) -> V { if let FieldsShape::Array { count, .. } = self.layout.fields { if self.layout.is_unsized() { assert_eq!(count, 0); @@ -415,11 +415,10 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout.size }; - let llval = bx.inbounds_gep( - bx.cx().backend_type(self.layout), - self.val.llval, - &[bx.cx().const_usize(0), llindex], - ); + let llval = bx.inbounds_gep(bx.cx().backend_type(self.layout), self.val.llval, &[ + bx.cx().const_usize(0), + llindex, + ]); let align = self.val.align.restrict_for_offset(offset); PlaceValue::new_sized(llval, align).with_type(layout) } @@ -470,10 +469,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Operand(..) => { if place_ref.is_indirect_first_projection() { base = 1; - let cg_base = self.codegen_consume( - bx, - mir::PlaceRef { projection: &place_ref.projection[..0], ..place_ref }, - ); + let cg_base = self.codegen_consume(bx, mir::PlaceRef { + projection: &place_ref.projection[..0], + ..place_ref + }); cg_base.deref(bx.cx()) } else { bug!("using operand local {:?} as place", place_ref); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d94c6f8ddcec3..f9c0f3ce94146 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -6,8 +6,8 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_session::config::OptLevel; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{self, FieldIdx, FIRST_VARIANT}; +use rustc_span::{DUMMY_SP, Span}; +use rustc_target::abi::{self, FIRST_VARIANT, FieldIdx}; use tracing::{debug, instrument}; use super::operand::{OperandRef, OperandValue}; @@ -15,11 +15,11 @@ use super::place::PlaceRef; use super::{FunctionCx, LocalRef}; use crate::common::IntPredicate; use crate::traits::*; -use crate::{base, MemFlags}; +use crate::{MemFlags, base}; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "trace", skip(self, bx))] - pub fn codegen_rvalue( + pub(crate) fn codegen_rvalue( &mut self, bx: &mut Bx, dest: PlaceRef<'tcx, Bx::Value>, @@ -34,7 +34,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::Unsize), + mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _), ref source, _, ) => { @@ -114,7 +114,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let count = self .monomorphize(count) - .eval_target_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); + .try_to_target_usize(bx.tcx()) + .expect("expected monomorphic const in codegen"); bx.write_operand_repeatedly(cg_elem, count, dest); } @@ -382,7 +383,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { scalar: abi::Scalar, backend_ty: Bx::Type, ) { - if matches!(self.cx.sess().opts.optimize, OptLevel::No | OptLevel::Less) + if matches!(self.cx.sess().opts.optimize, OptLevel::No) // For now, the critical niches are all over `Int`eger values. // Should floating-point values or pointers ever get more complex // niches, then this code will probably want to handle them too. @@ -419,7 +420,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - pub fn codegen_rvalue_unsized( + pub(crate) fn codegen_rvalue_unsized( &mut self, bx: &mut Bx, indirect_dest: PlaceRef<'tcx, Bx::Value>, @@ -440,7 +441,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - pub fn codegen_rvalue_operand( + pub(crate) fn codegen_rvalue_operand( &mut self, bx: &mut Bx, rvalue: &mir::Rvalue<'tcx>, @@ -464,7 +465,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let lladdr = bx.ptrtoint(llptr, llcast_ty); OperandValue::Immediate(lladdr) } - mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { + mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => { match *operand.layout.ty.kind() { ty::FnDef(def_id, args) => { let instance = ty::Instance::resolve_for_fn_ptr( @@ -480,7 +481,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), } } - mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)) => { + mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _) => { match *operand.layout.ty.kind() { ty::Closure(def_id, args) => { let instance = Instance::resolve_closure( @@ -495,11 +496,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty), } } - mir::CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { + mir::CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _) => { // This is a no-op at the LLVM level. operand.val } - mir::CastKind::PointerCoercion(PointerCoercion::Unsize) => { + mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _) => { assert!(bx.cx().is_backend_scalar_pair(cast)); let (lldata, llextra) = operand.val.pointer_parts(); let (lldata, llextra) = @@ -507,7 +508,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Pair(lldata, llextra) } mir::CastKind::PointerCoercion( - PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, + PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _ ) => { bug!("{kind:?} is for borrowck, and should never appear in codegen"); } @@ -525,7 +526,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("unexpected non-pair operand"); } } - mir::CastKind::DynStar => { + mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { let (lldata, llextra) = operand.val.pointer_parts(); let (lldata, llextra) = base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra); @@ -803,7 +804,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let Some(index) = place.as_local() { if let LocalRef::Operand(op) = self.locals[index] { if let ty::Array(_, n) = op.layout.ty.kind() { - let n = n.eval_target_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); + let n = n + .try_to_target_usize(bx.tcx()) + .expect("expected monomorphic const in codegen"); return bx.cx().const_usize(n); } } @@ -836,7 +839,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) } } - pub fn codegen_scalar_binop( + fn codegen_scalar_binop( &mut self, bx: &mut Bx, op: mir::BinOp, @@ -981,7 +984,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - pub fn codegen_fat_ptr_binop( + fn codegen_fat_ptr_binop( &mut self, bx: &mut Bx, op: mir::BinOp, @@ -1023,7 +1026,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - pub fn codegen_scalar_checked_binop( + fn codegen_scalar_checked_binop( &mut self, bx: &mut Bx, op: mir::BinOp, @@ -1047,10 +1050,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Pair(val, of) } -} -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { + pub(crate) fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { match *rvalue { mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => { let operand_ty = operand.ty(self.mir, self.cx.tcx()); diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 2ef860fc336d6..6338d16c897f6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,6 +1,5 @@ use rustc_middle::mir::{self, NonDivergingIntrinsic}; use rustc_middle::span_bug; -use rustc_session::config::OptLevel; use tracing::instrument; use super::{FunctionCx, LocalRef}; @@ -8,7 +7,7 @@ use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "debug", skip(self, bx))] - pub fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) { + pub(crate) fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) { self.set_debug_loc(bx, statement.source_info); match statement.kind { mir::StatementKind::Assign(box (ref place, ref rvalue)) => { @@ -68,10 +67,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_coverage(bx, kind, statement.source_info.scope); } mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => { - if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) { - let op_val = self.codegen_operand(bx, op); - bx.assume(op_val.immediate()); - } + let op_val = self.codegen_operand(bx, op); + bx.assume(op_val.immediate()); } mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( mir::CopyNonOverlapping { ref count, ref src, ref dst }, diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 64fcefdc860cd..038c5857face1 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,8 +1,8 @@ use rustc_hir as hir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::Instance; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::{span_bug, ty}; use tracing::debug; diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 933904f984505..827b939217e82 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -28,9 +28,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Load size/align from vtable. let vtable = info.unwrap(); let size = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE) - .get_usize(bx, vtable); + .get_usize(bx, vtable, t); let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN) - .get_usize(bx, vtable); + .get_usize(bx, vtable, t); // Size is always <= isize::MAX. let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128; @@ -45,11 +45,13 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // The info in this case is the length of the str, so the size is that // times the unit size. ( - // All slice sizes must fit into `isize`, so this multiplication cannot (signed) wrap. + // All slice sizes must fit into `isize`, so this multiplication cannot (signed) + // wrap. // NOTE: ideally, we want the effects of both `unchecked_smul` and `unchecked_umul` // (resulting in `mul nsw nuw` in LLVM IR), since we know that the multiplication - // cannot signed wrap, and that both operands are non-negative. But at the time of writing, - // the `LLVM-C` binding can't do this, and it doesn't seem to enable any further optimizations. + // cannot signed wrap, and that both operands are non-negative. But at the time of + // writing, the `LLVM-C` binding can't do this, and it doesn't seem to enable any + // further optimizations. bx.unchecked_smul(info.unwrap(), bx.const_usize(unit.size.bytes())), bx.const_usize(unit.align.abi.bytes()), ) @@ -67,9 +69,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let (fn_abi, llfn, _instance) = common::build_langcall(bx, None, LangItem::PanicNounwind); - // Generate the call. - // Cannot use `do_call` since we don't have a MIR terminator so we can't create a `TerminationCodegenHelper`. - // (But we are in good company, this code is duplicated plenty of times.) + // Generate the call. Cannot use `do_call` since we don't have a MIR terminator so we + // can't create a `TerminationCodegenHelper`. (But we are in good company, this code is + // duplicated plenty of times.) let fn_ty = bx.fn_decl_backend_type(fn_abi); bx.call( @@ -148,9 +150,14 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // The full formula for the size would be: // let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align); // let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align); - // However, `unsized_size` is a multiple of `unsized_align`. - // Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`: - // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(unsized_align).align_to(full_align); + // However, `unsized_size` is a multiple of `unsized_align`. Therefore, we can + // equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`: + // + // let full_size = + // (unsized_offset_unadjusted + unsized_size) + // .align_to(unsized_align) + // .align_to(full_align); + // // Furthermore, `align >= unsized_align`, and therefore we only need to do: // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align); diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index cf8f7fa25d856..dfe8fd616e4a2 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -4,18 +4,18 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use crate::errors; -pub fn from_target_feature( +pub(crate) fn from_target_feature( tcx: TyCtxt<'_>, attr: &ast::Attribute, supported_target_features: &UnordMap>, @@ -146,7 +146,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet { /// Checks the function annotated with `#[target_feature]` is not a safe /// trait method implementation, reporting an error if it is. -pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { +pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { if let DefKind::AssocFn = tcx.def_kind(id) { let parent_id = tcx.local_parent(id); if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) { diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index 162141a106bcc..f4853da115648 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -60,7 +60,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes { ); } -pub trait AsmMethods<'tcx> { +pub trait AsmCodegenMethods<'tcx> { fn codegen_global_asm( &self, template: &[InlineAsmTemplatePiece], diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index c5e2d55be833d..676fb181d67cc 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -5,24 +5,23 @@ use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::ErrorGuaranteed; -use rustc_metadata::creader::MetadataLoaderDyn; use rustc_metadata::EncodedMetadata; +use rustc_metadata::creader::MetadataLoaderDyn; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; -use rustc_session::config::{self, OutputFilenames, PrintRequest}; use rustc_session::Session; +use rustc_session::config::{self, OutputFilenames, PrintRequest}; use rustc_span::symbol::Symbol; -use rustc_target::abi::call::FnAbi; -use super::write::WriteBackendMethods; use super::CodegenObject; +use super::write::WriteBackendMethods; use crate::back::write::TargetMachineFactoryFn; use crate::{CodegenResults, ModuleCodegen}; pub trait BackendTypes { type Value: CodegenObject; + type Metadata: CodegenObject; type Function: CodegenObject; type BasicBlock: Copy; @@ -36,34 +35,21 @@ pub trait BackendTypes { type DIVariable: Copy; } -pub trait Backend<'tcx>: - Sized - + BackendTypes - + HasTyCtxt<'tcx> - + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> - + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> -{ -} - -impl<'tcx, T> Backend<'tcx> for T where - Self: BackendTypes - + HasTyCtxt<'tcx> - + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> - + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> -{ -} - pub trait CodegenBackend { /// Locale resources for diagnostic messages - a string the content of the Fluent resource. /// Called before `init` so that all other functions are able to emit translatable diagnostics. fn locale_resource(&self) -> &'static str; fn init(&self, _sess: &Session) {} + fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} + fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { vec![] } + fn print_passes(&self) {} + fn print_version(&self) {} /// The metadata loader used to load rlib and dylib metadata. @@ -75,6 +61,7 @@ pub trait CodegenBackend { } fn provide(&self, _providers: &mut Providers) {} + fn codegen_crate<'tcx>( &self, tcx: TyCtxt<'tcx>, @@ -120,6 +107,7 @@ pub trait ExtraBackendMethods: kind: AllocatorKind, 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. fn compile_codegen_unit( @@ -127,6 +115,7 @@ pub trait ExtraBackendMethods: tcx: TyCtxt<'_>, cgu_name: Symbol, ) -> (ModuleCodegen, u64); + fn target_machine_factory( &self, sess: &Session, diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 6cf84a012f061..c0c1085e949e2 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -1,29 +1,29 @@ use std::assert_matches::assert_matches; +use std::ops::Deref; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout}; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty}; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange}; -use rustc_target::spec::HasTargetSpec; use super::abi::AbiBuilderMethods; use super::asm::AsmBuilderMethods; -use super::consts::ConstMethods; +use super::consts::ConstCodegenMethods; use super::coverageinfo::CoverageInfoBuilderMethods; use super::debuginfo::DebugInfoBuilderMethods; -use super::intrinsic::IntrinsicCallMethods; -use super::misc::MiscMethods; -use super::type_::{ArgAbiMethods, BaseTypeMethods, LayoutTypeMethods}; -use super::{HasCodegen, StaticBuilderMethods}; +use super::intrinsic::IntrinsicCallBuilderMethods; +use super::misc::MiscCodegenMethods; +use super::type_::{ArgAbiBuilderMethods, BaseTypeCodegenMethods, LayoutTypeCodegenMethods}; +use super::{CodegenMethods, StaticBuilderMethods}; +use crate::MemFlags; use crate::common::{ AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, }; use crate::mir::operand::{OperandRef, OperandValue}; use crate::mir::place::{PlaceRef, PlaceValue}; -use crate::MemFlags; #[derive(Copy, Clone, Debug)] pub enum OverflowOp { @@ -33,17 +33,34 @@ pub enum OverflowOp { } pub trait BuilderMethods<'a, 'tcx>: - HasCodegen<'tcx> + Sized + + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> + + Deref + CoverageInfoBuilderMethods<'tcx> + DebugInfoBuilderMethods - + ArgAbiMethods<'tcx> + + ArgAbiBuilderMethods<'tcx> + AbiBuilderMethods<'tcx> - + IntrinsicCallMethods<'tcx> + + IntrinsicCallBuilderMethods<'tcx> + AsmBuilderMethods<'tcx> + StaticBuilderMethods - + HasParamEnv<'tcx> - + HasTargetSpec { + // `BackendTypes` is a supertrait of both `CodegenMethods` and + // `BuilderMethods`. This bound ensures all impls agree on the associated + // types within. + type CodegenCx: CodegenMethods< + 'tcx, + Value = Self::Value, + Metadata = Self::Metadata, + Function = Self::Function, + BasicBlock = Self::BasicBlock, + Type = Self::Type, + Funclet = Self::Funclet, + DIScope = Self::DIScope, + DILocation = Self::DILocation, + DIVariable = Self::DIVariable, + >; + fn build(cx: &'a Self::CodegenCx, llbb: Self::BasicBlock) -> Self; fn cx(&self) -> &Self::CodegenCx; diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index c15f1fa8e564f..9af463a691af0 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -3,7 +3,7 @@ use rustc_target::abi; use super::BackendTypes; -pub trait ConstMethods<'tcx>: BackendTypes { +pub trait ConstCodegenMethods<'tcx>: BackendTypes { // Constant constructors fn const_null(&self, t: Self::Type) -> Self::Value; /// Generate an uninitialized value (matching uninitialized memory in MIR). @@ -14,18 +14,20 @@ pub trait ConstMethods<'tcx>: BackendTypes { /// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a /// poison value. fn const_poison(&self, t: Self::Type) -> Self::Value; - fn const_int(&self, t: Self::Type, i: i64) -> Self::Value; - fn const_uint(&self, t: Self::Type, i: u64) -> Self::Value; - fn const_uint_big(&self, t: Self::Type, u: u128) -> Self::Value; + fn const_bool(&self, val: bool) -> Self::Value; + + fn const_i8(&self, i: i8) -> Self::Value; fn const_i16(&self, i: i16) -> Self::Value; fn const_i32(&self, i: i32) -> Self::Value; - fn const_i8(&self, i: i8) -> Self::Value; + fn const_int(&self, t: Self::Type, i: i64) -> Self::Value; + fn const_u8(&self, i: u8) -> Self::Value; fn const_u32(&self, i: u32) -> Self::Value; fn const_u64(&self, i: u64) -> Self::Value; fn const_u128(&self, i: u128) -> Self::Value; fn const_usize(&self, i: u64) -> Self::Value; - fn const_u8(&self, i: u8) -> Self::Value; + fn const_uint(&self, t: Self::Type, i: u64) -> Self::Value; + fn const_uint_big(&self, t: Self::Type, u: u128) -> Self::Value; fn const_real(&self, t: Self::Type, val: f64) -> Self::Value; fn const_str(&self, s: &str) -> (Self::Value, Self::Value); diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs index 0b1645c66edca..0b513dac50378 100644 --- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs @@ -1,9 +1,7 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::ty::Instance; -use super::BackendTypes; - -pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { +pub trait CoverageInfoBuilderMethods<'tcx> { /// Performs any start-of-function codegen needed for coverage instrumentation. /// /// Can be a no-op in backends that don't support coverage instrumentation. diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 31104e5749b30..c26d4532d0f14 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -3,13 +3,13 @@ use std::ops::Range; use rustc_middle::mir; use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_span::{SourceFile, Span, Symbol}; -use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; +use rustc_target::abi::call::FnAbi; use super::BackendTypes; use crate::mir::debuginfo::{FunctionDebugContext, VariableKind}; -pub trait DebugInfoMethods<'tcx>: BackendTypes { +pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { fn create_vtable_debuginfo( &self, ty: Ty<'tcx>, @@ -80,6 +80,7 @@ pub trait DebugInfoBuilderMethods: BackendTypes { fragment: Option>, ); fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation); + fn clear_dbg_loc(&mut self); fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); fn set_var_name(&mut self, value: Self::Value, name: &str); } diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs index 792d2b04ed6a6..c1edeac31b0f9 100644 --- a/compiler/rustc_codegen_ssa/src/traits/declare.rs +++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs @@ -2,9 +2,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::Instance; -use super::BackendTypes; - -pub trait PreDefineMethods<'tcx>: BackendTypes { +pub trait PreDefineCodegenMethods<'tcx> { fn predefine_static( &self, def_id: DefId, diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 172004a9cc774..5b9274b48248c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -5,7 +5,7 @@ use rustc_target::abi::call::FnAbi; use super::BackendTypes; use crate::mir::operand::OperandRef; -pub trait IntrinsicCallMethods<'tcx>: BackendTypes { +pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { /// Remember to add all intrinsics here, in `compiler/rustc_hir_analysis/src/check/mod.rs`, /// and in `library/core/src/intrinsics.rs`; if you need access to any LLVM intrinsics, /// add them to `compiler/rustc_codegen_llvm/src/context.rs`. @@ -24,14 +24,14 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; /// Trait method used to test whether a given pointer is associated with a type identifier. - fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value; + fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value; /// Trait method used to load a function while testing if it is associated with a type /// identifier. fn type_checked_load( &mut self, llvtable: Self::Value, vtable_byte_offset: u64, - typeid: Self::Value, + typeid: Self::Metadata, ) -> Self::Value; /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in /// Rust defined C-variadic functions. diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index 40a49b3e1b578..5b33fd7ab1028 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -7,7 +7,7 @@ use rustc_session::Session; use super::BackendTypes; -pub trait MiscMethods<'tcx>: BackendTypes { +pub trait MiscCodegenMethods<'tcx>: BackendTypes { fn vtables( &self, ) -> &RefCell, Option>), Self::Value>>; @@ -25,6 +25,7 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>; fn set_frame_pointer_type(&self, llfn: Self::Function); fn apply_target_cpu_attr(&self, llfn: Self::Function); - /// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists. + /// Declares the extern "C" main function for the entry point. Returns None if the symbol + /// already exists. fn declare_c_main(&self, fn_type: Self::Type) -> Option; } diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 9ac923bef880c..800470286bc94 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -8,9 +8,6 @@ //! actual codegen, while the builder stores the information about the function during codegen and //! is used to produce the instructions of the backend IR. //! -//! Finally, a third `Backend` structure has to implement methods related to how codegen information -//! is passed to the backend, especially for asynchronous compilation. -//! //! The traits contain associated types that are backend-specific, such as the backend's value or //! basic blocks. @@ -30,71 +27,36 @@ mod write; use std::fmt; -use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt}; -use rustc_target::spec::HasTargetSpec; +use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; +use rustc_target::abi::call::FnAbi; pub use self::abi::AbiBuilderMethods; -pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; -pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; +pub use self::asm::{ + AsmBuilderMethods, AsmCodegenMethods, GlobalAsmOperandRef, InlineAsmOperandRef, +}; +pub use self::backend::{BackendTypes, CodegenBackend, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; -pub use self::consts::ConstMethods; +pub use self::consts::ConstCodegenMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; -pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods}; -pub use self::declare::PreDefineMethods; -pub use self::intrinsic::IntrinsicCallMethods; -pub use self::misc::MiscMethods; -pub use self::statics::{StaticBuilderMethods, StaticMethods}; +pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; +pub use self::declare::PreDefineCodegenMethods; +pub use self::intrinsic::IntrinsicCallBuilderMethods; +pub use self::misc::MiscCodegenMethods; +pub use self::statics::{StaticBuilderMethods, StaticCodegenMethods}; pub use self::type_::{ - ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMembershipMethods, - TypeMethods, + ArgAbiBuilderMethods, BaseTypeCodegenMethods, DerivedTypeCodegenMethods, + LayoutTypeCodegenMethods, TypeCodegenMethods, TypeMembershipCodegenMethods, }; pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; -pub trait CodegenObject: Copy + PartialEq + fmt::Debug {} -impl CodegenObject for T {} - -pub trait CodegenMethods<'tcx>: - Backend<'tcx> - + TypeMethods<'tcx> - + MiscMethods<'tcx> - + ConstMethods<'tcx> - + StaticMethods - + DebugInfoMethods<'tcx> - + AsmMethods<'tcx> - + PreDefineMethods<'tcx> - + HasParamEnv<'tcx> - + HasTyCtxt<'tcx> - + HasTargetSpec -{ -} - -impl<'tcx, T> CodegenMethods<'tcx> for T where - Self: Backend<'tcx> - + TypeMethods<'tcx> - + MiscMethods<'tcx> - + ConstMethods<'tcx> - + StaticMethods - + DebugInfoMethods<'tcx> - + AsmMethods<'tcx> - + PreDefineMethods<'tcx> - + HasParamEnv<'tcx> - + HasTyCtxt<'tcx> - + HasTargetSpec -{ -} +pub trait CodegenObject = Copy + PartialEq + fmt::Debug; -pub trait HasCodegen<'tcx>: - Backend<'tcx> + std::ops::Deref>::CodegenCx> -{ - type CodegenCx: CodegenMethods<'tcx> - + BackendTypes< - Value = Self::Value, - Function = Self::Function, - BasicBlock = Self::BasicBlock, - Type = Self::Type, - Funclet = Self::Funclet, - DIScope = Self::DIScope, - DILocation = Self::DILocation, - DIVariable = Self::DIVariable, - >; -} +pub trait CodegenMethods<'tcx> = LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> + + TypeCodegenMethods<'tcx> + + ConstCodegenMethods<'tcx> + + StaticCodegenMethods + + DebugInfoCodegenMethods<'tcx> + + AsmCodegenMethods<'tcx> + + PreDefineCodegenMethods<'tcx>; diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs index b418199e61636..c10733fb0ed54 100644 --- a/compiler/rustc_codegen_ssa/src/traits/statics.rs +++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs @@ -3,7 +3,7 @@ use rustc_target::abi::Align; use super::BackendTypes; -pub trait StaticMethods: BackendTypes { +pub trait StaticCodegenMethods: BackendTypes { fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value; fn codegen_static(&self, def_id: DefId); diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 7c042c0c6219a..f862434c8ef78 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -1,17 +1,15 @@ use rustc_middle::bug; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg}; use rustc_target::abi::{AddressSpace, Float, Integer}; -use super::misc::MiscMethods; -use super::{Backend, HasCodegen}; +use super::BackendTypes; +use super::misc::MiscCodegenMethods; use crate::common::TypeKind; use crate::mir::place::PlaceRef; -// This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use -// `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. -pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { +pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes { fn type_i8(&self) -> Self::Type; fn type_i16(&self) -> Self::Type; fn type_i32(&self) -> Self::Type; @@ -42,7 +40,9 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { fn val_ty(&self, v: Self::Value) -> Self::Type; } -pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { +pub trait DerivedTypeCodegenMethods<'tcx>: + BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> +{ fn type_int(&self) -> Self::Type { match &self.sess().target.c_int_width[..] { "16" => self.type_i16(), @@ -100,9 +100,12 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } } -impl<'tcx, T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {} +impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where + Self: BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> +{ +} -pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { +pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes { /// The backend type used for a rust type when it's in memory, /// such as when it's stack-allocated or when it's being loaded or stored. fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type; @@ -114,7 +117,7 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { /// /// For nearly all types this is the same as the [`Self::backend_type`], however /// `bool` (and other `0`-or-`1` values) are kept as `i1` in registers but as - /// [`BaseTypeMethods::type_i8`] in memory. + /// [`BaseTypeCodegenMethods::type_i8`] in memory. /// /// Converting values between the two different backend types is done using /// [`from_immediate`](super::BuilderMethods::from_immediate) and @@ -146,17 +149,17 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { // For backends that support CFI using type membership (i.e., testing whether a given pointer is // associated with a type identifier). -pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> { +pub trait TypeMembershipCodegenMethods<'tcx>: BackendTypes { fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {} fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn typeid_metadata(&self, _typeid: String) -> Option { + fn typeid_metadata(&self, _typeid: String) -> Option { None } fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} fn set_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} } -pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { +pub trait ArgAbiBuilderMethods<'tcx>: BackendTypes { fn store_fn_arg( &mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, @@ -172,12 +175,6 @@ pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type; } -pub trait TypeMethods<'tcx>: - DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> -{ -} - -impl<'tcx, T> TypeMethods<'tcx> for T where - Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> -{ -} +pub trait TypeCodegenMethods<'tcx> = DerivedTypeCodegenMethods<'tcx> + + LayoutTypeCodegenMethods<'tcx> + + TypeMembershipCodegenMethods<'tcx>; diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 8a6dfb892490a..73a9a1569f64e 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -134,9 +134,6 @@ const_eval_incompatible_return_types = const_eval_incompatible_types = calling a function with argument of type {$callee_ty} passing data of type {$caller_ty} -const_eval_interior_mutability_borrow = - cannot borrow here, since the borrowed element may contain interior mutability - const_eval_interior_mutable_data_refer = {const_eval_const_context}s cannot refer to interior mutable data .label = this borrow of an interior mutable value may end up in the final value @@ -201,7 +198,7 @@ const_eval_invalid_vtable_pointer = using {$pointer} as vtable pointer but it does not point to a vtable const_eval_invalid_vtable_trait = - using vtable for trait `{$vtable_trait}` but trait `{$expected_trait}` was expected + using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected const_eval_lazy_lock = consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` @@ -230,9 +227,6 @@ const_eval_memory_exhausted = const_eval_modified_global = modifying a static's initial value from another static's initializer -const_eval_mut_deref = - mutation through a reference is not allowed in {const_eval_const_context}s - const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead @@ -363,10 +357,6 @@ const_eval_too_generic = const_eval_too_many_caller_args = calling a function with more arguments than it expected -const_eval_transient_mut_borrow = mutable references are not allowed in {const_eval_const_context}s - -const_eval_transient_mut_raw = raw mutable pointers are not allowed in {const_eval_const_context}s - const_eval_try_block_from_output_non_const = `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s @@ -469,7 +459,7 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer -const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$ref_trait}`, but encountered `{$vtable_trait}` +const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}` const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` const_eval_validation_null_box = {$front_matter}: encountered a null box diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 7cfb101399daa..e1b605979972d 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -11,18 +11,17 @@ use rustc_hir::{self as hir, LangItem}; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt}; +use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; -use rustc_mir_dataflow::Analysis; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; -use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor}; use tracing::{debug, instrument, trace}; use super::ops::{self, NonConstOp, Status}; @@ -46,7 +45,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. /// /// Only updates the cursor if absolutely necessary - pub fn needs_drop( + fn needs_drop( &mut self, ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, @@ -76,7 +75,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`. /// /// Only updates the cursor if absolutely necessary - pub fn needs_non_const_drop( + pub(crate) fn needs_non_const_drop( &mut self, ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, @@ -106,7 +105,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. /// /// Only updates the cursor if absolutely necessary. - pub fn has_mut_interior( + fn has_mut_interior( &mut self, ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, @@ -166,24 +165,6 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { } } -struct LocalReturnTyVisitor<'ck, 'mir, 'tcx> { - kind: LocalKind, - checker: &'ck mut Checker<'mir, 'tcx>, -} - -impl<'ck, 'mir, 'tcx> TypeVisitor> for LocalReturnTyVisitor<'ck, 'mir, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) { - match t.kind() { - ty::FnPtr(..) => {} - ty::Ref(_, _, hir::Mutability::Mut) => { - self.checker.check_op(ops::mut_ref::MutRef(self.kind)); - t.super_visit_with(self) - } - _ => t.super_visit_with(self), - } - } -} - pub struct Checker<'mir, 'tcx> { ccx: &'mir ConstCx<'mir, 'tcx>, qualifs: Qualifs<'mir, 'tcx>, @@ -230,25 +211,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { return; } - // The local type and predicate checks are not free and only relevant for `const fn`s. - if self.const_kind() == hir::ConstContext::ConstFn { - for (idx, local) in body.local_decls.iter_enumerated() { - // Handle the return place below. - if idx == RETURN_PLACE { - continue; - } - - self.span = local.source_info.span; - self.check_local_or_return_ty(local.ty, idx); - } - - // impl trait is gone in MIR, so check the return type of a const fn by its signature - // instead of the type of the return place. - self.span = body.local_decls[RETURN_PLACE].source_info.span; - let return_ty = self.ccx.fn_sig().output(); - self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); - } - if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) { self.visit_body(body); } @@ -358,16 +320,11 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { self.check_op_spanned(ops::StaticAccess, span) } - fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { - let kind = self.body.local_kind(local); - - let mut visitor = LocalReturnTyVisitor { kind, checker: self }; - - visitor.visit_ty(ty); - } - - fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) { - match self.const_kind() { + /// Returns whether this place can possibly escape the evaluation of the current const/static + /// initializer. The check assumes that all already existing pointers and references point to + /// non-escaping places. + fn place_may_escape(&mut self, place: &Place<'_>) -> bool { + let is_transient = match self.const_kind() { // In a const fn all borrows are transient or point to the places given via // references in the arguments (so we already checked them with // TransientMutBorrow/MutBorrow as appropriate). @@ -375,7 +332,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // NOTE: Once we have heap allocations during CTFE we need to figure out // how to prevent `const fn` to create long-lived allocations that point // to mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)), + hir::ConstContext::ConstFn => true, _ => { // For indirect places, we are not creating a new permanent borrow, it's just as // transient as the already existing one. For reborrowing references this is handled @@ -387,15 +344,16 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // value of the constant. // Note: This is only sound if every local that has a `StorageDead` has a // `StorageDead` in every control flow path leading to a `return` terminator. - // The good news is that interning will detect if any unexpected mutable - // pointer slips through. - if place.is_indirect() || self.local_is_transient(place.local) { - self.check_op(ops::TransientMutBorrow(kind)); - } else { - self.check_op(ops::MutBorrow(kind)); - } + // If anything slips through, there's no safety net -- safe code can create + // references to variants of `!Freeze` enums as long as that variant is `Freeze`, so + // interning can't protect us here. (There *is* a safety net for mutable references + // though, interning will ICE if we miss something here.) + place.is_indirect() || self.local_is_transient(place.local) } - } + }; + // Transient places cannot possibly escape because the place doesn't exist any more at the + // end of evaluation. + !is_transient } } @@ -420,47 +378,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); - // Special-case reborrows to be more like a copy of a reference. - // FIXME: this does not actually handle all reborrows. It only detects cases where `*` is the outermost - // projection of the borrowed place, it skips deref'ing raw pointers and it skips `static`. - // All those cases are handled below with shared/mutable borrows. - // Once `const_mut_refs` is stable, we should be able to entirely remove this special case. - // (`const_refs_to_cell` is not needed, we already allow all borrows of indirect places anyway.) - match *rvalue { - Rvalue::Ref(_, kind, place) => { - if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { - let ctx = match kind { - BorrowKind::Shared => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) - } - BorrowKind::Fake(_) => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) - } - BorrowKind::Mut { .. } => { - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - } - }; - self.visit_local(reborrowed_place_ref.local, ctx, location); - self.visit_projection(reborrowed_place_ref, ctx, location); - return; - } - } - Rvalue::RawPtr(mutbl, place) => { - if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { - let ctx = match mutbl { - Mutability::Not => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) - } - Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::RawBorrow), - }; - self.visit_local(reborrowed_place_ref.local, ctx, location); - self.visit_projection(reborrowed_place_ref, ctx, location); - return; - } - } - _ => {} - } - self.super_rvalue(rvalue, location); match rvalue { @@ -494,15 +411,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let is_allowed = self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut); - if !is_allowed { - self.check_mut_borrow( - place, - if matches!(rvalue, Rvalue::Ref(..)) { - hir::BorrowKind::Ref - } else { - hir::BorrowKind::Raw - }, - ); + if !is_allowed && self.place_may_escape(place) { + self.check_op(ops::EscapingMutBorrow(if matches!(rvalue, Rvalue::Ref(..)) { + hir::BorrowKind::Ref + } else { + hir::BorrowKind::Raw + })); } } @@ -514,39 +428,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { place.as_ref(), ); - // If the place is indirect, this is basically a reborrow. We have a reborrow - // special case above, but for raw pointers and pointers/references to `static` and - // when the `*` is not the first projection, `place_as_reborrow` does not recognize - // them as such, so we end up here. This should probably be considered a - // `TransientCellBorrow` (we consider the equivalent mutable case a - // `TransientMutBorrow`), but such reborrows got accidentally stabilized already and - // it is too much of a breaking change to take back. - if borrowed_place_has_mut_interior && !place.is_indirect() { - match self.const_kind() { - // In a const fn all borrows are transient or point to the places given via - // references in the arguments (so we already checked them with - // TransientCellBorrow/CellBorrow as appropriate). - // The borrow checker guarantees that no new non-transient borrows are created. - // NOTE: Once we have heap allocations during CTFE we need to figure out - // how to prevent `const fn` to create long-lived allocations that point - // to (interior) mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow), - _ => { - // Locals with StorageDead are definitely not part of the final constant value, and - // it is thus inherently safe to permit such locals to have their - // address taken as we can't end up with a reference to them in the - // final value. - // Note: This is only sound if every local that has a `StorageDead` has a - // `StorageDead` in every control flow path leading to a `return` terminator. - // The good news is that interning will detect if any unexpected mutable - // pointer slips through. - if self.local_is_transient(place.local) { - self.check_op(ops::TransientCellBorrow); - } else { - self.check_op(ops::CellBorrow); - } - } - } + if borrowed_place_has_mut_interior && self.place_may_escape(place) { + self.check_op(ops::EscapingCellBorrow); } } @@ -557,6 +440,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | PointerCoercion::UnsafeFnPointer | PointerCoercion::ClosureFnPointer(_) | PointerCoercion::ReifyFnPointer, + _, ), _, _, @@ -564,8 +448,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // These are all okay; they only change the type, not the data. } - Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), _, _) => { - // Unsizing is implemented for CTFE. + Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::Unsize | PointerCoercion::DynStar, _), + _, + _, + ) => { + // Unsizing and `dyn*` coercions are implemented for CTFE. } Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => { @@ -575,10 +463,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Since no pointer can ever get exposed (rejected above), this is easy to support. } - Rvalue::Cast(CastKind::DynStar, _, _) => { - // `dyn*` coercion is implemented for CTFE. - } - Rvalue::Cast(_, _, _) => {} Rvalue::NullaryOp( @@ -635,58 +519,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } } - fn visit_projection_elem( - &mut self, - place_ref: PlaceRef<'tcx>, - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - trace!( - "visit_projection_elem: place_ref={:?} elem={:?} \ - context={:?} location={:?}", - place_ref, elem, context, location, - ); - - self.super_projection_elem(place_ref, elem, context, location); - - match elem { - ProjectionElem::Deref => { - let base_ty = place_ref.ty(self.body, self.tcx).ty; - if base_ty.is_unsafe_ptr() { - if place_ref.projection.is_empty() { - let decl = &self.body.local_decls[place_ref.local]; - // If this is a static, then this is not really dereferencing a pointer, - // just directly accessing a static. That is not subject to any feature - // gates (except for the one about whether statics can even be used, but - // that is checked already by `visit_operand`). - if let LocalInfo::StaticRef { .. } = *decl.local_info() { - return; - } - } - - // `*const T` is stable, `*mut T` is not - if !base_ty.is_mutable_ptr() { - return; - } - - self.check_op(ops::RawMutPtrDeref); - } - - if context.is_mutating_use() { - self.check_op(ops::MutDeref); - } - } - - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Downcast(..) - | ProjectionElem::OpaqueCast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(..) - | ProjectionElem::Field(..) - | ProjectionElem::Index(_) => {} - } - } fn visit_source_info(&mut self, source_info: &SourceInfo) { trace!("visit_source_info: source_info={:?}", source_info); @@ -983,40 +815,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } -fn place_as_reborrow<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - place: Place<'tcx>, -) -> Option> { - match place.as_ref().last_projection() { - Some((place_base, ProjectionElem::Deref)) => { - // FIXME: why do statics and raw pointers get excluded here? This makes - // some code involving mutable pointers unstable, but it is unclear - // why that code is treated differently from mutable references. - // Once TransientMutBorrow and TransientCellBorrow are stable, - // this can probably be cleaned up without any behavioral changes. - - // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` - // that points to the allocation for the static. Don't treat these as reborrows. - if body.local_decls[place_base.local].is_ref_to_static() { - None - } else { - // Ensure the type being derefed is a reference and not a raw pointer. - // This is sufficient to prevent an access to a `static mut` from being marked as a - // reborrow, even if the check above were to disappear. - let inner_ty = place_base.ty(body, tcx).ty; - - if let ty::Ref(..) = inner_ty.kind() { - return Some(place_base); - } else { - return None; - } - } - } - _ => None, - } -} - fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool { ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point() } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 93fafa6055773..df8313d0e7038 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -2,20 +2,20 @@ use hir::def_id::LocalDefId; use hir::{ConstContext, LangItem}; -use rustc_errors::codes::*; use rustc_errors::Diag; +use rustc_errors::codes::*; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; -use rustc_middle::mir::{self, CallSource}; +use rustc_middle::mir::CallSource; use rustc_middle::span_bug; -use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _}; +use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ - self, suggest_constraining_type_param, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, - Param, TraitRef, Ty, + self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, + suggest_constraining_type_param, }; -use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind}; +use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; @@ -57,7 +57,7 @@ pub trait NonConstOp<'tcx>: std::fmt::Debug { /// A function call where the callee is a pointer. #[derive(Debug)] -pub struct FnCallIndirect; +pub(crate) struct FnCallIndirect; impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { ccx.dcx().create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() }) @@ -66,7 +66,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { /// A function call where the callee is not marked as `const`. #[derive(Debug, Clone, Copy)] -pub struct FnCallNonConst<'tcx> { +pub(crate) struct FnCallNonConst<'tcx> { pub caller: LocalDefId, pub callee: DefId, pub args: GenericArgsRef<'tcx>, @@ -299,7 +299,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { /// /// Contains the name of the feature that would allow the use of this function. #[derive(Debug)] -pub struct FnCallUnstable(pub DefId, pub Option); +pub(crate) struct FnCallUnstable(pub DefId, pub Option); impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { @@ -324,7 +324,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { } #[derive(Debug)] -pub struct Coroutine(pub hir::CoroutineKind); +pub(crate) struct Coroutine(pub hir::CoroutineKind); impl<'tcx> NonConstOp<'tcx> for Coroutine { fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { if let hir::CoroutineKind::Desugared( @@ -356,7 +356,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { } #[derive(Debug)] -pub struct HeapAllocation; +pub(crate) struct HeapAllocation; impl<'tcx> NonConstOp<'tcx> for HeapAllocation { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { ccx.dcx().create_err(errors::UnallowedHeapAllocations { @@ -368,7 +368,7 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { } #[derive(Debug)] -pub struct InlineAsm; +pub(crate) struct InlineAsm; impl<'tcx> NonConstOp<'tcx> for InlineAsm { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { ccx.dcx().create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() }) @@ -376,7 +376,7 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm { } #[derive(Debug)] -pub struct LiveDrop<'tcx> { +pub(crate) struct LiveDrop<'tcx> { pub dropped_at: Option, pub dropped_ty: Ty<'tcx>, } @@ -391,27 +391,12 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> { } } -#[derive(Debug)] -/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to -/// the final value of the constant. -pub struct TransientCellBorrow; -impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_refs_to_cell) - } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.tcx - .sess - .create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) - } -} - #[derive(Debug)] /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to /// the final value of the constant, and thus we cannot allow this (for now). We may allow /// it in the future for static items. -pub struct CellBorrow; -impl<'tcx> NonConstOp<'tcx> for CellBorrow { +pub(crate) struct EscapingCellBorrow; +impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow { fn importance(&self) -> DiagImportance { // Most likely the code will try to do mutation with these borrows, which // triggers its own errors. Only show this one if that does not happen. @@ -431,9 +416,9 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { /// This op is for `&mut` borrows in the trailing expression of a constant /// which uses the "enclosing scopes rule" to leak its locals into anonymous /// static or const items. -pub struct MutBorrow(pub hir::BorrowKind); +pub(crate) struct EscapingMutBorrow(pub hir::BorrowKind); -impl<'tcx> NonConstOp<'tcx> for MutBorrow { +impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Forbidden } @@ -460,52 +445,9 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { } } -#[derive(Debug)] -pub struct TransientMutBorrow(pub hir::BorrowKind); - -impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let kind = ccx.const_kind(); - match self.0 { - hir::BorrowKind::Raw => ccx - .tcx - .sess - .create_feature_err(errors::TransientMutRawErr { span, kind }, sym::const_mut_refs), - hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err( - errors::TransientMutBorrowErr { span, kind }, - sym::const_mut_refs, - ), - } - } -} - -#[derive(Debug)] -pub struct MutDeref; -impl<'tcx> NonConstOp<'tcx> for MutDeref { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn importance(&self) -> DiagImportance { - // Usually a side-effect of a `TransientMutBorrow` somewhere. - DiagImportance::Secondary - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.tcx.sess.create_feature_err( - errors::MutDerefErr { span, kind: ccx.const_kind() }, - sym::const_mut_refs, - ) - } -} - /// A call to a `panic()` lang item where the first argument is _not_ a `&str`. #[derive(Debug)] -pub struct PanicNonStr; +pub(crate) struct PanicNonStr; impl<'tcx> NonConstOp<'tcx> for PanicNonStr { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { ccx.dcx().create_err(errors::PanicNonStrErr { span }) @@ -516,7 +458,7 @@ impl<'tcx> NonConstOp<'tcx> for PanicNonStr { /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on /// allocation base addresses that are not known at compile-time. #[derive(Debug)] -pub struct RawPtrComparison; +pub(crate) struct RawPtrComparison; impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { // FIXME(const_trait_impl): revert to span_bug? @@ -524,29 +466,11 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { } } -#[derive(Debug)] -pub struct RawMutPtrDeref; -impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - feature_err( - &ccx.tcx.sess, - sym::const_mut_refs, - span, - format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),), - ) - } -} - /// Casting raw pointer or function pointer to an integer. /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on /// allocation base addresses that are not known at compile-time. #[derive(Debug)] -pub struct RawPtrToIntCast; +pub(crate) struct RawPtrToIntCast; impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { ccx.dcx().create_err(errors::RawPtrToIntErr { span }) @@ -555,7 +479,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { /// An access to a (non-thread-local) `static`. #[derive(Debug)] -pub struct StaticAccess; +pub(crate) struct StaticAccess; impl<'tcx> NonConstOp<'tcx> for StaticAccess { fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { if let hir::ConstContext::Static(_) = ccx.const_kind() { @@ -582,39 +506,9 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { /// An access to a thread-local `static`. #[derive(Debug)] -pub struct ThreadLocalAccess; +pub(crate) struct ThreadLocalAccess; impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { ccx.dcx().create_err(errors::ThreadLocalAccessErr { span }) } } - -/// Types that cannot appear in the signature or locals of a `const fn`. -pub mod mut_ref { - use super::*; - - #[derive(Debug)] - pub struct MutRef(pub mir::LocalKind); - impl<'tcx> NonConstOp<'tcx> for MutRef { - fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn importance(&self) -> DiagImportance { - match self.0 { - mir::LocalKind::Temp => DiagImportance::Secondary, - mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => DiagImportance::Primary, - } - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - feature_err( - &ccx.tcx.sess, - sym::const_mut_refs, - span, - format!("mutable references are not allowed in {}s", ccx.const_kind()), - ) - } - } -} diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs index f0998300dc843..f98234ce7f3c1 100644 --- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs @@ -1,14 +1,14 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, BasicBlock, Location}; use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use tracing::trace; +use super::ConstCx; use super::check::Qualifs; use super::ops::{self, NonConstOp}; use super::qualifs::{NeedsNonConstDrop, Qualif}; -use super::ConstCx; use crate::check_consts::rustc_allow_const_fn_unstable; /// Returns `true` if we should use the more precise live drop checker that runs after drop diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index c566dc7fa844d..7358a6c6d2256 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -206,14 +206,10 @@ impl Qualif for NeedsNonConstDrop { cx.tcx, ObligationCause::dummy_with_span(cx.body.span), cx.param_env, - ty::TraitRef::new( - cx.tcx, - destruct_def_id, - [ - ty::GenericArg::from(ty), - ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())), - ], - ), + ty::TraitRef::new(cx.tcx, destruct_def_id, [ + ty::GenericArg::from(ty), + ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())), + ]), ); let infcx = cx.tcx.infer_ctxt().build(); diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 681184f7fbcde..eb5024c36f4b6 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -13,7 +13,7 @@ use rustc_middle::mir::{ use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::{Analysis, AnalysisDomain, JoinSemiLattice}; -use super::{qualifs, ConstCx, Qualif}; +use super::{ConstCx, Qualif, qualifs}; /// A `Visitor` that propagates qualifs between locals. This defines the transfer function of /// `FlowSensitiveAnalysis`. diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index aa7449e8ad269..ed1c912e6cb03 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -6,7 +6,7 @@ use rustc_middle::{bug, span_bug, ty}; use rustc_span::def_id::DefId; use crate::interpret::{ - self, throw_machine_stop, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, + self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, throw_machine_stop, }; /// Macro for machine-specific `InterpError` without allocation. diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 25b32785b7d3e..fd05664e2f227 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,8 +1,8 @@ use std::mem; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg}; -use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; use rustc_middle::mir::AssertKind; +use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{ConstInt, TyCtxt}; @@ -11,7 +11,7 @@ use rustc_span::{Span, Symbol}; use super::CompileTimeMachine; use crate::errors::{self, FrameNote, ReportErrorExt}; use crate::interpret::{ - err_inval, err_machine_stop, ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType, + ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType, err_inval, err_machine_stop, }; /// The CTFE machine has some custom error kinds. diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 96b3ec6f18728..a241edbd77ad9 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -10,21 +10,19 @@ use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::lint; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{self, Abi}; use tracing::{debug, instrument, trace}; use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; use crate::const_eval::CheckAlignment; -use crate::errors::{self, ConstEvalError, DanglingPtrInFinal}; use crate::interpret::{ - create_static_alloc, eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust, CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError, - InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, + InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc, + eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust, }; -use crate::CTRL_C_RECEIVED; +use crate::{CTRL_C_RECEIVED, errors}; // Returns a pointer to where the result lives #[instrument(level = "trace", skip(ecx, body))] @@ -75,12 +73,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( // This can't use `init_stack_frame` since `body` is not a function, // so computing its ABI would fail. It's also not worth it since there are no arguments to pass. - ecx.push_stack_frame_raw( - cid.instance, - body, - &ret.clone().into(), - StackPopCleanup::Root { cleanup: false }, - )?; + ecx.push_stack_frame_raw(cid.instance, body, &ret, StackPopCleanup::Root { cleanup: false })?; ecx.storage_live_for_always_live_locals()?; // The main interpreter loop. @@ -94,7 +87,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret); // Since evaluation had no errors, validate the resulting constant. - const_validate_mplace(&ecx, &ret, cid)?; + const_validate_mplace(ecx, &ret, cid)?; // Only report this after validation, as validaiton produces much better diagnostics. // FIXME: ensure validation always reports this and stop making interning care about it. @@ -105,18 +98,15 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( return Err(ecx .tcx .dcx() - .emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) + .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) .into()); } Err(InternResult::FoundBadMutablePointer) => { - // only report mutable pointers if there were no dangling pointers - let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }; - ecx.tcx.emit_node_span_lint( - lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, - ecx.machine.best_lint_scope(*ecx.tcx), - err_diag.span, - err_diag, - ) + return Err(ecx + .tcx + .dcx() + .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }) + .into()); } } @@ -391,7 +381,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( #[inline(always)] fn const_validate_mplace<'tcx>( - ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, + ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, mplace: &MPlaceTy<'tcx>, cid: GlobalId<'tcx>, ) -> Result<(), ErrorHandled> { @@ -448,7 +438,12 @@ fn report_eval_error<'tcx>( error, DUMMY_SP, || super::get_span_and_frames(ecx.tcx, ecx.stack()), - |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, + |span, frames| errors::ConstEvalError { + span, + error_kind: kind, + instance, + frame_notes: frames, + }, ) } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 9c1fef095f552..6d74998b7d88e 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -1,19 +1,19 @@ -use std::borrow::Borrow; +use std::borrow::{Borrow, Cow}; use std::fmt; use std::hash::Hash; use std::ops::ControlFlow; use rustc_ast::Mutability; -use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, LangItem, CRATE_HIR_ID}; +use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; use tracing::debug; @@ -22,10 +22,10 @@ use super::error::*; use crate::errors::{LongRunning, LongRunningWarn}; use crate::fluent_generated as fluent; use crate::interpret::{ - self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, throw_unsup, - throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, - GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar, - StackPopCleanup, + self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, + InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, RangeSet, Scalar, + StackPopCleanup, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, + throw_unsup, throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -65,6 +65,9 @@ pub struct CompileTimeMachine<'tcx> { /// storing the result in the given `AllocId`. /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops. pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>, + + /// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes). + union_data_ranges: FxHashMap, RangeSet>, } #[derive(Copy, Clone)] @@ -99,6 +102,7 @@ impl<'tcx> CompileTimeMachine<'tcx> { can_access_mut_global, check_alignment, static_root_ids: None, + union_data_ranges: FxHashMap::default(), } } } @@ -199,8 +203,8 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); - use rustc_session::config::RemapPathScopeComponents; use rustc_session::RemapFileNameExt; + use rustc_session::config::RemapPathScopeComponents; ( Symbol::intern( &caller @@ -637,7 +641,14 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // current number of evaluated terminators is a power of 2. The latter gives us a cheap // way to implement exponential backoff. let span = ecx.cur_span(); - ecx.tcx.dcx().emit_warn(LongRunningWarn { span, item_span: ecx.tcx.span }); + // We store a unique number in `force_duplicate` to evade `-Z deduplicate-diagnostics`. + // `new_steps` is guaranteed to be unique because `ecx.machine.num_evaluated_steps` is + // always increasing. + ecx.tcx.dcx().emit_warn(LongRunningWarn { + span, + item_span: ecx.tcx.span, + force_duplicate: new_steps, + }); } } @@ -714,16 +725,29 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { _kind: mir::RetagKind, val: &ImmTy<'tcx, CtfeProvenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, CtfeProvenance>> { - // If it's a frozen shared reference that's not already immutable, make it immutable. + // If it's a frozen shared reference that's not already immutable, potentially make it immutable. // (Do nothing on `None` provenance, that cannot store immutability anyway.) if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind() && *mutbl == Mutability::Not - && val.to_scalar_and_meta().0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable()) - // That next check is expensive, that's why we have all the guards above. - && ty.is_freeze(*ecx.tcx, ecx.param_env) + && val + .to_scalar_and_meta() + .0 + .to_pointer(ecx)? + .provenance + .is_some_and(|p| !p.immutable()) { + // That next check is expensive, that's why we have all the guards above. + let is_immutable = ty.is_freeze(*ecx.tcx, ecx.param_env); let place = ecx.ref_to_mplace(val)?; - let new_place = place.map_provenance(CtfeProvenance::as_immutable); + let new_place = if is_immutable { + place.map_provenance(CtfeProvenance::as_immutable) + } else { + // Even if it is not immutable, remember that it is a shared reference. + // This allows it to become part of the final value of the constant. + // (See for why we allow this + // even when there is interior mutability.) + place.map_provenance(CtfeProvenance::as_shared_ref) + }; Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) } else { Ok(val.clone()) @@ -766,6 +790,19 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } Ok(()) } + + fn cached_union_data_range<'e>( + ecx: &'e mut InterpCx<'tcx, Self>, + ty: Ty<'tcx>, + compute_range: impl FnOnce() -> RangeSet, + ) -> Cow<'e, RangeSet> { + if ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks { + Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range)) + } else { + // Don't bother caching, we're only doing one validation at the end anyway. + Cow::Owned(compute_range()) + } + } } // Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 8add23ed22fb3..48aeee2e6f05e 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -7,7 +7,7 @@ use rustc_middle::{bug, mir}; use rustc_target::abi::VariantIdx; use tracing::instrument; -use crate::interpret::{format_interp_error, InterpCx}; +use crate::interpret::{InterpCx, format_interp_error}; mod dummy_machine; mod error; @@ -16,12 +16,12 @@ mod fn_queries; mod machine; mod valtrees; -pub use dummy_machine::*; -pub use error::*; -pub use eval_queries::*; -pub use fn_queries::*; -pub use machine::*; -pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value}; +pub use self::dummy_machine::*; +pub use self::error::*; +pub use self::eval_queries::*; +pub use self::fn_queries::*; +pub use self::machine::*; +pub(crate) use self::valtrees::{eval_to_valtree, valtree_to_const_value}; // We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. const VALTREE_MAX_NODES: usize = 100000; diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index c96296eddb844..a11d491bdd2c9 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -9,12 +9,12 @@ use tracing::{debug, instrument, trace}; use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; use super::machine::CompileTimeInterpCx; -use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; +use super::{VALTREE_MAX_NODES, ValTreeCreationError, ValTreeCreationResult}; use crate::const_eval::CanAccessMutGlobal; use crate::errors::MaxNumNodesInConstErr; use crate::interpret::{ - intern_const_alloc_recursive, ImmTy, Immediate, InternKind, MPlaceTy, MemPlaceMeta, MemoryKind, - PlaceTy, Projectable, Scalar, + ImmTy, Immediate, InternKind, MPlaceTy, MemPlaceMeta, MemoryKind, PlaceTy, Projectable, Scalar, + intern_const_alloc_recursive, }; #[instrument(skip(ecx), level = "debug")] @@ -319,7 +319,7 @@ pub fn valtree_to_const_value<'tcx>( let branches = valtree.unwrap_branch(); // Find the non-ZST field. (There can be aligned ZST!) for (i, &inner_valtree) in branches.iter().enumerate() { - let field = layout.field(&LayoutCx { tcx, param_env }, i); + let field = layout.field(&LayoutCx::new(tcx, param_env), i); if !field.is_zst() { return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree); } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 0b366b43f95f6..c60bacb85067f 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -15,8 +15,8 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::ty::{self, Mutability, Ty}; use rustc_span::Span; -use rustc_target::abi::call::AdjustForForeignAbiError; use rustc_target::abi::WrappingRange; +use rustc_target::abi::call::AdjustForForeignAbiError; use crate::interpret::InternKind; @@ -35,13 +35,10 @@ pub(crate) struct NestedStaticInThreadLocal { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag(const_eval_mutable_ptr_in_final)] pub(crate) struct MutablePtrInFinal { - // rust-lang/rust#122153: This was marked as `#[primary_span]` under - // `derive(Diagnostic)`. Since we expect we may hard-error in future, we are - // keeping the field (and skipping it under `derive(LintDiagnostic)`). - #[skip_arg] + #[primary_span] pub span: Span, pub kind: InternKind, } @@ -96,30 +93,6 @@ pub(crate) struct PanicNonStrErr { pub span: Span, } -#[derive(Diagnostic)] -#[diag(const_eval_mut_deref, code = E0658)] -pub(crate) struct MutDerefErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_transient_mut_borrow, code = E0658)] -pub(crate) struct TransientMutBorrowErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_transient_mut_raw, code = E0658)] -pub(crate) struct TransientMutRawErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - #[derive(Diagnostic)] #[diag(const_eval_max_num_nodes_in_const)] pub(crate) struct MaxNumNodesInConstErr { @@ -220,13 +193,6 @@ pub(crate) struct InteriorMutableDataRefer { pub teach: bool, } -#[derive(Diagnostic)] -#[diag(const_eval_interior_mutability_borrow)] -pub(crate) struct InteriorMutabilityBorrow { - #[primary_span] - pub span: Span, -} - #[derive(LintDiagnostic)] #[diag(const_eval_long_running)] #[note] @@ -243,6 +209,8 @@ pub struct LongRunningWarn { pub span: Span, #[help] pub item_span: Span, + // Used for evading `-Z deduplicate-diagnostics`. + pub force_duplicate: usize, } #[derive(Subdiagnostic)] @@ -542,13 +510,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { } ShiftOverflow { intrinsic, shift_amount } => { diag.arg("intrinsic", intrinsic); - diag.arg( - "shift_amount", - match shift_amount { - Either::Left(v) => v.to_string(), - Either::Right(v) => v.to_string(), - }, - ); + diag.arg("shift_amount", match shift_amount { + Either::Left(v) => v.to_string(), + Either::Right(v) => v.to_string(), + }); } BoundsCheckFailed { len, index } => { diag.arg("len", len); @@ -557,12 +522,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { diag.arg("pointer", ptr); } - InvalidVTableTrait { expected_trait, vtable_trait } => { - diag.arg("expected_trait", expected_trait.to_string()); - diag.arg( - "vtable_trait", - vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("")), - ); + InvalidVTableTrait { expected_dyn_type, vtable_dyn_type } => { + diag.arg("expected_dyn_type", expected_dyn_type.to_string()); + diag.arg("vtable_dyn_type", vtable_dyn_type.to_string()); } PointerUseAfterFree(alloc_id, msg) => { diag.arg("alloc_id", alloc_id) @@ -812,12 +774,9 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { DanglingPtrNoProvenance { pointer, .. } => { err.arg("pointer", pointer); } - InvalidMetaWrongTrait { expected_trait: ref_trait, vtable_trait } => { - err.arg("ref_trait", ref_trait.to_string()); - err.arg( - "vtable_trait", - vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("")), - ); + InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => { + err.arg("vtable_dyn_type", vtable_dyn_type.to_string()); + err.arg("expected_dyn_type", expected_dyn_type.to_string()); } NullPtr { .. } | ConstRefToMutable diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 61e8007e10ecf..f5a0a2c0ee360 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -14,13 +14,13 @@ use rustc_target::spec::abi::Abi; use tracing::{info, instrument, trace}; use super::{ - throw_ub, throw_ub_custom, throw_unsup_format, CtfeProvenance, FnVal, ImmTy, InterpCx, - InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, ReturnAction, Scalar, - StackPopCleanup, StackPopInfo, + CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, + Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, throw_ub, + throw_ub_custom, throw_unsup_format, }; use crate::fluent_generated as fluent; -/// An argment passed to a function. +/// An argument passed to a function. #[derive(Clone, Debug)] pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> { /// Pass a copy of the given operand. @@ -123,7 +123,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed) }; let inner = self.unfold_transparent(inner, /* may_unfold */ |def| { - // Stop at NPO tpyes so that we don't miss that attribute in the check below! + // Stop at NPO types so that we don't miss that attribute in the check below! def.is_struct() && !is_npo(def) }); Ok(match inner.ty.kind() { @@ -189,7 +189,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::Ref(_, ty, _) => *ty, ty::RawPtr(ty, _) => *ty, // We only accept `Box` with the default allocator. - _ if ty.is_box_global(*self.tcx) => ty.boxed_ty(), + _ if ty.is_box_global(*self.tcx) => ty.expect_boxed_ty(), _ => return Ok(None), })) }; @@ -221,7 +221,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // Fall back to exact equality. - // FIXME: We are missing the rules for "repr(C) wrapping compatible types". Ok(caller == callee) } @@ -234,14 +233,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // so we implement a type-based check that reflects the guaranteed rules for ABI compatibility. if self.layout_compat(caller_abi.layout, callee_abi.layout)? { // Ensure that our checks imply actual ABI compatibility for this concrete call. + // (This can fail e.g. if `#[rustc_nonnull_optimization_guaranteed]` is used incorrectly.) assert!(caller_abi.eq_abi(callee_abi)); - return Ok(true); + Ok(true) } else { trace!( "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}", caller_abi, callee_abi ); - return Ok(false); + Ok(false) } } @@ -364,13 +364,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { "caller ABI: {:#?}, args: {:#?}", caller_fn_abi, args.iter() - .map(|arg| ( - arg.layout().ty, - match arg { - FnArg::Copy(op) => format!("copy({op:?})"), - FnArg::InPlace(mplace) => format!("in-place({mplace:?})"), - } - )) + .map(|arg| (arg.layout().ty, match arg { + FnArg::Copy(op) => format!("copy({op:?})"), + FnArg::InPlace(mplace) => format!("in-place({mplace:?})"), + })) .collect::>() ); trace!( @@ -823,7 +820,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { (Abi::Rust, fn_abi), &[FnArg::Copy(arg.into())], false, - &ret.into(), + &ret, Some(target), unwind, ) @@ -853,13 +850,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ); // Check `unwinding`. - assert_eq!( - unwinding, - match self.frame().loc { - Left(loc) => self.body().basic_blocks[loc.block].is_cleanup, - Right(_) => true, - } - ); + assert_eq!(unwinding, match self.frame().loc { + Left(loc) => self.body().basic_blocks[loc.block].is_cleanup, + Right(_) => true, + }); if unwinding && self.frame_idx() == 0 { throw_ub_custom!(fluent::const_eval_unwind_past_top); } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index e8c9f145eea55..85e7d91c2ad50 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -2,8 +2,8 @@ use std::assert_matches::assert_matches; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; -use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::mir::CastKind; +use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty}; @@ -14,7 +14,7 @@ use tracing::trace; use super::util::ensure_monomorphic_enough; use super::{ - err_inval, throw_ub, throw_ub_custom, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, + FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, throw_ub, throw_ub_custom, }; use crate::fluent_generated as fluent; @@ -32,7 +32,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if cast_ty == dest.layout.ty { dest.layout } else { self.layout_of(cast_ty)? }; // FIXME: In which cases should we trigger UB when the source is uninit? match cast_kind { - CastKind::PointerCoercion(PointerCoercion::Unsize) => { + CastKind::PointerCoercion(PointerCoercion::Unsize, _) => { self.unsize_into(src, cast_layout, dest)?; } @@ -68,11 +68,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CastKind::PointerCoercion( PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, + _, ) => { bug!("{cast_kind:?} casts are for borrowck only, not runtime MIR"); } - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => { // All reifications must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; @@ -94,7 +95,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _) => { let src = self.read_immediate(src)?; match cast_ty.kind() { ty::FnPtr(..) => { @@ -105,7 +106,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)) => { + CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _) => { // All reifications must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; @@ -125,10 +126,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - CastKind::DynStar => { + CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() { // Initial cast from sized to dyn trait - let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; + let vtable = self.get_vtable_ptr(src.layout.ty, data)?; let vtable = Scalar::from_maybe_pointer(vtable, self); let data = self.read_immediate(src)?.to_scalar(); let _assert_pointer_like = data.to_pointer(self)?; @@ -446,12 +447,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // Get the destination trait vtable and return that. - let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; + let new_vptr = self.get_vtable_ptr(ty, data_b)?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } (_, &ty::Dynamic(data, _, ty::Dyn)) => { // Initial cast from sized to dyn trait - let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; + let vtable = self.get_vtable_ptr(src_pointee_ty, data)?; let ptr = self.read_pointer(src)?; let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); self.write_immediate(val, dest) diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 0008a15722bde..3bab2b3261e1e 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -7,7 +7,7 @@ use rustc_target::abi::{self, TagEncoding, VariantIdx, Variants}; use tracing::{instrument, trace}; use super::{ - err_ub, throw_ub, ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable, + ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, throw_ub, }; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { @@ -60,7 +60,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[instrument(skip(self), level = "trace")] pub fn read_discriminant( &self, - op: &impl Readable<'tcx, M::Provenance>, + op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, VariantIdx> { let ty = op.layout().ty; trace!("read_discriminant_value {:#?}", op.layout()); diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 7a6bbdfdcb5e5..f4c4a6fb0bf5b 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1,8 +1,8 @@ use either::{Left, Right}; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::DefId; -use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::at::ToTrace; use rustc_infer::traits::ObligationCause; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; @@ -16,14 +16,14 @@ use rustc_span::Span; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_trait_selection::traits::ObligationCtxt; -use tracing::{debug, trace}; +use tracing::{debug, instrument, trace}; use super::{ - err_inval, throw_inval, throw_ub, throw_ub_custom, Frame, FrameInfo, GlobalId, InterpErrorInfo, - InterpResult, MPlaceTy, Machine, MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, - Projectable, Provenance, + Frame, FrameInfo, GlobalId, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlaceMeta, + Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, err_inval, + throw_inval, throw_ub, throw_ub_custom, }; -use crate::{fluent_generated as fluent, util, ReportErrorExt}; +use crate::{ReportErrorExt, fluent_generated as fluent, util}; pub struct InterpCx<'tcx, M: Machine<'tcx>> { /// Stores the `Machine` instance. @@ -315,6 +315,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Check if the two things are equal in the current param_env, using an infctx to get proper /// equality checks. + #[instrument(level = "trace", skip(self), ret)] pub(super) fn eq_in_param_env(&self, a: T, b: T) -> bool where T: PartialEq + TypeFoldable> + ToTrace<'tcx>, @@ -330,13 +331,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // equate the two trait refs after normalization let a = ocx.normalize(&cause, self.param_env, a); let b = ocx.normalize(&cause, self.param_env, b); - if ocx.eq(&cause, self.param_env, a, b).is_ok() { - if ocx.select_all_or_error().is_empty() { - // All good. - return true; - } + + if let Err(terr) = ocx.eq(&cause, self.param_env, a, b) { + trace!(?terr); + return false; } - return false; + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + trace!(?errors); + return false; + } + + // All good. + true } /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a @@ -574,7 +582,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // be computed as the type references non-existing names. // See . } else { - // Looks like the const is not captued by `required_consts`, that's bad. + // Looks like the const is not captured by `required_consts`, that's bad. span_bug!(span, "interpret const eval failure of {val:?} which is not in required_consts"); } } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 8b0a2afa4d669..81659df7c533b 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -20,12 +20,13 @@ use rustc_hir as hir; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult}; use rustc_middle::query::TyCtxtAt; +use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::LocalDefId; use rustc_span::sym; use tracing::{instrument, trace}; -use super::{err_ub, AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy}; +use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub}; use crate::const_eval; use crate::errors::NestedStaticInThreadLocal; @@ -99,11 +100,11 @@ fn intern_as_new_static<'tcx>( alloc_id: AllocId, alloc: ConstAllocation<'tcx>, ) { - let feed = tcx.create_def( - static_id, - sym::nested, - DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, - ); + let feed = tcx.create_def(static_id, sym::nested, DefKind::Static { + safety: hir::Safety::Safe, + mutability: alloc.0.mutability, + nested: true, + }); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); if tcx.is_thread_local_static(static_id.into()) { @@ -223,37 +224,52 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval continue; } - // Crucially, we check this *before* checking whether the `alloc_id` - // has already been interned. The point of this check is to ensure that when - // there are multiple pointers to the same allocation, they are *all* immutable. - // Therefore it would be bad if we only checked the first pointer to any given - // allocation. + // Ensure that this is derived from a shared reference. Crucially, we check this *before* + // checking whether the `alloc_id` has already been interned. The point of this check is to + // ensure that when there are multiple pointers to the same allocation, they are *all* + // derived from a shared reference. Therefore it would be bad if we only checked the first + // pointer to any given allocation. // (It is likely not possible to actually have multiple pointers to the same allocation, // so alternatively we could also check that and ICE if there are multiple such pointers.) + // See for why we are checking for "shared + // reference" and not "immutable", i.e., for why we are allowing interior-mutable shared + // references: they can actually be created in safe code while pointing to apparently + // "immutable" values, via promotion or tail expression lifetime extension of + // `&None::>`. + // We also exclude promoteds from this as `&mut []` can be promoted, which is a mutable + // reference pointing to an immutable (zero-sized) allocation. We rely on the promotion + // analysis not screwing up to ensure that it is sound to intern promoteds as immutable. if intern_kind != InternKind::Promoted && inner_mutability == Mutability::Not - && !prov.immutable() + && !prov.shared_ref() { - if ecx.tcx.try_get_global_alloc(alloc_id).is_some() - && !just_interned.contains(&alloc_id) - { + let is_already_global = ecx.tcx.try_get_global_alloc(alloc_id).is_some(); + if is_already_global && !just_interned.contains(&alloc_id) { // This is a pointer to some memory from another constant. We encounter mutable // pointers to such memory since we do not always track immutability through // these "global" pointers. Allowing them is harmless; the point of these checks // during interning is to justify why we intern the *new* allocations immutably, - // so we can completely ignore existing allocations. We also don't need to add - // this to the todo list, since after all it is already interned. + // so we can completely ignore existing allocations. + // We can also skip the rest of this loop iteration, since after all it is already + // interned. continue; } - // Found a mutable pointer inside a const where inner allocations should be - // immutable. We exclude promoteds from this, since things like `&mut []` and - // `&None::>` lead to promotion that can produce mutable pointers. We rely - // on the promotion analysis not screwing up to ensure that it is sound to intern - // promoteds as immutable. - trace!("found bad mutable pointer"); - // Prefer dangling pointer errors over mutable pointer errors - if result.is_ok() { - result = Err(InternResult::FoundBadMutablePointer); + // If this is a dangling pointer, that's actually fine -- the problematic case is + // when there is memory there that someone might expect to be mutable, but we make it immutable. + let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id); + if !dangling { + // Found a mutable reference inside a const where inner allocations should be + // immutable. + if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + span_bug!( + ecx.tcx.span, + "the static const safety checks accepted mutable references they should not have accepted" + ); + } + // Prefer dangling pointer errors over mutable pointer errors + if result.is_ok() { + result = Err(InternResult::FoundBadMutablePointer); + } } } if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { @@ -261,7 +277,6 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval debug_assert!(!ecx.memory.alloc_map.contains_key(&alloc_id)); continue; } - just_interned.insert(alloc_id); // We always intern with `inner_mutability`, and furthermore we ensured above that if // that is "immutable", then there are *no* mutable pointers anywhere in the newly // interned memory -- justifying that we can indeed intern immutably. However this also @@ -272,6 +287,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // pointers before deciding which allocations can be made immutable; but for now we are // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. + just_interned.insert(alloc_id); match intern_shallow(ecx, alloc_id, inner_mutability) { Ok(nested) => todo.extend(nested), Err(()) => { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index bedc56de0da25..e1fd8bea1f30c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -9,16 +9,16 @@ use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{GenericArgsRef, Ty, TyCtxt}; use rustc_middle::{bug, ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use rustc_target::abi::Size; use tracing::trace; use super::memory::MemoryKind; use super::util::ensure_monomorphic_enough; use super::{ - err_inval, err_ub_custom, err_unsup_format, throw_inval, throw_ub_custom, throw_ub_format, Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, - MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar, + MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, + err_ub_custom, err_unsup_format, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -216,7 +216,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?; } sym::write_bytes => { - self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?; + self.write_bytes_intrinsic(&args[0], &args[1], &args[2], "write_bytes")?; } sym::compare_bytes => { let result = self.compare_bytes_intrinsic(&args[0], &args[1], &args[2])?; @@ -384,8 +384,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::simd_insert => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); let elem = &args[2]; - let (input, input_len) = self.operand_to_simd(&args[0])?; - let (dest, dest_len) = self.mplace_to_simd(dest)?; + let (input, input_len) = self.project_to_simd(&args[0])?; + let (dest, dest_len) = self.project_to_simd(dest)?; assert_eq!(input_len, dest_len, "Return vector length must match input length"); // Bounds are not checked by typeck so we have to do it ourselves. if index >= input_len { @@ -406,7 +406,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } sym::simd_extract => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); - let (input, input_len) = self.operand_to_simd(&args[0])?; + let (input, input_len) = self.project_to_simd(&args[0])?; // Bounds are not checked by typeck so we have to do it ourselves. if index >= input_len { throw_ub_format!( @@ -599,9 +599,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let count = self.read_target_usize(count)?; let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?; let (size, align) = (layout.size, layout.align.abi); - // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), - // but no actual allocation can be big enough for the difference to be noticeable. - let size = size.checked_mul(count, self).ok_or_else(|| { + + let size = self.compute_size_in_bytes(size, count).ok_or_else(|| { err_ub_custom!( fluent::const_eval_size_overflow, name = if nonoverlapping { "copy_nonoverlapping" } else { "copy" } @@ -635,11 +634,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(()) } - pub(crate) fn write_bytes_intrinsic( + pub fn write_bytes_intrinsic( &mut self, dst: &OpTy<'tcx, >::Provenance>, byte: &OpTy<'tcx, >::Provenance>, count: &OpTy<'tcx, >::Provenance>, + name: &'static str, ) -> InterpResult<'tcx> { let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap())?; @@ -649,9 +649,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // but no actual allocation can be big enough for the difference to be noticeable. - let len = layout.size.checked_mul(count, self).ok_or_else(|| { - err_ub_custom!(fluent::const_eval_size_overflow, name = "write_bytes") - })?; + let len = self + .compute_size_in_bytes(layout.size, count) + .ok_or_else(|| err_ub_custom!(fluent::const_eval_size_overflow, name = name))?; let bytes = std::iter::repeat(byte).take(len.bytes_usize()); self.write_bytes_ptr(dst, bytes) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 6cfd7be48e624..a809f74e8eb90 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -9,17 +9,18 @@ use std::hash::Hash; use rustc_apfloat::{Float, FloatConvert}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{mir, ty}; -use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_span::def_id::DefId; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; use super::{ - throw_unsup, throw_unsup_format, AllocBytes, AllocId, AllocKind, AllocRange, Allocation, - ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, - MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance, CTFE_ALLOC_SALT, + AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation, + CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, + Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, throw_unsup, throw_unsup_format, }; /// Data returned by [`Machine::after_stack_pop`], and consumed by @@ -539,10 +540,29 @@ pub trait Machine<'tcx>: Sized { Ok(ReturnAction::Normal) } + /// Called immediately after an "immediate" local variable is read + /// (i.e., this is called for reads that do not end up accessing addressable memory). + #[inline(always)] + fn after_local_read(_ecx: &InterpCx<'tcx, Self>, _local: mir::Local) -> InterpResult<'tcx> { + Ok(()) + } + + /// Called immediately after an "immediate" local variable is assigned a new value + /// (i.e., this is called for writes that do not end up in memory). + /// `storage_live` indicates whether this is the initial write upon `StorageLive`. + #[inline(always)] + fn after_local_write( + _ecx: &mut InterpCx<'tcx, Self>, + _local: mir::Local, + _storage_live: bool, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Called immediately after actual memory was allocated for a local /// but before the local's stack frame is updated to point to that memory. #[inline(always)] - fn after_local_allocated( + fn after_local_moved_to_memory( _ecx: &mut InterpCx<'tcx, Self>, _local: mir::Local, _mplace: &MPlaceTy<'tcx, Self::Provenance>, @@ -578,6 +598,15 @@ pub trait Machine<'tcx>: Sized { ecx: &InterpCx<'tcx, Self>, instance: Option>, ) -> usize; + + fn cached_union_data_range<'e>( + _ecx: &'e mut InterpCx<'tcx, Self>, + _ty: Ty<'tcx>, + compute_range: impl FnOnce() -> RangeSet, + ) -> Cow<'e, RangeSet> { + // Default to no caching. + Cow::Owned(compute_range()) + } } /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 97326fe99a21a..c3b506d848cdb 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -7,10 +7,9 @@ //! short-circuiting the empty case! use std::assert_matches::assert_matches; -use std::borrow::Cow; -use std::cell::Cell; +use std::borrow::{Borrow, Cow}; use std::collections::VecDeque; -use std::{fmt, ptr}; +use std::{fmt, mem, ptr}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; @@ -22,10 +21,10 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use tracing::{debug, instrument, trace}; use super::{ - alloc_range, err_ub, err_ub_custom, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer, - PointerArithmetic, Provenance, Scalar, + PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, throw_ub, + throw_ub_custom, throw_unsup, throw_unsup_format, }; use crate::fluent_generated as fluent; @@ -118,7 +117,7 @@ pub struct Memory<'tcx, M: Machine<'tcx>> { /// This stores whether we are currently doing reads purely for the purpose of validation. /// Those reads do not trigger the machine's hooks for memory reads. /// Needless to say, this must only be set with great care! - validation_in_progress: Cell, + validation_in_progress: bool, } /// A reference to some allocation that was already bounds-checked for the given region @@ -145,7 +144,7 @@ impl<'tcx, M: Machine<'tcx>> Memory<'tcx, M> { alloc_map: M::MemoryMap::default(), extra_fn_ptr_map: FxIndexMap::default(), dead_alloc_map: FxIndexMap::default(), - validation_in_progress: Cell::new(false), + validation_in_progress: false, } } @@ -223,7 +222,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } else { Allocation::try_uninit(size, align)? }; - self.allocate_raw_ptr(alloc, kind) + self.insert_allocation(alloc, kind) } pub fn allocate_bytes_ptr( @@ -234,14 +233,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mutability: Mutability, ) -> InterpResult<'tcx, Pointer> { let alloc = Allocation::from_bytes(bytes, align, mutability); - self.allocate_raw_ptr(alloc, kind) + self.insert_allocation(alloc, kind) } - pub fn allocate_raw_ptr( + pub fn insert_allocation( &mut self, alloc: Allocation, kind: MemoryKind, ) -> InterpResult<'tcx, Pointer> { + assert!(alloc.size() <= self.max_size_of_val()); let id = self.tcx.reserve_alloc_id(); debug_assert_ne!( Some(kind), @@ -387,12 +387,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { size: Size, ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> { let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes - self.check_and_deref_ptr( + Self::check_and_deref_ptr( + self, ptr, size, CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, prov| { - let (size, align) = self + |this, alloc_id, offset, prov| { + let (size, align) = this .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?; Ok((size, align, (alloc_id, offset, prov))) }, @@ -409,8 +410,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes - self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| { - let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?; + Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { + let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; Ok((size, align, ())) })?; Ok(()) @@ -425,8 +426,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { size: i64, msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { - self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| { - let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?; + Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { + let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; Ok((size, align, ())) })?; Ok(()) @@ -440,12 +441,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// `alloc_size` will only get called for non-zero-sized accesses. /// /// Returns `None` if and only if the size is 0. - fn check_and_deref_ptr( - &self, + fn check_and_deref_ptr>( + this: R, ptr: Pointer>, size: i64, msg: CheckInAllocMsg, alloc_size: impl FnOnce( + R, AllocId, Size, M::ProvenanceExtra, @@ -456,13 +458,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return Ok(None); } - Ok(match self.ptr_try_get_alloc_id(ptr, size) { + Ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) { Err(addr) => { // We couldn't get a proper allocation. throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg }); } Ok((alloc_id, offset, prov)) => { - let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; + let tcx = this.borrow().tcx; + let (alloc_size, _alloc_align, ret_val) = alloc_size(this, alloc_id, offset, prov)?; let offset = offset.bytes(); // Compute absolute begin and end of the range. let (begin, end) = if size >= 0 { @@ -476,7 +479,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(PointerOutOfBounds { alloc_id, alloc_size, - ptr_offset: self.sign_extend_to_target_isize(offset), + ptr_offset: tcx.sign_extend_to_target_isize(offset), inbounds_size: size, msg, }) @@ -670,19 +673,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option>> { let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes - let ptr_and_alloc = self.check_and_deref_ptr( + let ptr_and_alloc = Self::check_and_deref_ptr( + self, ptr, size_i64, CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, prov| { - let alloc = self.get_alloc_raw(alloc_id)?; + |this, alloc_id, offset, prov| { + let alloc = this.get_alloc_raw(alloc_id)?; Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) }, )?; // We want to call the hook on *all* accesses that involve an AllocId, including zero-sized // accesses. That means we cannot rely on the closure above or the `Some` branch below. We // do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked. - if !self.memory.validation_in_progress.get() { + if !self.memory.validation_in_progress { if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) { M::before_alloc_read(self, alloc_id)?; } @@ -690,7 +694,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { let range = alloc_range(offset, size); - if !self.memory.validation_in_progress.get() { + if !self.memory.validation_in_progress { M::before_memory_read( self.tcx, &self.machine, @@ -727,7 +731,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // We have "NLL problem case #3" here, which cannot be worked around without loss of // efficiency even for the common case where the key is in the map. // - // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.) + // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`, and that boils down to + // Miri's `adjust_alloc_root_pointer` needing to look up the size of the allocation. + // It could be avoided with a totally separate codepath in Miri for handling the absolute address + // of global allocations, but that's not worth it.) if self.memory.alloc_map.get_mut(id).is_none() { // Slow path. // Allocation not found locally, go look global. @@ -763,14 +770,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { size: Size, ) -> InterpResult<'tcx, Option>> { - let parts = self.get_ptr_access(ptr, size)?; - if let Some((alloc_id, offset, prov)) = parts { - let tcx = self.tcx; - // FIXME: can we somehow avoid looking up the allocation twice here? - // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. - let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?; + let tcx = self.tcx; + let validation_in_progress = self.memory.validation_in_progress; + + let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes + let ptr_and_alloc = Self::check_and_deref_ptr( + self, + ptr, + size_i64, + CheckInAllocMsg::MemoryAccessTest, + |this, alloc_id, offset, prov| { + let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?; + Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) + }, + )?; + + if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc { let range = alloc_range(offset, size); - M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; + if !validation_in_progress { + M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; + } Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) } else { Ok(None) @@ -827,7 +846,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (size, align) = if nested { // Nested anonymous statics are untyped, so let's get their - // size and alignment from the allocaiton itself. This always + // size and alignment from the allocation itself. This always // succeeds, as the query is fed at DefId creation time, so no // evaluation actually occurs. let alloc = self.tcx.eval_static_initializer(def_id).unwrap(); @@ -924,12 +943,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if offset.bytes() != 0 { throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))) } - let Some(GlobalAlloc::VTable(ty, vtable_trait)) = self.tcx.try_get_global_alloc(alloc_id) + let Some(GlobalAlloc::VTable(ty, vtable_dyn_type)) = + self.tcx.try_get_global_alloc(alloc_id) else { throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))) }; - if let Some(expected_trait) = expected_trait { - self.check_vtable_for_type(vtable_trait, expected_trait)?; + if let Some(expected_dyn_type) = expected_trait { + self.check_vtable_for_type(vtable_dyn_type, expected_dyn_type)?; } Ok(ty) } @@ -1014,20 +1034,24 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// /// We do this so Miri's allocation access tracking does not show the validation /// reads as spurious accesses. - pub fn run_for_validation(&self, f: impl FnOnce() -> R) -> R { + pub fn run_for_validation(&mut self, f: impl FnOnce(&mut Self) -> R) -> R { // This deliberately uses `==` on `bool` to follow the pattern // `assert!(val.replace(new) == old)`. assert!( - self.memory.validation_in_progress.replace(true) == false, + mem::replace(&mut self.memory.validation_in_progress, true) == false, "`validation_in_progress` was already set" ); - let res = f(); + let res = f(self); assert!( - self.memory.validation_in_progress.replace(false) == true, + mem::replace(&mut self.memory.validation_in_progress, false) == true, "`validation_in_progress` was unset by someone else" ); res } + + pub(super) fn validation_in_progress(&self) -> bool { + self.memory.validation_in_progress + } } #[doc(hidden)] @@ -1090,11 +1114,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { Some(GlobalAlloc::Function { instance, .. }) => { write!(fmt, " (fn: {instance})")?; } - Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { - write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; - } - Some(GlobalAlloc::VTable(ty, None)) => { - write!(fmt, " (vtable: impl for {ty})")?; + Some(GlobalAlloc::VTable(ty, dyn_ty)) => { + write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?; } Some(GlobalAlloc::Static(did)) => { write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; @@ -1112,9 +1133,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { } /// Reading and writing. -impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> +impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRefMut<'a, 'tcx, Prov, Extra, Bytes> { + pub fn as_ref<'b>(&'b self) -> AllocRef<'b, 'tcx, Prov, Extra, Bytes> { + AllocRef { alloc: self.alloc, range: self.range, tcx: self.tcx, alloc_id: self.alloc_id } + } + /// `range` is relative to this allocation reference, not the base of the allocation. pub fn write_scalar(&mut self, range: AllocRange, val: Scalar) -> InterpResult<'tcx> { let range = self.range.subrange(range); @@ -1130,16 +1155,33 @@ impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) } + /// Mark the given sub-range (relative to this allocation reference) as uninitialized. + pub fn write_uninit(&mut self, range: AllocRange) -> InterpResult<'tcx> { + let range = self.range.subrange(range); + Ok(self + .alloc + .write_uninit(&self.tcx, range) + .map_err(|e| e.to_interp_error(self.alloc_id))?) + } + /// Mark the entire referenced range as uninitialized - pub fn write_uninit(&mut self) -> InterpResult<'tcx> { + pub fn write_uninit_full(&mut self) -> InterpResult<'tcx> { Ok(self .alloc .write_uninit(&self.tcx, self.range) .map_err(|e| e.to_interp_error(self.alloc_id))?) } + + /// Remove all provenance in the reference range. + pub fn clear_provenance(&mut self) -> InterpResult<'tcx> { + Ok(self + .alloc + .clear_provenance(&self.tcx, self.range) + .map_err(|e| e.to_interp_error(self.alloc_id))?) + } } -impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> { +impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn read_scalar( &self, @@ -1278,7 +1320,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); - assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation"); + assert!(!self.memory.validation_in_progress, "we can't be copying during validation"); M::before_memory_read( tcx, &self.machine, diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 511756e3f86c9..5e84626f77e7a 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -19,25 +19,25 @@ mod util; mod validity; mod visitor; -use eval_context::{from_known_layout, mir_assign_valid_types}; #[doc(no_inline)] pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here pub use self::call::FnArg; -pub use self::eval_context::{format_interp_error, InterpCx}; +pub use self::eval_context::{InterpCx, format_interp_error}; +use self::eval_context::{from_known_layout, mir_assign_valid_types}; pub use self::intern::{ - intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind, - InternResult, + HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop, + intern_const_alloc_recursive, }; pub(crate) use self::intrinsics::eval_nullary_intrinsic; -pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, ReturnAction}; +pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine}; pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; use self::operand::Operand; -pub use self::operand::{ImmTy, Immediate, OpTy, Readable}; +pub use self::operand::{ImmTy, Immediate, OpTy}; pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable}; use self::place::{MemPlace, Place}; pub use self::projection::{OffsetMode, Projectable}; pub use self::stack::{Frame, FrameInfo, LocalState, StackPopCleanup, StackPopInfo}; pub(crate) use self::util::create_static_alloc; -pub use self::validity::{CtfeValidationMode, RefTracking}; +pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking}; pub use self::visitor::ValueVisitor; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 9a8ccaa7cc5ca..31ee3e6519afc 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -14,9 +14,9 @@ use rustc_target::abi::{self, Abi, HasDataLayout, Size}; use tracing::trace; use super::{ - alloc_range, err_ub, from_known_layout, mir_assign_valid_types, throw_ub, CtfeProvenance, - InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, - Pointer, Projectable, Provenance, Scalar, + CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, + PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout, + mir_assign_valid_types, throw_ub, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -111,6 +111,46 @@ impl Immediate { Immediate::Uninit => bug!("Got uninit where a scalar or scalar pair was expected"), } } + + /// Assert that this immediate is a valid value for the given ABI. + pub fn assert_matches_abi(self, abi: Abi, cx: &impl HasDataLayout) { + match (self, abi) { + (Immediate::Scalar(scalar), Abi::Scalar(s)) => { + assert_eq!(scalar.size(), s.size(cx)); + if !matches!(s.primitive(), abi::Pointer(..)) { + assert!(matches!(scalar, Scalar::Int(..))); + } + } + (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { + assert_eq!(a_val.size(), a.size(cx)); + if !matches!(a.primitive(), abi::Pointer(..)) { + assert!(matches!(a_val, Scalar::Int(..))); + } + assert_eq!(b_val.size(), b.size(cx)); + if !matches!(b.primitive(), abi::Pointer(..)) { + assert!(matches!(b_val, Scalar::Int(..))); + } + } + (Immediate::Uninit, _) => {} + _ => { + bug!("value {self:?} does not match ABI {abi:?})",) + } + } + } + + pub fn clear_provenance<'tcx>(&mut self) -> InterpResult<'tcx> { + match self { + Immediate::Scalar(s) => { + s.clear_provenance()?; + } + Immediate::ScalarPair(a, b) => { + a.clear_provenance()?; + b.clear_provenance()?; + } + Immediate::Uninit => {} + } + Ok(()) + } } // ScalarPair needs a type to interpret, so we often have an immediate and a type together @@ -393,6 +433,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { Ok(self.offset_(offset, layout, ecx)) } + #[inline(always)] fn to_op>( &self, _ecx: &InterpCx<'tcx, M>, @@ -482,6 +523,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { } } + #[inline(always)] fn to_op>( &self, _ecx: &InterpCx<'tcx, M>, @@ -490,32 +532,6 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { } } -/// The `Readable` trait describes interpreter values that one can read from. -pub trait Readable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { - fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>>; -} - -impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for OpTy<'tcx, Prov> { - #[inline(always)] - fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>> { - self.as_mplace_or_imm() - } -} - -impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { - #[inline(always)] - fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>> { - Left(self.clone()) - } -} - -impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for ImmTy<'tcx, Prov> { - #[inline(always)] - fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>> { - Right(self.clone()) - } -} - impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. /// Returns `None` if the layout does not permit loading this as a value. @@ -588,9 +604,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// ConstProp needs it, though. pub fn read_immediate_raw( &self, - src: &impl Readable<'tcx, M::Provenance>, + src: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Either, ImmTy<'tcx, M::Provenance>>> { - Ok(match src.as_mplace_or_imm() { + Ok(match src.to_op(self)?.as_mplace_or_imm() { Left(ref mplace) => { if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { Right(val) @@ -608,7 +624,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline(always)] pub fn read_immediate( &self, - op: &impl Readable<'tcx, M::Provenance>, + op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { if !matches!( op.layout().abi, @@ -627,7 +643,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Read a scalar from a place pub fn read_scalar( &self, - op: &impl Readable<'tcx, M::Provenance>, + op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Scalar> { Ok(self.read_immediate(op)?.to_scalar()) } @@ -638,21 +654,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Read a pointer from a place. pub fn read_pointer( &self, - op: &impl Readable<'tcx, M::Provenance>, + op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Pointer>> { self.read_scalar(op)?.to_pointer(self) } /// Read a pointer-sized unsigned integer from a place. pub fn read_target_usize( &self, - op: &impl Readable<'tcx, M::Provenance>, + op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, u64> { self.read_scalar(op)?.to_target_usize(self) } /// Read a pointer-sized signed integer from a place. pub fn read_target_isize( &self, - op: &impl Readable<'tcx, M::Provenance>, + op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, i64> { self.read_scalar(op)?.to_target_isize(self) } @@ -665,30 +681,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(str) } - /// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements. - /// Also returns the number of elements. - /// - /// Can (but does not always) trigger UB if `op` is uninitialized. - pub fn operand_to_simd( - &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { - // Basically we just transmute this place into an array following simd_size_and_type. - // This only works in memory, but repr(simd) types should never be immediates anyway. - assert!(op.layout.ty.is_simd()); - match op.as_mplace_or_imm() { - Left(mplace) => self.mplace_to_simd(&mplace), - Right(imm) => match *imm { - Immediate::Uninit => { - throw_ub!(InvalidUninitBytes(None)) - } - Immediate::Scalar(..) | Immediate::ScalarPair(..) => { - bug!("arrays/slices can never have Scalar/ScalarPair layout") - } - }, - } - } - /// Read from a local of the current frame. /// Will not access memory, instead an indirect `Operand` is returned. /// @@ -705,6 +697,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(op, Operand::Immediate(_)) { assert!(!layout.is_unsized()); } + M::after_local_read(self, local)?; Ok(OpTy { op, layout }) } @@ -717,7 +710,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { match place.as_mplace_or_local() { Left(mplace) => Ok(mplace.into()), - Right((local, offset, locals_addr)) => { + Right((local, offset, locals_addr, _)) => { debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`. debug_assert_eq!(locals_addr, self.frame().locals_addr()); let base = self.local_to_op(local, None)?; diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index e9ba12dbcc4ea..863b330a74cd5 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -1,14 +1,15 @@ use either::Either; use rustc_apfloat::{Float, FloatConvert}; -use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::mir::NullOp; +use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::symbol::sym; +use rustc_target::abi::Size; use tracing::trace; -use super::{throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta}; +use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, throw_ub}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn three_way_compare(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> { @@ -287,6 +288,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }) } + /// Computes the total size of this access, `count * elem_size`, + /// checking for overflow beyond isize::MAX. + pub fn compute_size_in_bytes(&self, elem_size: Size, count: u64) -> Option { + // `checked_mul` applies `u64` limits independent of the target pointer size... but the + // subsequent check for `max_size_of_val` means we also handle 32bit targets correctly. + // (We cannot use `Size::checked_mul` as that enforces `obj_size_bound` as the limit, which + // would be wrong here.) + elem_size + .bytes() + .checked_mul(count) + .map(Size::from_bytes) + .filter(|&total| total <= self.max_size_of_val()) + } + fn binary_ptr_op( &self, bin_op: mir::BinOp, @@ -303,8 +318,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let pointee_layout = self.layout_of(pointee_ty)?; assert!(pointee_layout.abi.is_sized()); - // We cannot overflow i64 as a type's size must be <= isize::MAX. + // The size always fits in `i64` as it can be at most `isize::MAX`. let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap(); + // This uses the same type as `right`, which can be `isize` or `usize`. + // `pointee_size` is guaranteed to fit into both types. let pointee_size = ImmTy::from_int(pointee_size, right.layout); // Multiply element size and element count. let (val, overflowed) = self @@ -316,6 +333,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } let offset_bytes = val.to_target_isize(self)?; + if !right.layout.abi.is_signed() && offset_bytes < 0 { + // We were supposed to do an unsigned offset but the result is negative -- this + // can only mean that the cast wrapped around. + throw_ub!(PointerArithOverflow) + } let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?; Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout)) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index ede6a51c712b9..32f90254a9470 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -6,16 +6,16 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; use rustc_ast::Mutability; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, mir, span_bug}; use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; use tracing::{instrument, trace}; use super::{ - alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, - ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, - Operand, Pointer, Projectable, Provenance, Readable, Scalar, + AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, + Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance, + Scalar, alloc_range, mir_assign_valid_types, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -61,13 +61,13 @@ pub(super) struct MemPlace { impl MemPlace { /// Adjust the provenance of the main pointer (metadata is unaffected). - pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self { + fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self { MemPlace { ptr: self.ptr.map_provenance(|p| p.map(f)), ..self } } /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. #[inline] - pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { + fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { Immediate::new_pointer_with_meta(self.ptr, self.meta, cx) } @@ -166,6 +166,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout }) } + #[inline(always)] fn to_op>( &self, _ecx: &InterpCx<'tcx, M>, @@ -180,13 +181,14 @@ pub(super) enum Place { Ptr(MemPlace), /// To support alloc-free locals, we are able to write directly to a local. The offset indicates - /// where in the local this place is located; if it is `None`, no projection has been applied. + /// where in the local this place is located; if it is `None`, no projection has been applied + /// and the type of the place is exactly the type of the local. /// Such projections are meaningful even if the offset is 0, since they can change layouts. /// (Without that optimization, we'd just always be a `MemPlace`.) /// `Local` places always refer to the current stack frame, so they are unstable under /// function calls/returns and switching betweens stacks of different threads! /// We carry around the address of the `locals` buffer of the correct stack frame as a sanity - /// chec to be able to catch some cases of using a dangling `Place`. + /// check to be able to catch some cases of using a dangling `Place`. /// /// This variant shall not be used for unsized types -- those must always live in memory. Local { local: mir::Local, offset: Option, locals_addr: usize }, @@ -231,10 +233,12 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { #[inline(always)] pub fn as_mplace_or_local( &self, - ) -> Either, (mir::Local, Option, usize)> { + ) -> Either, (mir::Local, Option, usize, TyAndLayout<'tcx>)> { match self.place { Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout }), - Place::Local { local, offset, locals_addr } => Right((local, offset, locals_addr)), + Place::Local { local, offset, locals_addr } => { + Right((local, offset, locals_addr, self.layout)) + } } } @@ -277,7 +281,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { ) -> InterpResult<'tcx, Self> { Ok(match self.as_mplace_or_local() { Left(mplace) => mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into(), - Right((local, old_offset, locals_addr)) => { + Right((local, old_offset, locals_addr, _)) => { debug_assert!(layout.is_sized(), "unsized locals should live in memory"); assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway... // `Place::Local` are always in-bounds of their surrounding local, so we can just @@ -296,6 +300,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { }) } + #[inline(always)] fn to_op>( &self, ecx: &InterpCx<'tcx, M>, @@ -328,9 +333,7 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { /// The `Weiteable` trait describes interpreter values that can be written to. pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { - fn as_mplace_or_local( - &self, - ) -> Either, (mir::Local, Option, usize, TyAndLayout<'tcx>)>; + fn to_place(&self) -> PlaceTy<'tcx, Prov>; fn force_mplace>( &self, @@ -340,11 +343,8 @@ pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> { #[inline(always)] - fn as_mplace_or_local( - &self, - ) -> Either, (mir::Local, Option, usize, TyAndLayout<'tcx>)> { - self.as_mplace_or_local() - .map_right(|(local, offset, locals_addr)| (local, offset, locals_addr, self.layout)) + fn to_place(&self) -> PlaceTy<'tcx, Prov> { + self.clone() } #[inline(always)] @@ -358,10 +358,8 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> { impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { #[inline(always)] - fn as_mplace_or_local( - &self, - ) -> Either, (mir::Local, Option, usize, TyAndLayout<'tcx>)> { - Left(self.clone()) + fn to_place(&self) -> PlaceTy<'tcx, Prov> { + self.clone().into() } #[inline(always)] @@ -379,13 +377,15 @@ where Prov: Provenance, M: Machine<'tcx, Provenance = Prov>, { - pub fn ptr_with_meta_to_mplace( + fn ptr_with_meta_to_mplace( &self, ptr: Pointer>, meta: MemPlaceMeta, layout: TyAndLayout<'tcx>, + unaligned: bool, ) -> MPlaceTy<'tcx, M::Provenance> { - let misaligned = self.is_ptr_misaligned(ptr, layout.align.abi); + let misaligned = + if unaligned { None } else { self.is_ptr_misaligned(ptr, layout.align.abi) }; MPlaceTy { mplace: MemPlace { ptr, meta, misaligned }, layout } } @@ -395,7 +395,16 @@ where layout: TyAndLayout<'tcx>, ) -> MPlaceTy<'tcx, M::Provenance> { assert!(layout.is_sized()); - self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout) + self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ false) + } + + pub fn ptr_to_mplace_unaligned( + &self, + ptr: Pointer>, + layout: TyAndLayout<'tcx>, + ) -> MPlaceTy<'tcx, M::Provenance> { + assert!(layout.is_sized()); + self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ true) } /// Take a value, which represents a (thin or wide) reference, and make it a place. @@ -416,7 +425,7 @@ where // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; // we hence can't call `size_and_align_of` since that asserts more validity than we want. let ptr = ptr.to_pointer(self)?; - Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout)) + Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false)) } /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. @@ -436,7 +445,7 @@ where #[instrument(skip(self), level = "trace")] pub fn deref_pointer( &self, - src: &impl Readable<'tcx, M::Provenance>, + src: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { if src.layout().ty.is_box() { // Derefer should have removed all Box derefs. @@ -486,37 +495,18 @@ where Ok(a) } - /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. - /// Also returns the number of elements. - pub fn mplace_to_simd( - &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { - // Basically we want to transmute this place into an array following simd_size_and_type. - let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); - // Some SIMD types have padding, so `len` many `e_ty` does not cover the entire place. - // Therefore we cannot transmute, and instead we project at offset 0, which side-steps - // the size check. - let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, e_ty, len))?; - assert!(array_layout.size <= mplace.layout.size); - let mplace = mplace.offset(Size::ZERO, array_layout, self)?; - Ok((mplace, len)) - } - /// Turn a local in the current frame into a place. pub fn local_to_place( &self, local: mir::Local, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { - // Other parts of the system rely on `Place::Local` never being unsized. - // So we eagerly check here if this local has an MPlace, and if yes we use it. let frame = self.frame(); let layout = self.layout_of_local(frame, local, None)?; let place = if layout.is_sized() { // We can just always use the `Local` for sized values. Place::Local { local, offset: None, locals_addr: frame.locals_addr() } } else { - // Unsized `Local` isn't okay (we cannot store the metadata). + // Other parts of the system rely on `Place::Local` never being unsized. match frame.locals[local].access()? { Operand::Immediate(_) => bug!(), Operand::Indirect(mplace) => Place::Ptr(*mplace), @@ -562,6 +552,44 @@ where Ok(place) } + /// Given a place, returns either the underlying mplace or a reference to where the value of + /// this place is stored. + #[inline(always)] + fn as_mplace_or_mutable_local( + &mut self, + place: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult< + 'tcx, + Either< + MPlaceTy<'tcx, M::Provenance>, + (&mut Immediate, TyAndLayout<'tcx>, mir::Local), + >, + > { + Ok(match place.to_place().as_mplace_or_local() { + Left(mplace) => Left(mplace), + Right((local, offset, locals_addr, layout)) => { + if offset.is_some() { + // This has been projected to a part of this local, or had the type changed. + // FIMXE: there are cases where we could still avoid allocating an mplace. + Left(place.force_mplace(self)?) + } else { + debug_assert_eq!(locals_addr, self.frame().locals_addr()); + debug_assert_eq!(self.layout_of_local(self.frame(), local, None)?, layout); + match self.frame_mut().locals[local].access_mut()? { + Operand::Indirect(mplace) => { + // The local is in memory. + Left(MPlaceTy { mplace: *mplace, layout }) + } + Operand::Immediate(local_val) => { + // The local still has the optimized representation. + Right((local_val, layout, local)) + } + } + } + } + }) + } + /// Write an immediate to a place #[inline(always)] #[instrument(skip(self), level = "trace")] @@ -574,9 +602,11 @@ where if M::enforce_validity(self, dest.layout()) { // Data got changed, better make sure it matches the type! + // Also needed to reset padding. self.validate_operand( - &dest.to_op(self)?, + &dest.to_place(), M::enforce_validity_recursively(self, dest.layout()), + /*reset_provenance_and_padding*/ true, )?; } @@ -606,67 +636,31 @@ where /// Write an immediate to a place. /// If you use this you are responsible for validating that things got copied at the /// right type. - fn write_immediate_no_validate( + pub(super) fn write_immediate_no_validate( &mut self, src: Immediate, dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { assert!(dest.layout().is_sized(), "Cannot write unsized immediate data"); - // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`, - // but not factored as a separate function. - let mplace = match dest.as_mplace_or_local() { - Right((local, offset, locals_addr, layout)) => { - if offset.is_some() { - // This has been projected to a part of this local. We could have complicated - // logic to still keep this local as an `Operand`... but it's much easier to - // just fall back to the indirect path. - dest.force_mplace(self)? - } else { - debug_assert_eq!(locals_addr, self.frame().locals_addr()); - match self.frame_mut().locals[local].access_mut()? { - Operand::Immediate(local_val) => { - // Local can be updated in-place. - *local_val = src; - // Double-check that the value we are storing and the local fit to each other. - // (*After* doing the update for borrow checker reasons.) - if cfg!(debug_assertions) { - let local_layout = - self.layout_of_local(&self.frame(), local, None)?; - match (src, local_layout.abi) { - (Immediate::Scalar(scalar), Abi::Scalar(s)) => { - assert_eq!(scalar.size(), s.size(self)) - } - ( - Immediate::ScalarPair(a_val, b_val), - Abi::ScalarPair(a, b), - ) => { - assert_eq!(a_val.size(), a.size(self)); - assert_eq!(b_val.size(), b.size(self)); - } - (Immediate::Uninit, _) => {} - (src, abi) => { - bug!( - "value {src:?} cannot be written into local with type {} (ABI {abi:?})", - local_layout.ty - ) - } - }; - } - return Ok(()); - } - Operand::Indirect(mplace) => { - // The local is in memory, go on below. - MPlaceTy { mplace: *mplace, layout } - } - } + match self.as_mplace_or_mutable_local(&dest.to_place())? { + Right((local_val, local_layout, local)) => { + // Local can be updated in-place. + *local_val = src; + // Call the machine hook (the data race detector needs to know about this write). + if !self.validation_in_progress() { + M::after_local_write(self, local, /*storage_live*/ false)?; + } + // Double-check that the value we are storing and the local fit to each other. + if cfg!(debug_assertions) { + src.assert_matches_abi(local_layout.abi, self); } } - Left(mplace) => mplace, // already referring to memory - }; - - // This is already in memory, write there. - self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace) + Left(mplace) => { + self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace)?; + } + } + Ok(()) } /// Write an immediate to memory. @@ -678,6 +672,9 @@ where layout: TyAndLayout<'tcx>, dest: MemPlace, ) -> InterpResult<'tcx> { + if cfg!(debug_assertions) { + value.assert_matches_abi(layout.abi, self); + } // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here // to handle padding properly, which is only correct if we never look at this data with the @@ -691,15 +688,7 @@ where match value { Immediate::Scalar(scalar) => { - let Abi::Scalar(s) = layout.abi else { - span_bug!( - self.cur_span(), - "write_immediate_to_mplace: invalid Scalar layout: {layout:#?}", - ) - }; - let size = s.size(&tcx); - assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); - alloc.write_scalar(alloc_range(Size::ZERO, size), scalar) + alloc.write_scalar(alloc_range(Size::ZERO, scalar.size()), scalar) } Immediate::ScalarPair(a_val, b_val) => { let Abi::ScalarPair(a, b) = layout.abi else { @@ -709,18 +698,19 @@ where layout ) }; - let (a_size, b_size) = (a.size(&tcx), b.size(&tcx)); - let b_offset = a_size.align_to(b.align(&tcx).abi); + let b_offset = a.size(&tcx).align_to(b.align(&tcx).abi); assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, // but that does not work: We could be a newtype around a pair, then the // fields do not match the `ScalarPair` components. - alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?; - alloc.write_scalar(alloc_range(b_offset, b_size), b_val) + alloc.write_scalar(alloc_range(Size::ZERO, a_val.size()), a_val)?; + alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?; + // We don't have to reset padding here, `write_immediate` will anyway do a validation run. + Ok(()) } - Immediate::Uninit => alloc.write_uninit(), + Immediate::Uninit => alloc.write_uninit_full(), } } @@ -728,35 +718,46 @@ where &mut self, dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - let mplace = match dest.as_mplace_or_local() { - Left(mplace) => mplace, - Right((local, offset, locals_addr, layout)) => { - if offset.is_some() { - // This has been projected to a part of this local. We could have complicated - // logic to still keep this local as an `Operand`... but it's much easier to - // just fall back to the indirect path. - // FIXME: share the logic with `write_immediate_no_validate`. - dest.force_mplace(self)? - } else { - debug_assert_eq!(locals_addr, self.frame().locals_addr()); - match self.frame_mut().locals[local].access_mut()? { - Operand::Immediate(local) => { - *local = Immediate::Uninit; - return Ok(()); - } - Operand::Indirect(mplace) => { - // The local is in memory, go on below. - MPlaceTy { mplace: *mplace, layout } - } - } + match self.as_mplace_or_mutable_local(&dest.to_place())? { + Right((local_val, _local_layout, local)) => { + *local_val = Immediate::Uninit; + // Call the machine hook (the data race detector needs to know about this write). + if !self.validation_in_progress() { + M::after_local_write(self, local, /*storage_live*/ false)?; } } - }; - let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { - // Zero-sized access - return Ok(()); - }; - alloc.write_uninit()?; + Left(mplace) => { + let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { + // Zero-sized access + return Ok(()); + }; + alloc.write_uninit_full()?; + } + } + Ok(()) + } + + /// Remove all provenance in the given place. + pub fn clear_provenance( + &mut self, + dest: &impl Writeable<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + match self.as_mplace_or_mutable_local(&dest.to_place())? { + Right((local_val, _local_layout, local)) => { + local_val.clear_provenance()?; + // Call the machine hook (the data race detector needs to know about this write). + if !self.validation_in_progress() { + M::after_local_write(self, local, /*storage_live*/ false)?; + } + } + Left(mplace) => { + let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { + // Zero-sized access + return Ok(()); + }; + alloc.clear_provenance()?; + } + } Ok(()) } @@ -768,7 +769,7 @@ where #[inline(always)] pub(super) fn copy_op_no_dest_validation( &mut self, - src: &impl Readable<'tcx, M::Provenance>, + src: &impl Projectable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.copy_op_inner( @@ -781,7 +782,7 @@ where #[inline(always)] pub fn copy_op_allow_transmute( &mut self, - src: &impl Readable<'tcx, M::Provenance>, + src: &impl Projectable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.copy_op_inner( @@ -794,7 +795,7 @@ where #[inline(always)] pub fn copy_op( &mut self, - src: &impl Readable<'tcx, M::Provenance>, + src: &impl Projectable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.copy_op_inner( @@ -808,28 +809,35 @@ where #[instrument(skip(self), level = "trace")] fn copy_op_inner( &mut self, - src: &impl Readable<'tcx, M::Provenance>, + src: &impl Projectable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool, validate_dest: bool, ) -> InterpResult<'tcx> { - // Generally for transmutation, data must be valid both at the old and new type. - // But if the types are the same, the 2nd validation below suffices. - if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) { - self.validate_operand( - &src.to_op(self)?, - M::enforce_validity_recursively(self, src.layout()), - )?; - } + // These are technically *two* typed copies: `src` is a not-yet-loaded value, + // so we're going a typed copy at `src` type from there to some intermediate storage. + // And then we're doing a second typed copy from that intermediate storage to `dest`. + // But as an optimization, we only make a single direct copy here. // Do the actual copy. self.copy_op_no_validate(src, dest, allow_transmute)?; if validate_dest && M::enforce_validity(self, dest.layout()) { - // Data got changed, better make sure it matches the type! + let dest = dest.to_place(); + // Given that there were two typed copies, we have to ensure this is valid at both types, + // and we have to ensure this loses provenance and padding according to both types. + // But if the types are identical, we only do one pass. + if allow_transmute && src.layout().ty != dest.layout().ty { + self.validate_operand( + &dest.transmute(src.layout(), self)?, + M::enforce_validity_recursively(self, src.layout()), + /*reset_provenance_and_padding*/ true, + )?; + } self.validate_operand( - &dest.to_op(self)?, + &dest, M::enforce_validity_recursively(self, dest.layout()), + /*reset_provenance_and_padding*/ true, )?; } @@ -843,7 +851,7 @@ where #[instrument(skip(self), level = "trace")] fn copy_op_no_validate( &mut self, - src: &impl Readable<'tcx, M::Provenance>, + src: &impl Projectable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool, ) -> InterpResult<'tcx> { @@ -946,7 +954,7 @@ where mplace.mplace, )?; } - M::after_local_allocated(self, local, &mplace)?; + M::after_local_moved_to_memory(self, local, &mplace)?; // Now we can call `access_mut` again, asserting it goes well, and actually // overwrite things. This points to the entire allocation, not just the part // the place refers to, i.e. we do this before we apply `offset`. @@ -985,7 +993,7 @@ where span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; let ptr = self.allocate_ptr(size, align, kind)?; - Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout)) + Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) } pub fn allocate( @@ -1020,7 +1028,12 @@ where }; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); let layout = self.layout_of(self.tcx.types.str_).unwrap(); - Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout)) + Ok(self.ptr_with_meta_to_mplace( + ptr.into(), + MemPlaceMeta::Meta(meta), + layout, + /*unaligned*/ false, + )) } pub fn raw_const_to_mplace( diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index dd8dd21e0e8b9..621afdb1050a2 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -10,15 +10,15 @@ use std::marker::PhantomData; use std::ops::Range; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, mir, span_bug, ty}; use rustc_target::abi::{self, Size, VariantIdx}; use tracing::{debug, instrument}; use super::{ - throw_ub, throw_unsup, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, - Provenance, Scalar, + InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, err_ub, + throw_ub, throw_unsup, }; /// Describes the constraints placed on offset-projections. @@ -101,7 +101,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { } /// A type representing iteration over the elements of an array. -pub struct ArrayIterator<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> { +pub struct ArrayIterator<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> { base: &'a P, range: Range, stride: Size, @@ -109,7 +109,7 @@ pub struct ArrayIterator<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> _phantom: PhantomData, // otherwise it says `Prov` is never used... } -impl<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'tcx, 'a, Prov, P> { +impl<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'a, 'tcx, Prov, P> { /// Should be the same `ecx` on each call, and match the one used to create the iterator. pub fn next>( &mut self, @@ -229,7 +229,11 @@ where // This can only be reached in ConstProp and non-rustc-MIR. throw_ub!(BoundsCheckFailed { len, index }); } - let offset = stride * index; // `Size` multiplication + // With raw slices, `len` can be so big that this *can* overflow. + let offset = self + .compute_size_in_bytes(stride, index) + .ok_or_else(|| err_ub!(PointerArithOverflow))?; + // All fields have the same layout. let field_layout = base.layout().field(self, 0); (offset, field_layout) @@ -244,6 +248,19 @@ where base.offset(offset, field_layout, self) } + /// Converts a repr(simd) value into an array of the right size, such that `project_index` + /// accesses the SIMD elements. Also returns the number of elements. + pub fn project_to_simd>( + &self, + base: &P, + ) -> InterpResult<'tcx, (P, u64)> { + assert!(base.layout().ty.ty_adt_def().unwrap().repr().simd()); + // SIMD types must be newtypes around arrays, so all we have to do is project to their only field. + let array = self.project_field(base, 0)?; + let len = array.len(self)?; + Ok((array, len)) + } + fn project_constant_index>( &self, base: &P, @@ -273,7 +290,7 @@ where pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>( &self, base: &'a P, - ) -> InterpResult<'tcx, ArrayIterator<'tcx, 'a, M::Provenance, P>> { + ) -> InterpResult<'tcx, ArrayIterator<'a, 'tcx, M::Provenance, P>> { let abi::FieldsShape::Array { stride, .. } = base.layout().fields else { span_bug!(self.cur_span(), "project_array_fields: expected an array layout"); }; diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 0f6bf5c03364c..15868f1b02d92 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -1,5 +1,5 @@ //! Manages the low-level pushing and popping of stack frames and the (de)allocation of local variables. -//! For hadling of argument passing and return values, see the `call` module. +//! For handling of argument passing and return values, see the `call` module. use std::cell::Cell; use std::{fmt, mem}; @@ -15,9 +15,9 @@ use rustc_span::Span; use tracing::{info_span, instrument, trace}; use super::{ - from_known_layout, throw_ub, throw_unsup, AllocId, CtfeProvenance, Immediate, InterpCx, - InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, MemoryKind, Operand, Pointer, - Provenance, ReturnAction, Scalar, + AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, + MemPlaceMeta, MemoryKind, Operand, Pointer, Provenance, ReturnAction, Scalar, + from_known_layout, throw_ub, throw_unsup, }; use crate::errors; @@ -534,8 +534,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?; Operand::Indirect(*dest_place.mplace()) } else { - assert!(!meta.has_meta()); // we're dropping the metadata // Just make this an efficient immediate. + assert!(!meta.has_meta()); // we're dropping the metadata + // Make sure the machine knows this "write" is happening. (This is important so that + // races involving local variable allocation can be detected by Miri.) + M::after_local_write(self, local, /*storage_live*/ true)?; // Note that not calling `layout_of` here does have one real consequence: // if the type is too big, we'll only notice this when the local is actually initialized, // which is a bit too late -- we should ideally notice this already here, when the memory diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 70cfba1922c6e..8e2367e0d214c 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -9,12 +9,12 @@ use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::source_map::Spanned; use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx}; use tracing::{info, instrument, trace}; use super::{ - throw_ub, FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, - PlaceTy, Projectable, Scalar, + FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, + Projectable, Scalar, throw_ub, }; use crate::util; diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index cd4faf06655fe..8eead6018ac4a 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,36 +1,35 @@ use rustc_middle::mir::interpret::{InterpResult, Pointer}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, Ty, TyCtxt, VtblEntry}; +use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry}; use rustc_target::abi::{Align, Size}; use tracing::trace; use super::util::ensure_monomorphic_enough; -use super::{throw_ub, InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable}; +use super::{InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, throw_ub}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// - /// The `trait_ref` encodes the erased self type. Hence, if we are making an object `Foo` - /// from a value of type `Foo`, then `trait_ref` would map `T: Trait`. `None` here means that - /// this is an auto trait without any methods, so we only need the basic vtable (drop, size, - /// align). + /// The `dyn_ty` encodes the erased self type. Hence, if we are making an object + /// `Foo + Send>` from a value of type `Foo`, then `dyn_ty` + /// would be `Trait + Send`. If this list doesn't have a principal trait ref, + /// we only need the basic vtable prefix (drop, size, align). pub fn get_vtable_ptr( &self, ty: Ty<'tcx>, - poly_trait_ref: Option>, + dyn_ty: &'tcx ty::List>, ) -> InterpResult<'tcx, Pointer>> { - trace!("get_vtable(trait_ref={:?})", poly_trait_ref); + trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})"); - let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); + let (ty, dyn_ty) = self.tcx.erase_regions((ty, dyn_ty)); // All vtables must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, ty)?; - ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; + ensure_monomorphic_enough(*self.tcx, dyn_ty)?; let salt = M::get_global_alloc_salt(self, None); - let vtable_symbolic_allocation = - self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref, salt); + let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt); let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?; Ok(vtable_ptr.into()) } @@ -64,17 +63,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// expected trait type. pub(super) fn check_vtable_for_type( &self, - vtable_trait: Option>, - expected_trait: &'tcx ty::List>, + vtable_dyn_type: &'tcx ty::List>, + expected_dyn_type: &'tcx ty::List>, ) -> InterpResult<'tcx> { - let eq = match (expected_trait.principal(), vtable_trait) { - (Some(a), Some(b)) => self.eq_in_param_env(a, b), - (None, None) => true, - _ => false, - }; - if !eq { - throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait }); + // We check validity by comparing the lists of predicates for equality. We *could* instead + // check that the dynamic type to which the vtable belongs satisfies all the expected + // predicates, but that would likely be a lot slower and seems unnecessarily permissive. + + // FIXME: we are skipping auto traits for now, but might revisit this in the future. + let mut sorted_vtable: Vec<_> = vtable_dyn_type.without_auto_traits().collect(); + let mut sorted_expected: Vec<_> = expected_dyn_type.without_auto_traits().collect(); + // `skip_binder` here is okay because `stable_cmp` doesn't look at binders + sorted_vtable.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder())); + sorted_vtable.dedup(); + sorted_expected.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder())); + sorted_expected.dedup(); + + if sorted_vtable.len() != sorted_expected.len() { + throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }); + } + + for (a_pred, b_pred) in std::iter::zip(sorted_vtable, sorted_expected) { + let is_eq = match (a_pred.skip_binder(), b_pred.skip_binder()) { + ( + ty::ExistentialPredicate::Trait(a_data), + ty::ExistentialPredicate::Trait(b_data), + ) => self.eq_in_param_env(a_pred.rebind(a_data), b_pred.rebind(b_data)), + + ( + ty::ExistentialPredicate::Projection(a_data), + ty::ExistentialPredicate::Projection(b_data), + ) => self.eq_in_param_env(a_pred.rebind(a_data), b_pred.rebind(b_data)), + + _ => false, + }; + if !is_eq { + throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }); + } } + Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 6f5bcebbbb66f..2d53badf0f967 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{ }; use tracing::debug; -use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind}; +use super::{InterpCx, MPlaceTy, MemoryKind, throw_inval}; use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; /// Checks whether a type contains generic parameters which must be instantiated. @@ -103,5 +103,5 @@ pub(crate) fn create_static_alloc<'tcx>( assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); - Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout)) + Ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 26b7251f6dbc5..203cceccd9d1f 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -4,6 +4,7 @@ //! That's useful because it means other passes (e.g. promotion) can rely on `const`s //! to be const-safe. +use std::borrow::Cow; use std::fmt::Write; use std::hash::Hash; use std::num::NonZero; @@ -17,21 +18,21 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::ValidationErrorKind::{self, *}; use rustc_middle::mir::interpret::{ ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, - UnsupportedOpInfo, ValidationErrorInfo, + UnsupportedOpInfo, ValidationErrorInfo, alloc_range, }; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use rustc_target::abi::{ - Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, + Abi, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, }; use tracing::trace; use super::machine::AllocMap; use super::{ - err_ub, format_interp_error, throw_ub, AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, - Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, - Scalar, ValueVisitor, + AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, + MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, + format_interp_error, throw_ub, }; // for the validation errors @@ -125,6 +126,7 @@ pub enum PathElem { EnumTag, CoroutineTag, DynDowncast, + Vtable, } /// Extra things to check for during validation of CTFE results. @@ -163,22 +165,22 @@ impl RefTracking pub fn empty() -> Self { RefTracking { seen: FxHashSet::default(), todo: vec![] } } - pub fn new(op: T) -> Self { + pub fn new(val: T) -> Self { let mut ref_tracking_for_consts = - RefTracking { seen: FxHashSet::default(), todo: vec![(op.clone(), PATH::default())] }; - ref_tracking_for_consts.seen.insert(op); + RefTracking { seen: FxHashSet::default(), todo: vec![(val.clone(), PATH::default())] }; + ref_tracking_for_consts.seen.insert(val); ref_tracking_for_consts } pub fn next(&mut self) -> Option<(T, PATH)> { self.todo.pop() } - fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { - if self.seen.insert(op.clone()) { - trace!("Recursing below ptr {:#?}", op); + fn track(&mut self, val: T, path: impl FnOnce() -> PATH) { + if self.seen.insert(val.clone()) { + trace!("Recursing below ptr {:#?}", val); let path = path(); // Remember to come back to this later. - self.todo.push((op, path)); + self.todo.push((val, path)); } } } @@ -204,11 +206,62 @@ fn write_path(out: &mut String, path: &[PathElem]) { // not the root. Deref => write!(out, "."), DynDowncast => write!(out, "."), + Vtable => write!(out, "."), } .unwrap() } } +/// Represents a set of `Size` values as a sorted list of ranges. +// These are (offset, length) pairs, and they are sorted and mutually disjoint, +// and never adjacent (i.e. there's always a gap between two of them). +#[derive(Debug, Clone)] +pub struct RangeSet(Vec<(Size, Size)>); + +impl RangeSet { + fn add_range(&mut self, offset: Size, size: Size) { + if size.bytes() == 0 { + // No need to track empty ranges. + return; + } + let v = &mut self.0; + // We scan for a partition point where the left partition is all the elements that end + // strictly before we start. Those are elements that are too "low" to merge with us. + let idx = + v.partition_point(|&(other_offset, other_size)| other_offset + other_size < offset); + // Now we want to either merge with the first element of the second partition, or insert ourselves before that. + if let Some(&(other_offset, other_size)) = v.get(idx) + && offset + size >= other_offset + { + // Their end is >= our start (otherwise it would not be in the 2nd partition) and + // our end is >= their start. This means we can merge the ranges. + let new_start = other_offset.min(offset); + let mut new_end = (other_offset + other_size).max(offset + size); + // We grew to the right, so merge with overlapping/adjacent elements. + // (We also may have grown to the left, but that can never make us adjacent with + // anything there since we selected the first such candidate via `partition_point`.) + let mut scan_right = 1; + while let Some(&(next_offset, next_size)) = v.get(idx + scan_right) + && new_end >= next_offset + { + // Increase our size to absorb the next element. + new_end = new_end.max(next_offset + next_size); + // Look at the next element. + scan_right += 1; + } + // Update the element we grew. + v[idx] = (new_start, new_end - new_start); + // Remove the elements we absorbed (if any). + if scan_right > 1 { + drop(v.drain((idx + 1)..(idx + scan_right))); + } + } else { + // Insert new element. + v.insert(idx, (offset, size)); + } + } +} + struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> { /// The `path` may be pushed to, but the part that is present when a function /// starts must not be changed! `visit_fields` and `visit_array` rely on @@ -217,7 +270,17 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> { ref_tracking: Option<&'rt mut RefTracking, Vec>>, /// `None` indicates this is not validating for CTFE (but for runtime). ctfe_mode: Option, - ecx: &'rt InterpCx<'tcx, M>, + ecx: &'rt mut InterpCx<'tcx, M>, + /// Whether provenance should be reset outside of pointers (emulating the effect of a typed + /// copy). + reset_provenance_and_padding: bool, + /// This tracks which byte ranges in this value contain data; the remaining bytes are padding. + /// The ideal representation here would be pointer-length pairs, but to keep things more compact + /// we only store a (range) set of offsets -- the base pointer is the same throughout the entire + /// visit, after all. + /// If this is `Some`, then `reset_provenance_and_padding` must be true (but not vice versa: + /// we might not track data vs padding bytes if the operand isn't stored in memory anyway). + data_bytes: Option, } impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { @@ -287,8 +350,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // arrays/slices ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field), + // dyn* vtables + ty::Dynamic(_, _, ty::DynKind::DynStar) if field == 1 => PathElem::Vtable, + // dyn traits - ty::Dynamic(..) => PathElem::DynDowncast, + ty::Dynamic(..) => { + assert_eq!(field, 0); + PathElem::DynDowncast + } // nothing else has an aggregate layout _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", layout.ty), @@ -314,11 +383,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { fn read_immediate( &self, - op: &OpTy<'tcx, M::Provenance>, + val: &PlaceTy<'tcx, M::Provenance>, expected: ExpectedKind, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { Ok(try_validation!( - self.ecx.read_immediate(op), + self.ecx.read_immediate(val), self.path, Ub(InvalidUninitBytes(None)) => Uninit { expected }, @@ -332,10 +401,40 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { fn read_scalar( &self, - op: &OpTy<'tcx, M::Provenance>, + val: &PlaceTy<'tcx, M::Provenance>, expected: ExpectedKind, ) -> InterpResult<'tcx, Scalar> { - Ok(self.read_immediate(op, expected)?.to_scalar()) + Ok(self.read_immediate(val, expected)?.to_scalar()) + } + + fn deref_pointer( + &mut self, + val: &PlaceTy<'tcx, M::Provenance>, + expected: ExpectedKind, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + // Not using `ecx.deref_pointer` since we want to use our `read_immediate` wrapper. + let imm = self.read_immediate(val, expected)?; + // Reset provenance: ensure slice tail metadata does not preserve provenance, + // and ensure all pointers do not preserve partial provenance. + if self.reset_provenance_and_padding { + if matches!(imm.layout.abi, Abi::Scalar(..)) { + // A thin pointer. If it has provenance, we don't have to do anything. + // If it does not, ensure we clear the provenance in memory. + if matches!(imm.to_scalar(), Scalar::Int(..)) { + self.ecx.clear_provenance(val)?; + } + } else { + // A wide pointer. This means we have to worry both about the pointer itself and the + // metadata. We do the lazy thing and just write back the value we got. Just + // clearing provenance in a targeted manner would be more efficient, but unless this + // is a perf hotspot it's just not worth the effort. + self.ecx.write_immediate_no_validate(*imm, val)?; + } + // The entire thing is data, not padding. + self.add_data_range_place(val); + } + // Now turn it into a place. + self.ecx.ref_to_mplace(&imm) } fn check_wide_ptr_meta( @@ -353,8 +452,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.path, Ub(DanglingIntPointer{ .. } | InvalidVTablePointer(..)) => InvalidVTablePtr { value: format!("{vtable}") }, - Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => { - InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait } + Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => { + InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } }, ); } @@ -376,11 +475,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { /// Check a reference or `Box`. fn check_safe_pointer( &mut self, - value: &OpTy<'tcx, M::Provenance>, + value: &PlaceTy<'tcx, M::Provenance>, ptr_kind: PointerKind, ) -> InterpResult<'tcx> { - // Not using `deref_pointer` since we want to use our `read_immediate` wrapper. - let place = self.ecx.ref_to_mplace(&self.read_immediate(value, ptr_kind.into())?)?; + let place = self.deref_pointer(value, ptr_kind.into())?; // Handle wide pointers. // Check metadata early, for better diagnostics if place.layout.is_unsized() { @@ -519,6 +617,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if ptr_expected_mutbl == Mutability::Mut && alloc_actual_mutbl == Mutability::Not { + // This can actually occur with transmutes. throw_validation_failure!(self.path, MutableRefToImmutable); } // In a const, everything must be completely immutable. @@ -564,31 +663,39 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { /// Note that not all of these have `FieldsShape::Primitive`, e.g. wide references. fn try_visit_primitive( &mut self, - value: &OpTy<'tcx, M::Provenance>, + value: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; match ty.kind() { ty::Bool => { - let value = self.read_scalar(value, ExpectedKind::Bool)?; + let scalar = self.read_scalar(value, ExpectedKind::Bool)?; try_validation!( - value.to_bool(), + scalar.to_bool(), self.path, Ub(InvalidBool(..)) => ValidationErrorKind::InvalidBool { - value: format!("{value:x}"), + value: format!("{scalar:x}"), } ); + if self.reset_provenance_and_padding { + self.ecx.clear_provenance(value)?; + self.add_data_range_place(value); + } Ok(true) } ty::Char => { - let value = self.read_scalar(value, ExpectedKind::Char)?; + let scalar = self.read_scalar(value, ExpectedKind::Char)?; try_validation!( - value.to_char(), + scalar.to_char(), self.path, Ub(InvalidChar(..)) => ValidationErrorKind::InvalidChar { - value: format!("{value:x}"), + value: format!("{scalar:x}"), } ); + if self.reset_provenance_and_padding { + self.ecx.clear_provenance(value)?; + self.add_data_range_place(value); + } Ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { @@ -602,11 +709,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ExpectedKind::Int }, )?; + if self.reset_provenance_and_padding { + self.ecx.clear_provenance(value)?; + self.add_data_range_place(value); + } Ok(true) } ty::RawPtr(..) => { - let place = - self.ecx.ref_to_mplace(&self.read_immediate(value, ExpectedKind::RawPtr)?)?; + let place = self.deref_pointer(value, ExpectedKind::RawPtr)?; if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta(), place.layout)?; } @@ -617,11 +727,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { Ok(true) } ty::FnPtr(..) => { - let value = self.read_scalar(value, ExpectedKind::FnPtr)?; + let scalar = self.read_scalar(value, ExpectedKind::FnPtr)?; // If we check references recursively, also check that this points to a function. if let Some(_) = self.ref_tracking { - let ptr = value.to_pointer(self.ecx)?; + let ptr = scalar.to_pointer(self.ecx)?; let _fn = try_validation!( self.ecx.get_ptr_fn(ptr), self.path, @@ -631,10 +741,18 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // FIXME: Check if the signature matches } else { // Otherwise (for standalone Miri), we have to still check it to be non-null. - if self.ecx.scalar_may_be_null(value)? { + if self.ecx.scalar_may_be_null(scalar)? { throw_validation_failure!(self.path, NullFnPtr); } } + if self.reset_provenance_and_padding { + // Make sure we do not preserve partial provenance. This matches the thin + // pointer handling in `deref_pointer`. + if matches!(scalar, Scalar::Int(..)) { + self.ecx.clear_provenance(value)?; + } + self.add_data_range_place(value); + } Ok(true) } ty::Never => throw_validation_failure!(self.path, NeverVal), @@ -685,10 +803,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if start == 1 && end == max_value { // Only null is the niche. So make sure the ptr is NOT null. if self.ecx.scalar_may_be_null(scalar)? { - throw_validation_failure!( - self.path, - NullablePtrOutOfRange { range: valid_range, max_value } - ) + throw_validation_failure!(self.path, NullablePtrOutOfRange { + range: valid_range, + max_value + }) } else { return Ok(()); } @@ -698,10 +816,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } else { // Conservatively, we reject, because the pointer *could* have a bad // value. - throw_validation_failure!( - self.path, - PtrOutOfRange { range: valid_range, max_value } - ) + throw_validation_failure!(self.path, PtrOutOfRange { + range: valid_range, + max_value + }) } } }; @@ -709,20 +827,186 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if valid_range.contains(bits) { Ok(()) } else { - throw_validation_failure!( - self.path, - OutOfRange { value: format!("{bits}"), range: valid_range, max_value } - ) + throw_validation_failure!(self.path, OutOfRange { + value: format!("{bits}"), + range: valid_range, + max_value + }) } } - fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool { - if let Some(mplace) = op.as_mplace_or_imm().left() { + fn in_mutable_memory(&self, val: &PlaceTy<'tcx, M::Provenance>) -> bool { + if let Some(mplace) = val.as_mplace_or_local().left() { if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { - return mutability(self.ecx, alloc_id).is_mut(); + mutability(self.ecx, alloc_id).is_mut() + } else { + // No memory at all. + false + } + } else { + // A local variable -- definitely mutable. + true + } + } + + /// Add the given pointer-length pair to the "data" range of this visit. + fn add_data_range(&mut self, ptr: Pointer>, size: Size) { + if let Some(data_bytes) = self.data_bytes.as_mut() { + // We only have to store the offset, the rest is the same for all pointers here. + let (_prov, offset) = ptr.into_parts(); + // Add this. + data_bytes.add_range(offset, size); + }; + } + + /// Add the entire given place to the "data" range of this visit. + fn add_data_range_place(&mut self, place: &PlaceTy<'tcx, M::Provenance>) { + // Only sized places can be added this way. + debug_assert!(place.layout.abi.is_sized()); + if let Some(data_bytes) = self.data_bytes.as_mut() { + let offset = Self::data_range_offset(self.ecx, place); + data_bytes.add_range(offset, place.layout.size); + } + } + + /// Convert a place into the offset it starts at, for the purpose of data_range tracking. + /// Must only be called if `data_bytes` is `Some(_)`. + fn data_range_offset(ecx: &InterpCx<'tcx, M>, place: &PlaceTy<'tcx, M::Provenance>) -> Size { + // The presence of `data_bytes` implies that our place is in memory. + let ptr = ecx + .place_to_op(place) + .expect("place must be in memory") + .as_mplace_or_imm() + .expect_left("place must be in memory") + .ptr(); + let (_prov, offset) = ptr.into_parts(); + offset + } + + fn reset_padding(&mut self, place: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + let Some(data_bytes) = self.data_bytes.as_mut() else { return Ok(()) }; + // Our value must be in memory, otherwise we would not have set up `data_bytes`. + let mplace = self.ecx.force_allocation(place)?; + // Determine starting offset and size. + let (_prov, start_offset) = mplace.ptr().into_parts(); + let (size, _align) = self + .ecx + .size_and_align_of_mplace(&mplace)? + .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); + // If there is no padding at all, we can skip the rest: check for + // a single data range covering the entire value. + if data_bytes.0 == &[(start_offset, size)] { + return Ok(()); + } + // Get a handle for the allocation. Do this only once, to avoid looking up the same + // allocation over and over again. (Though to be fair, iterating the value already does + // exactly that.) + let Some(mut alloc) = self.ecx.get_ptr_alloc_mut(mplace.ptr(), size)? else { + // A ZST, no padding to clear. + return Ok(()); + }; + // Add a "finalizer" data range at the end, so that the iteration below finds all gaps + // between ranges. + data_bytes.0.push((start_offset + size, Size::ZERO)); + // Iterate, and reset gaps. + let mut padding_cleared_until = start_offset; + for &(offset, size) in data_bytes.0.iter() { + assert!( + offset >= padding_cleared_until, + "reset_padding on {}: previous field ended at offset {}, next field starts at {} (and has a size of {} bytes)", + mplace.layout.ty, + (padding_cleared_until - start_offset).bytes(), + (offset - start_offset).bytes(), + size.bytes(), + ); + if offset > padding_cleared_until { + // We found padding. Adjust the range to be relative to `alloc`, and make it uninit. + let padding_start = padding_cleared_until - start_offset; + let padding_size = offset - padding_cleared_until; + let range = alloc_range(padding_start, padding_size); + trace!("reset_padding on {}: resetting padding range {range:?}", mplace.layout.ty); + alloc.write_uninit(range)?; + } + padding_cleared_until = offset + size; + } + assert!(padding_cleared_until == start_offset + size); + Ok(()) + } + + /// Computes the data range of this union type: + /// which bytes are inside a field (i.e., not padding.) + fn union_data_range<'e>( + ecx: &'e mut InterpCx<'tcx, M>, + layout: TyAndLayout<'tcx>, + ) -> Cow<'e, RangeSet> { + assert!(layout.ty.is_union()); + assert!(layout.abi.is_sized(), "there are no unsized unions"); + let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env); + return M::cached_union_data_range(ecx, layout.ty, || { + let mut out = RangeSet(Vec::new()); + union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out); + out + }); + + /// Helper for recursive traversal: add data ranges of the given type to `out`. + fn union_data_range_uncached<'tcx>( + cx: &LayoutCx<'tcx>, + layout: TyAndLayout<'tcx>, + base_offset: Size, + out: &mut RangeSet, + ) { + // If this is a ZST, we don't contain any data. In particular, this helps us to quickly + // skip over huge arrays of ZST. + if layout.is_zst() { + return; + } + // Just recursively add all the fields of everything to the output. + match &layout.fields { + FieldsShape::Primitive => { + out.add_range(base_offset, layout.size); + } + &FieldsShape::Union(fields) => { + // Currently, all fields start at offset 0 (relative to `base_offset`). + for field in 0..fields.get() { + let field = layout.field(cx, field); + union_data_range_uncached(cx, field, base_offset, out); + } + } + &FieldsShape::Array { stride, count } => { + let elem = layout.field(cx, 0); + + // Fast-path for large arrays of simple types that do not contain any padding. + if elem.abi.is_scalar() { + out.add_range(base_offset, elem.size * count); + } else { + for idx in 0..count { + // This repeats the same computation for every array element... but the alternative + // is to allocate temporary storage for a dedicated `out` set for the array element, + // and replicating that N times. Is that better? + union_data_range_uncached(cx, elem, base_offset + idx * stride, out); + } + } + } + FieldsShape::Arbitrary { offsets, .. } => { + for (field, &offset) in offsets.iter_enumerated() { + let field = layout.field(cx, field.as_usize()); + union_data_range_uncached(cx, field, base_offset + offset, out); + } + } + } + // Don't forget potential other variants. + match &layout.variants { + Variants::Single { .. } => { + // Fully handled above. + } + Variants::Multiple { variants, .. } => { + for variant in variants.indices() { + let variant = layout.for_variant(cx, variant); + union_data_range_uncached(cx, variant, base_offset, out); + } + } } } - false } } @@ -774,7 +1058,7 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) } impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, 'tcx, M> { - type V = OpTy<'tcx, M::Provenance>; + type V = PlaceTy<'tcx, M::Provenance>; #[inline(always)] fn ecx(&self) -> &InterpCx<'tcx, M> { @@ -783,11 +1067,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, fn read_discriminant( &mut self, - op: &OpTy<'tcx, M::Provenance>, + val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, VariantIdx> { self.with_elem(PathElem::EnumTag, move |this| { Ok(try_validation!( - this.ecx.read_discriminant(op), + this.ecx.read_discriminant(val), this.path, Ub(InvalidTag(val)) => InvalidEnumTag { value: format!("{val:x}"), @@ -802,44 +1086,54 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, #[inline] fn visit_field( &mut self, - old_op: &OpTy<'tcx, M::Provenance>, + old_val: &PlaceTy<'tcx, M::Provenance>, field: usize, - new_op: &OpTy<'tcx, M::Provenance>, + new_val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - let elem = self.aggregate_field_path_elem(old_op.layout, field); - self.with_elem(elem, move |this| this.visit_value(new_op)) + let elem = self.aggregate_field_path_elem(old_val.layout, field); + self.with_elem(elem, move |this| this.visit_value(new_val)) } #[inline] fn visit_variant( &mut self, - old_op: &OpTy<'tcx, M::Provenance>, + old_val: &PlaceTy<'tcx, M::Provenance>, variant_id: VariantIdx, - new_op: &OpTy<'tcx, M::Provenance>, + new_val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - let name = match old_op.layout.ty.kind() { + let name = match old_val.layout.ty.kind() { ty::Adt(adt, _) => PathElem::Variant(adt.variant(variant_id).name), // Coroutines also have variants ty::Coroutine(..) => PathElem::CoroutineState(variant_id), - _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty), + _ => bug!("Unexpected type with variant: {:?}", old_val.layout.ty), }; - self.with_elem(name, move |this| this.visit_value(new_op)) + self.with_elem(name, move |this| this.visit_value(new_val)) } #[inline(always)] fn visit_union( &mut self, - op: &OpTy<'tcx, M::Provenance>, + val: &PlaceTy<'tcx, M::Provenance>, _fields: NonZero, ) -> InterpResult<'tcx> { // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory. if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !op.layout.is_zst() && !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { - if !self.in_mutable_memory(op) { + if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { + if !self.in_mutable_memory(val) { throw_validation_failure!(self.path, UnsafeCellInImmutable); } } } + if self.reset_provenance_and_padding + && let Some(data_bytes) = self.data_bytes.as_mut() + { + let base_offset = Self::data_range_offset(self.ecx, val); + // Determine and add data range for this union. + let union_data_range = Self::union_data_range(self.ecx, val.layout); + for &(offset, size) in union_data_range.0.iter() { + data_bytes.add_range(base_offset + offset, size); + } + } Ok(()) } @@ -847,39 +1141,41 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, fn visit_box( &mut self, _box_ty: Ty<'tcx>, - op: &OpTy<'tcx, M::Provenance>, + val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - self.check_safe_pointer(op, PointerKind::Box)?; + self.check_safe_pointer(val, PointerKind::Box)?; Ok(()) } #[inline] - fn visit_value(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { - trace!("visit_value: {:?}, {:?}", *op, op.layout); + fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + trace!("visit_value: {:?}, {:?}", *val, val.layout); // Check primitive types -- the leaves of our recursive descent. + // This is called even for enum discriminants (which are "fields" of their enum), + // so for integer-typed discriminants the provenance reset will happen here. // We assume that the Scalar validity range does not restrict these values // any further than `try_visit_primitive` does! - if self.try_visit_primitive(op)? { + if self.try_visit_primitive(val)? { return Ok(()); } // Special check preventing `UnsafeCell` in the inner part of constants if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !op.layout.is_zst() - && let Some(def) = op.layout.ty.ty_adt_def() + if !val.layout.is_zst() + && let Some(def) = val.layout.ty.ty_adt_def() && def.is_unsafe_cell() { - if !self.in_mutable_memory(op) { + if !self.in_mutable_memory(val) { throw_validation_failure!(self.path, UnsafeCellInImmutable); } } } // Recursively walk the value at its type. Apply optimizations for some large types. - match op.layout.ty.kind() { + match val.layout.ty.kind() { ty::Str => { - let mplace = op.assert_mem_place(); // strings are unsized and hence never immediate + let mplace = val.assert_mem_place(); // strings are unsized and hence never immediate let len = mplace.len(self.ecx)?; try_validation!( self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len)), @@ -889,11 +1185,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, ); } ty::Array(tys, ..) | ty::Slice(tys) - // This optimization applies for types that can hold arbitrary bytes (such as - // integer and floating point types) or for structs or tuples with no fields. - // FIXME(wesleywiser) This logic could be extended further to arbitrary structs - // or tuples made up of integer/floating point types or inhabited ZSTs with no - // padding. + // This optimization applies for types that can hold arbitrary non-provenance bytes (such as + // integer and floating point types). + // FIXME(wesleywiser) This logic could be extended further to arbitrary structs or + // tuples made up of integer/floating point types or inhabited ZSTs with no padding. if matches!(tys.kind(), ty::Int(..) | ty::Uint(..) | ty::Float(..)) => { @@ -901,18 +1196,19 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // Optimized handling for arrays of integer/float type. // This is the length of the array/slice. - let len = op.len(self.ecx)?; + let len = val.len(self.ecx)?; // This is the element type size. let layout = self.ecx.layout_of(*tys)?; // This is the size in bytes of the whole array. (This checks for overflow.) let size = layout.size * len; // If the size is 0, there is nothing to check. - // (`size` can only be 0 of `len` is 0, and empty arrays are always valid.) + // (`size` can only be 0 if `len` is 0, and empty arrays are always valid.) if size == Size::ZERO { return Ok(()); } - // Now that we definitely have a non-ZST array, we know it lives in memory. - let mplace = match op.as_mplace_or_imm() { + // Now that we definitely have a non-ZST array, we know it lives in memory -- except it may + // be an uninitialized local variable, those are also "immediate". + let mplace = match val.to_op(self.ecx)?.as_mplace_or_imm() { Left(mplace) => mplace, Right(imm) => match *imm { Immediate::Uninit => @@ -958,25 +1254,35 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, } } } + + // Don't forget that these are all non-pointer types, and thus do not preserve + // provenance. + if self.reset_provenance_and_padding { + // We can't share this with above as above, we might be looking at read-only memory. + let mut alloc = self.ecx.get_ptr_alloc_mut(mplace.ptr(), size)?.expect("we already excluded size 0"); + alloc.clear_provenance()?; + // Also, mark this as containing data, not padding. + self.add_data_range(mplace.ptr(), size); + } } // Fast path for arrays and slices of ZSTs. We only need to check a single ZST element // of an array and not all of them, because there's only a single value of a specific // ZST type, so either validation fails for all elements or none. ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(*tys)?.is_zst() => { // Validate just the first element (if any). - if op.len(self.ecx)? > 0 { - self.visit_field(op, 0, &self.ecx.project_index(op, 0)?)?; + if val.len(self.ecx)? > 0 { + self.visit_field(val, 0, &self.ecx.project_index(val, 0)?)?; } } _ => { // default handler try_validation!( - self.walk_value(op), + self.walk_value(val), self.path, // It's not great to catch errors here, since we can't give a very good path, // but it's better than ICEing. - Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => { - InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait } + Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => { + InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type: *expected_dyn_type } }, ); } @@ -992,15 +1298,15 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // FIXME: We could avoid some redundant checks here. For newtypes wrapping // scalars, we do the same check on every "level" (e.g., first we check // MyNewtype and then the scalar in there). - match op.layout.abi { + match val.layout.abi { Abi::Uninhabited => { - let ty = op.layout.ty; + let ty = val.layout.ty; throw_validation_failure!(self.path, UninhabitedVal { ty }); } Abi::Scalar(scalar_layout) => { if !scalar_layout.is_uninit_valid() { // There is something to check here. - let scalar = self.read_scalar(op, ExpectedKind::InitScalar)?; + let scalar = self.read_scalar(val, ExpectedKind::InitScalar)?; self.visit_scalar(scalar, scalar_layout)?; } } @@ -1010,7 +1316,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // the other must be init. if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() { let (a, b) = - self.read_immediate(op, ExpectedKind::InitScalar)?.to_scalar_pair(); + self.read_immediate(val, ExpectedKind::InitScalar)?.to_scalar_pair(); self.visit_scalar(a, a_layout)?; self.visit_scalar(b, b_layout)?; } @@ -1031,19 +1337,34 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn validate_operand_internal( - &self, - op: &OpTy<'tcx, M::Provenance>, + &mut self, + val: &PlaceTy<'tcx, M::Provenance>, path: Vec, ref_tracking: Option<&mut RefTracking, Vec>>, ctfe_mode: Option, + reset_provenance_and_padding: bool, ) -> InterpResult<'tcx> { - trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); + trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty); - // Construct a visitor - let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self }; - - // Run it. - match self.run_for_validation(|| visitor.visit_value(op)) { + // Run the visitor. + match self.run_for_validation(|ecx| { + let reset_padding = reset_provenance_and_padding && { + // Check if `val` is actually stored in memory. If not, padding is not even + // represented and we need not reset it. + ecx.place_to_op(val)?.as_mplace_or_imm().is_left() + }; + let mut v = ValidityVisitor { + path, + ref_tracking, + ctfe_mode, + ecx, + reset_provenance_and_padding, + data_bytes: reset_padding.then_some(RangeSet(Vec::new())), + }; + v.visit_value(val)?; + v.reset_padding(val)?; + InterpResult::Ok(()) + }) { Ok(()) => Ok(()), // Pass through validation failures and "invalid program" issues. Err(err) @@ -1079,13 +1400,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// - no `UnsafeCell` or non-ZST `&mut`. #[inline(always)] pub(crate) fn const_validate_operand( - &self, - op: &OpTy<'tcx, M::Provenance>, + &mut self, + val: &PlaceTy<'tcx, M::Provenance>, path: Vec, ref_tracking: &mut RefTracking, Vec>, ctfe_mode: CtfeValidationMode, ) -> InterpResult<'tcx> { - self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode)) + self.validate_operand_internal( + val, + path, + Some(ref_tracking), + Some(ctfe_mode), + /*reset_provenance*/ false, + ) } /// This function checks the data at `op` to be runtime-valid. @@ -1093,21 +1420,41 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] pub fn validate_operand( - &self, - op: &OpTy<'tcx, M::Provenance>, + &mut self, + val: &PlaceTy<'tcx, M::Provenance>, recursive: bool, + reset_provenance_and_padding: bool, ) -> InterpResult<'tcx> { // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's // still correct to not use `ctfe_mode`: that mode is for validation of the final constant // value, it rules out things like `UnsafeCell` in awkward places. if !recursive { - return self.validate_operand_internal(op, vec![], None, None); + return self.validate_operand_internal( + val, + vec![], + None, + None, + reset_provenance_and_padding, + ); } // Do a recursive check. let mut ref_tracking = RefTracking::empty(); - self.validate_operand_internal(op, vec![], Some(&mut ref_tracking), None)?; + self.validate_operand_internal( + val, + vec![], + Some(&mut ref_tracking), + None, + reset_provenance_and_padding, + )?; while let Some((mplace, path)) = ref_tracking.todo.pop() { - self.validate_operand_internal(&mplace.into(), path, Some(&mut ref_tracking), None)?; + // Things behind reference do *not* have the provenance reset. + self.validate_operand_internal( + &mplace.into(), + path, + Some(&mut ref_tracking), + None, + /*reset_provenance_and_padding*/ false, + )?; } Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index b02f12e3c7f0b..d004a3f08929f 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -5,11 +5,12 @@ use std::num::NonZero; use rustc_index::IndexVec; use rustc_middle::mir::interpret::InterpResult; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; use rustc_target::abi::{FieldIdx, FieldsShape, VariantIdx, Variants}; use tracing::trace; -use super::{throw_inval, InterpCx, MPlaceTy, Machine, Projectable}; +use super::{InterpCx, MPlaceTy, Machine, Projectable, throw_inval}; /// How to traverse a value and what to do when we are at the leaves. pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { @@ -82,6 +83,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { self.visit_value(new_val) } + /// Traversal logic; should not be overloaded. fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx> { let ty = v.layout().ty; trace!("walk_value: type: {ty}"); @@ -104,6 +106,17 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // DynStar types. Very different from a dyn type (but strangely part of the // same variant in `TyKind`): These are pairs where the 2nd component is the // vtable, and the first component is the data (which must be ptr-sized). + + // First make sure the vtable can be read at its type. + // The type of this vtable is fake, it claims to be a reference to some actual memory but that isn't true. + // So we transmute it to a raw pointer. + let raw_ptr_ty = Ty::new_mut_ptr(*self.ecx().tcx, self.ecx().tcx.types.unit); + let raw_ptr_ty = self.ecx().layout_of(raw_ptr_ty)?; + let vtable_field = + self.ecx().project_field(v, 1)?.transmute(raw_ptr_ty, self.ecx())?; + self.visit_field(v, 1, &vtable_field)?; + + // Then unpack the first field, and continue. let data = self.ecx().unpack_dyn_star(v, data)?; return self.visit_field(v, 0, &data); } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index d825a47bfdf5d..cbe8a043fba00 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,6 +1,8 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(not(bootstrap), feature(unqualified_local_imports))] +#![cfg_attr(not(bootstrap), warn(unqualified_local_imports))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -14,6 +16,7 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod check_consts; @@ -24,10 +27,11 @@ pub mod util; use std::sync::atomic::AtomicBool; -pub use errors::ReportErrorExt; use rustc_middle::ty; use rustc_middle::util::Providers; +pub use self::errors::ReportErrorExt; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index eb185bee5c07b..7f4c36835e449 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -6,7 +6,7 @@ use rustc_middle::{bug, mir}; use rustc_span::symbol::Symbol; use tracing::trace; -use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeInterpCx}; +use crate::const_eval::{CanAccessMutGlobal, CompileTimeInterpCx, mk_eval_cx_to_read_const_val}; use crate::interpret::*; /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index cbd1fdeea2aa3..19393188c9adf 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -1,10 +1,12 @@ use rustc_middle::bug; -use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement}; +use rustc_middle::ty::layout::{ + HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement, +}; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine}; -use crate::interpret::{InterpCx, MemoryKind, OpTy}; +use crate::interpret::{InterpCx, MemoryKind}; /// Determines if this type permits "raw" initialization by just transmuting some memory into an /// instance of `T`. @@ -30,24 +32,24 @@ pub fn check_validity_requirement<'tcx>( return Ok(!layout.abi.is_uninhabited()); } - let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env }; + let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env); if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks { - might_permit_raw_init_strict(layout, &layout_cx, kind) + check_validity_requirement_strict(layout, &layout_cx, kind) } else { - might_permit_raw_init_lax(layout, &layout_cx, kind) + check_validity_requirement_lax(layout, &layout_cx, kind) } } -/// Implements the 'strict' version of the `might_permit_raw_init` checks; see that function for -/// details. -fn might_permit_raw_init_strict<'tcx>( +/// Implements the 'strict' version of the [`check_validity_requirement`] checks; see that function +/// for details. +fn check_validity_requirement_strict<'tcx>( ty: TyAndLayout<'tcx>, - cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, + cx: &LayoutCx<'tcx>, kind: ValidityRequirement, ) -> Result> { let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error); - let mut cx = InterpCx::new(cx.tcx, rustc_span::DUMMY_SP, cx.param_env, machine); + let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.param_env, machine); let allocated = cx .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) @@ -61,20 +63,26 @@ fn might_permit_raw_init_strict<'tcx>( .expect("failed to write bytes for zero valid check"); } - let ot: OpTy<'_, _> = allocated.into(); - // Assume that if it failed, it's a validation failure. // This does *not* actually check that references are dereferenceable, but since all types that // require dereferenceability also require non-null, we don't actually get any false negatives // due to this. - Ok(cx.validate_operand(&ot, /*recursive*/ false).is_ok()) + // The value we are validating is temporary and discarded at the end of this function, so + // there is no point in reseting provenance and padding. + Ok(cx + .validate_operand( + &allocated.into(), + /*recursive*/ false, + /*reset_provenance_and_padding*/ false, + ) + .is_ok()) } -/// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for -/// details. -fn might_permit_raw_init_lax<'tcx>( +/// Implements the 'lax' (default) version of the [`check_validity_requirement`] checks; see that +/// function for details. +fn check_validity_requirement_lax<'tcx>( this: TyAndLayout<'tcx>, - cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, + cx: &LayoutCx<'tcx>, init_kind: ValidityRequirement, ) -> Result> { let scalar_allows_raw_init = move |s: Scalar| -> bool { @@ -137,7 +145,7 @@ fn might_permit_raw_init_lax<'tcx>( } FieldsShape::Arbitrary { offsets, .. } => { for idx in 0..offsets.len() { - if !might_permit_raw_init_lax(this.field(cx, idx), cx, init_kind)? { + if !check_validity_requirement_lax(this.field(cx, idx), cx, init_kind)? { // We found a field that is unhappy with this kind of initialization. return Ok(false); } diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs index 1c2321623e491..0c3d7613d4f1f 100644 --- a/compiler/rustc_data_structures/src/base_n.rs +++ b/compiler/rustc_data_structures/src/base_n.rs @@ -42,7 +42,7 @@ impl fmt::Display for BaseNString { } // This trait just lets us reserve the exact right amount of space when doing fixed-length -// case-insensitve encoding. Add any impls you need. +// case-insensitive encoding. Add any impls you need. pub trait ToBaseN: Into { fn encoded_len(base: usize) -> usize; diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index efc56dc93373b..16c66824c5ba1 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -3,7 +3,7 @@ use std::hash::{Hash, Hasher}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use crate::stable_hasher::{ - impl_stable_traits_for_trivial_type, FromStableHash, Hash64, StableHasherHash, + FromStableHash, Hash64, StableHasherHash, impl_stable_traits_for_trivial_type, }; #[cfg(test)] diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs index 0d76df27a0a39..9739e501272c4 100644 --- a/compiler/rustc_data_structures/src/flock/windows.rs +++ b/compiler/rustc_data_structures/src/flock/windows.rs @@ -6,8 +6,8 @@ use std::path::Path; use tracing::debug; use windows::Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE}; use windows::Win32::Storage::FileSystem::{ - LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK, - LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS, + FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCK_FILE_FLAGS, LOCKFILE_EXCLUSIVE_LOCK, + LOCKFILE_FAIL_IMMEDIATELY, LockFileEx, }; use windows::Win32::System::IO::OVERLAPPED; diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs index 6c078ca7c6ee4..ef82193a4b9df 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs @@ -15,10 +15,17 @@ fn diamond() { #[test] fn paper() { // example from the paper: - let graph = TestGraph::new( - 6, - &[(6, 5), (6, 4), (5, 1), (4, 2), (4, 3), (1, 2), (2, 3), (3, 2), (2, 1)], - ); + let graph = TestGraph::new(6, &[ + (6, 5), + (6, 4), + (5, 1), + (4, 2), + (4, 3), + (1, 2), + (2, 3), + (3, 2), + (2, 1), + ]); let d = dominators(&graph); assert_eq!(d.immediate_dominator(0), None); // <-- note that 0 is not in graph @@ -33,10 +40,19 @@ fn paper() { #[test] fn paper_slt() { // example from the paper: - let graph = TestGraph::new( - 1, - &[(1, 2), (1, 3), (2, 3), (2, 7), (3, 4), (3, 6), (4, 5), (5, 4), (6, 7), (7, 8), (8, 5)], - ); + let graph = TestGraph::new(1, &[ + (1, 2), + (1, 3), + (2, 3), + (2, 7), + (3, 4), + (3, 6), + (4, 5), + (5, 4), + (6, 7), + (7, 8), + (8, 5), + ]); dominators(&graph); } @@ -53,24 +69,21 @@ fn immediate_dominator() { #[test] fn transitive_dominator() { - let graph = TestGraph::new( - 0, - &[ - // First tree branch. - (0, 1), - (1, 2), - (2, 3), - (3, 4), - // Second tree branch. - (1, 5), - (5, 6), - // Third tree branch. - (0, 7), - // These links make 0 the dominator for 2 and 3. - (7, 2), - (5, 3), - ], - ); + let graph = TestGraph::new(0, &[ + // First tree branch. + (0, 1), + (1, 2), + (2, 3), + (3, 4), + // Second tree branch. + (1, 5), + (5, 6), + // Third tree branch. + (0, 7), + // These links make 0 the dominator for 2 and 3. + (7, 2), + (5, 3), + ]); let d = dominators(&graph); assert_eq!(d.immediate_dominator(2), Some(0)); diff --git a/compiler/rustc_data_structures/src/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/implementation/tests.rs index 32a6d9ec881a9..7a240f4e58bcc 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/tests.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/tests.rs @@ -110,13 +110,10 @@ fn each_adjacent_from_a() { #[test] fn each_adjacent_from_b() { let graph = create_graph(); - test_adjacent_edges( - &graph, - NodeIndex(1), - "B", - &[("FB", "F"), ("AB", "A")], - &[("BD", "D"), ("BC", "C")], - ); + test_adjacent_edges(&graph, NodeIndex(1), "B", &[("FB", "F"), ("AB", "A")], &[ + ("BD", "D"), + ("BC", "C"), + ]); } #[test] diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 2a457ffb70b08..06fedef00fc3f 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -477,7 +477,7 @@ where // will know when we hit the state where previous_node == node. loop { // Back at the beginning, we can return. Note that we return the root state. - // This is becuse for components being explored, we would otherwise get a + // This is because for components being explored, we would otherwise get a // `node_state[n] = InCycleWith{ parent: n }` and that's wrong. if previous_node == node { return root_state; diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 373f87bfdbcfa..7c876c82af293 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -326,49 +326,46 @@ fn test_bug_max_leak_minimised() { #[test] fn test_bug_max_leak() { - let graph = TestGraph::new( - 8, - &[ - (0, 0), - (0, 18), - (0, 19), - (0, 1), - (0, 2), - (0, 7), - (0, 8), - (0, 23), - (18, 0), - (18, 12), - (19, 0), - (19, 25), - (12, 18), - (12, 3), - (12, 5), - (3, 12), - (3, 21), - (3, 22), - (5, 13), - (21, 3), - (22, 3), - (13, 5), - (13, 4), - (4, 13), - (4, 0), - (2, 11), - (7, 6), - (6, 20), - (20, 6), - (8, 17), - (17, 9), - (9, 16), - (16, 26), - (26, 15), - (15, 10), - (10, 14), - (14, 27), - (23, 24), - ], - ); + let graph = TestGraph::new(8, &[ + (0, 0), + (0, 18), + (0, 19), + (0, 1), + (0, 2), + (0, 7), + (0, 8), + (0, 23), + (18, 0), + (18, 12), + (19, 0), + (19, 25), + (12, 18), + (12, 3), + (12, 5), + (3, 12), + (3, 21), + (3, 22), + (5, 13), + (21, 3), + (22, 3), + (13, 5), + (13, 4), + (4, 13), + (4, 0), + (2, 11), + (7, 6), + (6, 20), + (20, 6), + (8, 17), + (17, 9), + (9, 16), + (16, 26), + (26, 15), + (15, 10), + (10, 14), + (14, 27), + (23, 24), + ]); let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w { 22 => MaxReached(1), 24 => MaxReached(2), diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs index f98c8de1eb097..8f4639fc2e666 100644 --- a/compiler/rustc_data_structures/src/hashes.rs +++ b/compiler/rustc_data_structures/src/hashes.rs @@ -3,11 +3,11 @@ //! or 16 bytes of the hash. //! //! The types in this module represent 64-bit or 128-bit hashes produced by a `StableHasher`. -//! `Hash64` and `Hash128` expose some utilty functions to encourage users to not extract the inner +//! `Hash64` and `Hash128` expose some utility functions to encourage users to not extract the inner //! hash value as an integer type and accidentally apply varint encoding to it. //! //! In contrast with `Fingerprint`, users of these types cannot and should not attempt to construct -//! and decompose these types into constitutent pieces. The point of these types is only to +//! and decompose these types into constituent pieces. The point of these types is only to //! connect the fact that they can only be produced by a `StableHasher` to their //! `Encode`/`Decode` impls. diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index a35f5b1f17db4..f225684d99ff4 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -23,6 +23,7 @@ #![feature(cfg_match)] #![feature(core_intrinsics)] #![feature(extend_one)] +#![feature(file_buffered)] #![feature(hash_raw_entry)] #![feature(macro_metavar_expr)] #![feature(map_try_insert)] diff --git a/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs index 60cde9a52b411..65a24366db837 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs @@ -1,6 +1,5 @@ use std::env::var_os; use std::fs::File; -use std::io::BufWriter; use std::path::Path; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -33,7 +32,7 @@ impl ObligationForest { let file_path = dir.as_ref().join(format!("{counter:010}_{description}.gv")); - let mut gv_file = BufWriter::new(File::create(file_path).unwrap()); + let mut gv_file = File::create_buffered(file_path).unwrap(); dot::render(&self, &mut gv_file).unwrap(); } diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs index a58c6ee1bccb6..8391e98ba8b07 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs @@ -347,10 +347,10 @@ fn diamond() { )); assert_eq!(d_count, 1); assert_eq!(ok.len(), 0); - assert_eq!( - err, - vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }] - ); + assert_eq!(err, vec![super::Error { + error: "operation failed", + backtrace: vec!["D'", "A'.1", "A'"] + }]); let errors = forest.to_errors(()); assert_eq!(errors.len(), 0); diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs index 324b8ecf2d393..e9ef7ea5afc74 100644 --- a/compiler/rustc_data_structures/src/owned_slice/tests.rs +++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs @@ -1,9 +1,9 @@ use std::ops::Deref; -use std::sync::atomic::{self, AtomicBool}; use std::sync::Arc; +use std::sync::atomic::{self, AtomicBool}; use crate::defer; -use crate::owned_slice::{slice_owned, try_slice_owned, OwnedSlice}; +use crate::owned_slice::{OwnedSlice, slice_owned, try_slice_owned}; #[test] fn smoke() { diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 03aa1d8f67862..d0b6fe2bc6fd0 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -8,7 +8,7 @@ use either::Either; use crate::fx::{FxHashMap, FxHasher}; #[cfg(parallel_compiler)] -use crate::sync::{is_dyn_thread_safe, CacheAligned}; +use crate::sync::{CacheAligned, is_dyn_thread_safe}; use crate::sync::{Lock, LockGuard, Mode}; // 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700, diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 9673f94d7a433..0872bd2c9acc9 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -14,7 +14,7 @@ pub use rustc_stable_hash::{ FromStableHash, SipHasher128Hash as StableHasherHash, StableSipHasher128 as StableHasher, }; -pub use crate::hashes::{Hash128, Hash64}; +pub use crate::hashes::{Hash64, Hash128}; /// Something that implements `HashStable` can be hashed in a way that is /// stable across multiple compilation sessions. diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index 0f2c0eee27d2f..aaa95f6b7f19e 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -57,6 +57,7 @@ impl Steal { /// /// This should not be used within rustc as it leaks information not tracked /// by the query system, breaking incremental compilation. + #[cfg_attr(not(bootstrap), rustc_lint_untracked_query_information)] pub fn is_stolen(&self) -> bool { self.value.borrow().is_none() } diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs index 7cf942685e3e1..012ee7f900eaa 100644 --- a/compiler/rustc_data_structures/src/sync/lock.rs +++ b/compiler/rustc_data_structures/src/sync/lock.rs @@ -25,8 +25,8 @@ mod maybe_sync { use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; - use parking_lot::lock_api::RawMutex as _; use parking_lot::RawMutex; + use parking_lot::lock_api::RawMutex as _; use super::Mode; use crate::sync::mode; diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 2b89431c2ed79..c7df19842d6d5 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -4,7 +4,7 @@ #![allow(dead_code)] use std::any::Any; -use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; +use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; #[cfg(not(parallel_compiler))] pub use disabled::*; @@ -12,8 +12,8 @@ pub use disabled::*; pub use enabled::*; use parking_lot::Mutex; -use crate::sync::IntoDynSyncSend; use crate::FatalErrorMarker; +use crate::sync::IntoDynSyncSend; /// A guard used to hold panics that occur during a parallel section to later by unwound. /// This is used for the parallel compiler to prevent fatal errors from non-deterministically @@ -102,7 +102,7 @@ mod disabled { #[cfg(parallel_compiler)] mod enabled { - use crate::sync::{mode, parallel_guard, DynSend, DynSync, FromDyn}; + use crate::sync::{DynSend, DynSync, FromDyn, mode, parallel_guard}; /// Runs a list of blocks in parallel. The first block is executed immediately on /// the current thread. Use that for the longest running block. diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs index 4950481d311f0..b6efcada10b77 100644 --- a/compiler/rustc_data_structures/src/sync/worker_local.rs +++ b/compiler/rustc_data_structures/src/sync/worker_local.rs @@ -19,7 +19,7 @@ impl RegistryId { /// index within the registry. This panics if the current thread is not associated with this /// registry. /// - /// Note that there's a race possible where the identifer in `THREAD_DATA` could be reused + /// Note that there's a race possible where the identifier in `THREAD_DATA` could be reused /// so this can succeed from a different registry. #[cfg(parallel_compiler)] fn verify(self) -> usize { @@ -50,7 +50,7 @@ struct ThreadData { } thread_local! { - /// A thread local which contains the identifer of `REGISTRY` but allows for faster access. + /// A thread local which contains the identifier of `REGISTRY` but allows for faster access. /// It also holds the index of the current thread. static THREAD_DATA: ThreadData = const { ThreadData { registry_id: Cell::new(RegistryId(ptr::null())), @@ -66,7 +66,7 @@ impl Registry { /// Gets the registry associated with the current thread. Panics if there's no such registry. pub fn current() -> Self { - REGISTRY.with(|registry| registry.get().cloned().expect("No assocated registry")) + REGISTRY.with(|registry| registry.get().cloned().expect("No associated registry")) } /// Registers the current thread with the registry so worker locals can be used on it. @@ -92,7 +92,7 @@ impl Registry { } } - /// Gets the identifer of this registry. + /// Gets the identifier of this registry. fn id(&self) -> RegistryId { RegistryId(&*self.0) } diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs index 490d7d3ddd57c..ca052e2eac6db 100644 --- a/compiler/rustc_data_structures/src/work_queue.rs +++ b/compiler/rustc_data_structures/src/work_queue.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; -use rustc_index::bit_set::BitSet; use rustc_index::Idx; +use rustc_index::bit_set::BitSet; /// A work queue is a handy data structure for tracking work left to /// do. (For example, basic blocks left to process.) It is basically a diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 91cbffcd7072b..6d6d3f35a4b1b 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -23,6 +23,7 @@ rustc_hir_analysis = { path = "../rustc_hir_analysis" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_hir_typeck = { path = "../rustc_hir_typeck" } rustc_incremental = { path = "../rustc_incremental" } +rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_interface = { path = "../rustc_interface" } rustc_lint = { path = "../rustc_lint" } @@ -72,6 +73,10 @@ ctrlc = "3.4.4" # tidy-alphabetical-start llvm = ['rustc_interface/llvm'] max_level_info = ['rustc_log/max_level_info'] +rustc_randomized_layouts = [ + 'rustc_index/rustc_randomized_layouts', + 'rustc_middle/rustc_randomized_layouts' +] rustc_use_parallel_compiler = [ 'rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler', diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index e49ae60e890ba..76b7270d4b815 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -7,7 +7,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -#![cfg_attr(bootstrap, feature(unsafe_extern_blocks))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(decl_macro)] @@ -25,7 +24,7 @@ use std::ffi::OsString; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::{self, IsTerminal, Read, Write}; -use std::panic::{self, catch_unwind, PanicHookInfo}; +use std::panic::{self, PanicHookInfo, catch_unwind}; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -38,31 +37,30 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenErrors, CodegenResults}; use rustc_const_eval::CTRL_C_RECEIVED; use rustc_data_structures::profiling::{ - get_resident_set_size, print_time_passes_entry, TimePassesFormat, + TimePassesFormat, get_resident_set_size, print_time_passes_entry, }; use rustc_errors::emitter::stderr_destination; use rustc_errors::registry::Registry; use rustc_errors::{ - markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, + ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, markdown, }; use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, get_codegen_backend}; -use rustc_interface::{interface, passes, Linker, Queries}; +use rustc_interface::{Linker, Queries, interface, passes}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ - nightly_options, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, CG_OPTIONS, - Z_OPTIONS, + CG_OPTIONS, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, Z_OPTIONS, + nightly_options, }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::output::collect_crate_types; -use rustc_session::{config, filesearch, EarlyDiagCtxt, Session}; -use rustc_span::source_map::FileLoader; -use rustc_span::symbol::sym; +use rustc_session::{EarlyDiagCtxt, Session, config, filesearch}; use rustc_span::FileName; +use rustc_span::source_map::FileLoader; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTriple}; use time::OffsetDateTime; @@ -209,17 +207,17 @@ pub fn diagnostics_registry() -> Registry { } /// This is the primary entry point for rustc. -pub struct RunCompiler<'a, 'b> { +pub struct RunCompiler<'a> { at_args: &'a [String], - callbacks: &'b mut (dyn Callbacks + Send), + callbacks: &'a mut (dyn Callbacks + Send), file_loader: Option>, make_codegen_backend: Option Box + Send>>, using_internal_features: Arc, } -impl<'a, 'b> RunCompiler<'a, 'b> { - pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self { +impl<'a> RunCompiler<'a> { + pub fn new(at_args: &'a [String], callbacks: &'a mut (dyn Callbacks + Send)) -> Self { Self { at_args, callbacks, @@ -322,7 +320,7 @@ fn run_compiler( output_dir: odir, ice_file, file_loader, - locale_resources: DEFAULT_LOCALE_RESOURCES, + locale_resources: DEFAULT_LOCALE_RESOURCES.to_vec(), lint_caps: Default::default(), psess_created: None, hash_untracked_state: None, @@ -412,11 +410,9 @@ fn run_compiler( }); } else { let krate = queries.parse()?; - pretty::print( - sess, - pp_mode, - pretty::PrintExtra::AfterParsing { krate: &*krate.borrow() }, - ); + pretty::print(sess, pp_mode, pretty::PrintExtra::AfterParsing { + krate: &*krate.borrow(), + }); } trace!("finished pretty-printing"); return early_exit(); @@ -777,16 +773,8 @@ fn print_crate_info( .config .iter() .filter_map(|&(name, value)| { - // Note that crt-static is a specially recognized cfg - // directive that's printed out here as part of - // rust-lang/rust#37406, but in general the - // `target_feature` cfg is gated under - // rust-lang/rust#29717. For now this is just - // specifically allowing the crt-static cfg and that's - // it, this is intended to get into Cargo and then go - // through to build scripts. - if (name != sym::target_feature || value != Some(sym::crt_dash_static)) - && !sess.is_nightly_build() + // On stable, exclude unstable flags. + if !sess.is_nightly_build() && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() { return None; @@ -871,9 +859,9 @@ fn print_crate_info( use rustc_target::spec::current_apple_deployment_target; if sess.target.is_like_osx { - let (major, minor) = current_apple_deployment_target(&sess.target) - .expect("unknown Apple target OS"); - println_info!("deployment_target={}", format!("{major}.{minor}")) + let (major, minor, patch) = current_apple_deployment_target(&sess.target); + let patch = if patch != 0 { format!(".{patch}") } else { String::new() }; + println_info!("deployment_target={major}.{minor}{patch}") } else { #[allow(rustc::diagnostic_outside_of_impl)] sess.dcx().fatal("only Apple targets currently support deployment version info") @@ -1228,17 +1216,30 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option = match e { getopts::Fail::UnrecognizedOption(ref opt) => CG_OPTIONS .iter() .map(|&(name, ..)| ('C', name)) .chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name))) .find(|&(_, name)| *opt == name.replace('_', "-")) .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")), + getopts::Fail::ArgumentMissing(ref opt) => { + optgroups.iter().find(|option| option.name == opt).map(|option| { + // Print the help just for the option in question. + let mut options = getopts::Options::new(); + (option.apply)(&mut options); + // getopt requires us to pass a function for joining an iterator of + // strings, even though in this case we expect exactly one string. + options.usage_with_format(|it| { + it.fold(format!("{e}\nUsage:"), |a, b| a + "\n" + &b) + }) + }) + } _ => None, }; early_dcx.early_fatal(msg.unwrap_or_else(|| e.to_string())); diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index c973fcec0e19a..0733b8c0b98a1 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -8,11 +8,11 @@ use rustc_errors::FatalError; use rustc_middle::bug; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; use rustc_session::Session; +use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; use rustc_smir::rustc_internal::pretty::write_smir_pretty; -use rustc_span::symbol::Ident; use rustc_span::FileName; +use rustc_span::symbol::Ident; use tracing::debug; use {rustc_ast as ast, rustc_hir_pretty as pprust_hir}; @@ -222,10 +222,8 @@ impl<'tcx> PrintExtra<'tcx> { } pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { - if ppm.needs_analysis() { - if ex.tcx().analysis(()).is_err() { - FatalError.raise(); - } + if ppm.needs_analysis() && ex.tcx().analysis(()).is_err() { + FatalError.raise(); } let (src, src_name) = get_source(sess); diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs index e1f868c2522d9..d4f8199390cc5 100644 --- a/compiler/rustc_driver_impl/src/signal_handler.rs +++ b/compiler/rustc_driver_impl/src/signal_handler.rs @@ -1,7 +1,7 @@ //! Signal handler for rustc //! Primarily used to extract a backtrace from stack overflow -use std::alloc::{alloc, Layout}; +use std::alloc::{Layout, alloc}; use std::{fmt, mem, ptr}; use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE}; @@ -35,6 +35,8 @@ macro raw_errln($tokens:tt) { } /// Signal handler installed for SIGSEGV +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#[allow(static_mut_refs)] extern "C" fn print_stack_trace(_: libc::c_int) { const MAX_FRAMES: usize = 256; // Reserve data segment so we don't have to malloc in a signal handler, which might fail diff --git a/compiler/rustc_error_codes/src/error_codes/E0074.md b/compiler/rustc_error_codes/src/error_codes/E0074.md index 785d6de226d3d..71d89f5eb60a4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0074.md +++ b/compiler/rustc_error_codes/src/error_codes/E0074.md @@ -11,7 +11,7 @@ This will cause an error: #![feature(repr_simd)] #[repr(simd)] -struct Bad(T, T, T, T); +struct Bad([T; 4]); ``` This will not: @@ -20,5 +20,5 @@ This will not: #![feature(repr_simd)] #[repr(simd)] -struct Good(u32, u32, u32, u32); +struct Good([u32; 4]); ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0075.md b/compiler/rustc_error_codes/src/error_codes/E0075.md index 969c1ee71313e..b58018eafc30c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0075.md +++ b/compiler/rustc_error_codes/src/error_codes/E0075.md @@ -1,6 +1,6 @@ -A `#[simd]` attribute was applied to an empty tuple struct. +A `#[simd]` attribute was applied to an empty or multi-field struct. -Erroneous code example: +Erroneous code examples: ```compile_fail,E0075 #![feature(repr_simd)] @@ -9,9 +9,15 @@ Erroneous code example: struct Bad; // error! ``` -The `#[simd]` attribute can only be applied to non empty tuple structs, because -it doesn't make sense to try to use SIMD operations when there are no values to -operate on. +```compile_fail,E0075 +#![feature(repr_simd)] + +#[repr(simd)] +struct Bad([u32; 1], [u32; 1]); // error! +``` + +The `#[simd]` attribute can only be applied to a single-field struct, because +the one field must be the array of values in the vector. Fixed example: @@ -19,5 +25,5 @@ Fixed example: #![feature(repr_simd)] #[repr(simd)] -struct Good(u32); // ok! +struct Good([u32; 2]); // ok! ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0076.md b/compiler/rustc_error_codes/src/error_codes/E0076.md index 1da8caa9506d7..b1943de63e5d4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0076.md +++ b/compiler/rustc_error_codes/src/error_codes/E0076.md @@ -1,4 +1,4 @@ -All types in a tuple struct aren't the same when using the `#[simd]` +The type of the field in a tuple struct isn't an array when using the `#[simd]` attribute. Erroneous code example: @@ -7,12 +7,12 @@ Erroneous code example: #![feature(repr_simd)] #[repr(simd)] -struct Bad(u16, u32, u32 u32); // error! +struct Bad(u16); // error! ``` When using the `#[simd]` attribute to automatically use SIMD operations in tuple -struct, the types in the struct must all be of the same type, or the compiler -will trigger this error. +structs, if you want a single-lane vector then the field must be a 1-element +array, or the compiler will trigger this error. Fixed example: @@ -20,5 +20,5 @@ Fixed example: #![feature(repr_simd)] #[repr(simd)] -struct Good(u32, u32, u32, u32); // ok! +struct Good([u16; 1]); // ok! ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0077.md b/compiler/rustc_error_codes/src/error_codes/E0077.md index 91aa24d1f52f4..688bfd3e72795 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0077.md +++ b/compiler/rustc_error_codes/src/error_codes/E0077.md @@ -7,7 +7,7 @@ Erroneous code example: #![feature(repr_simd)] #[repr(simd)] -struct Bad(String); // error! +struct Bad([String; 2]); // error! ``` When using the `#[simd]` attribute on a tuple struct, the elements in the tuple @@ -19,5 +19,5 @@ Fixed example: #![feature(repr_simd)] #[repr(simd)] -struct Good(u32, u32, u32, u32); // ok! +struct Good([u32; 4]); // ok! ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0511.md b/compiler/rustc_error_codes/src/error_codes/E0511.md index 681f4e611c32d..45ff49bdebb29 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0511.md +++ b/compiler/rustc_error_codes/src/error_codes/E0511.md @@ -23,11 +23,11 @@ The generic type has to be a SIMD type. Example: #[repr(simd)] #[derive(Copy, Clone)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); extern "rust-intrinsic" { fn simd_add(a: T, b: T) -> T; } -unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok! +unsafe { simd_add(i32x2([0, 0]), i32x2([1, 2])); } // ok! ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0582.md b/compiler/rustc_error_codes/src/error_codes/E0582.md index b2cdb509c95c0..c4aaa17706add 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0582.md +++ b/compiler/rustc_error_codes/src/error_codes/E0582.md @@ -44,7 +44,7 @@ where ``` The latter scenario encounters this error because `Foo::Assoc<'a>` could be implemented by a type that does not use the `'a` parameter, so there is no -guarentee that `X::Assoc<'a>` actually uses `'a`. +guarantee that `X::Assoc<'a>` actually uses `'a`. To fix this we can pass a dummy parameter: ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0764.md b/compiler/rustc_error_codes/src/error_codes/E0764.md index 152627cf6545f..4d5091cd954e9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0764.md +++ b/compiler/rustc_error_codes/src/error_codes/E0764.md @@ -3,8 +3,6 @@ A mutable reference was used in a constant. Erroneous code example: ```compile_fail,E0764 -#![feature(const_mut_refs)] - fn main() { const OH_NO: &'static mut usize = &mut 1; // error! } @@ -26,8 +24,6 @@ Remember: you cannot use a function call inside a constant or static. However, you can totally use it in constant functions: ``` -#![feature(const_mut_refs)] - const fn foo(x: usize) -> usize { let mut y = 1; let z = &mut y; diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md index 9bafd52f75cf2..efbd51e89ea3a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0775.md +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -1,13 +1,14 @@ +#### Note: this error code is no longer emitted by the compiler. + `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension. Erroneous code example: -```compile_fail,E0775 +```ignore (no longer emitted) #![feature(cmse_nonsecure_entry)] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function() {} +pub extern "C-cmse-nonsecure-entry" fn entry_function() {} ``` To fix this error, compile your code for a Rust target that supports the diff --git a/compiler/rustc_error_codes/src/error_codes/E0776.md b/compiler/rustc_error_codes/src/error_codes/E0776.md index d65beebe07c61..e46d498d1c262 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0776.md +++ b/compiler/rustc_error_codes/src/error_codes/E0776.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + `#[cmse_nonsecure_entry]` functions require a C ABI Erroneous code example: -```compile_fail,E0776 +```ignore (no longer emitted) #![feature(cmse_nonsecure_entry)] #[no_mangle] diff --git a/compiler/rustc_error_codes/src/error_codes/E0796.md b/compiler/rustc_error_codes/src/error_codes/E0796.md index 7ac429e521581..ced163e98f745 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0796.md +++ b/compiler/rustc_error_codes/src/error_codes/E0796.md @@ -1,14 +1,14 @@ +#### Note: this error code is no longer emitted by the compiler. + You have created a reference to a mutable static. Erroneous code example: -```compile_fail,edition2024,E0796 +``` static mut X: i32 = 23; - fn work() { let _val = unsafe { X }; } - let x_ref = unsafe { &mut X }; work(); // The next line has Undefined Behavior! diff --git a/compiler/rustc_error_codes/src/error_codes/E0799.md b/compiler/rustc_error_codes/src/error_codes/E0799.md new file mode 100644 index 0000000000000..38ebc84060497 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0799.md @@ -0,0 +1,19 @@ +Something other than a type or const parameter has been used when one was +expected. + +Erroneous code example: + +```compile_fail,E0799 +fn bad1() -> impl Sized + use
{} + +fn bad2(x: ()) -> impl Sized + use {} + +fn main() {} +``` + +In the given examples, for `bad1`, the name `main` corresponds to a function +rather than a type or const parameter. In `bad2`, the name `x` corresponds to +a function argument rather than a type or const parameter. + +Only type and const parameters, including `Self`, may be captured by +`use<...>` precise capturing bounds. diff --git a/compiler/rustc_error_codes/src/error_codes/E0800.md b/compiler/rustc_error_codes/src/error_codes/E0800.md new file mode 100644 index 0000000000000..3e08cd499b7e6 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0800.md @@ -0,0 +1,11 @@ +A type or const parameter of the given name is not in scope. + +Erroneous code examples: + +```compile_fail,E0800 +fn missing() -> impl Sized + use {} +``` + +To fix this error, please verify you didn't misspell the type or const +parameter, or double-check if you forgot to declare the parameter in +the list of generics. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 150f99a3ee743..8631de65ec820 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -538,6 +538,8 @@ E0795: 0795, E0796: 0796, E0797: 0797, E0798: 0798, +E0799: 0799, +E0800: 0800, ); ) } @@ -679,3 +681,5 @@ E0798: 0798, // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. // E0744, // merged into E0728 +// E0776, // Removed; cmse_nonsecure_entry is now `C-cmse-nonsecure-entry` +// E0796, // unused error code. We use `static_mut_refs` lint instead. diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index e84d7be45d7a0..2ede7d805fa40 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -16,20 +16,20 @@ use std::path::{Path, PathBuf}; use std::sync::LazyLock as Lazy; use std::{fmt, fs, io}; -pub use fluent_bundle::types::FluentType; use fluent_bundle::FluentResource; +pub use fluent_bundle::types::FluentType; pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue}; use fluent_syntax::parser::ParserError; use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; -#[cfg(parallel_compiler)] -use intl_memoizer::concurrent::IntlLangMemoizer; #[cfg(not(parallel_compiler))] use intl_memoizer::IntlLangMemoizer; +#[cfg(parallel_compiler)] +use intl_memoizer::concurrent::IntlLangMemoizer; use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; use tracing::{instrument, trace}; -pub use unic_langid::{langid, LanguageIdentifier}; +pub use unic_langid::{LanguageIdentifier, langid}; pub type FluentBundle = IntoDynSyncSend>; diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index d71ae9d210d5d..f468fbf4497e0 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -8,12 +8,12 @@ use annotate_snippets::{Renderer, Snippet}; use rustc_data_structures::sync::Lrc; use rustc_error_messages::FluentArgs; -use rustc_span::source_map::SourceMap; use rustc_span::SourceFile; +use rustc_span::source_map::SourceMap; use crate::emitter::FileWithAnnotatedLines; use crate::snippet::Line; -use crate::translation::{to_fluent_args, Translate}; +use crate::translation::{Translate, to_fluent_args}; use crate::{ CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, FluentBundle, LazyFallbackBundle, Level, MultiSpan, Style, Subdiag, @@ -48,7 +48,7 @@ impl Emitter for AnnotateSnippetEmitter { fn emit_diagnostic(&mut self, mut diag: DiagInner) { let fluent_args = to_fluent_args(diag.args.iter()); - let mut suggestions = diag.suggestions.unwrap_or(vec![]); + let mut suggestions = diag.suggestions.unwrap_tag(); self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 34aebadfdadc5..4352de3ad25fe 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -7,25 +7,21 @@ use std::panic; use std::thread::panicking; use rustc_data_structures::fx::FxIndexMap; -use rustc_error_messages::{fluent_value_from_str_list_sep_by_and, FluentValue}; -use rustc_lint_defs::{Applicability, LintExpectationId}; +use rustc_error_messages::{FluentValue, fluent_value_from_str_list_sep_by_and}; +use rustc_lint_defs::Applicability; use rustc_macros::{Decodable, Encodable}; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; -use rustc_span::{AttrId, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use tracing::debug; use crate::snippet::Style; use crate::{ CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level, MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle, + Suggestions, }; -/// Error type for `DiagInner`'s `suggestions` field, indicating that -/// `.disable_suggestions()` was called on the `DiagInner`. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] -pub struct SuggestionsDisabled; - /// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of /// `DiagArg` are converted to `FluentArgs` (consuming the collection) at the start of diagnostic /// emission. @@ -296,7 +292,7 @@ pub struct DiagInner { pub code: Option, pub span: MultiSpan, pub children: Vec, - pub suggestions: Result, SuggestionsDisabled>, + pub suggestions: Suggestions, pub args: DiagArgMap, /// This is not used for highlighting or rendering any error message. Rather, it can be used @@ -325,7 +321,7 @@ impl DiagInner { code: None, span: MultiSpan::new(), children: vec![], - suggestions: Ok(vec![]), + suggestions: Suggestions::Enabled(vec![]), args: Default::default(), sort_span: DUMMY_SP, is_lint: None, @@ -354,26 +350,6 @@ impl DiagInner { } } - pub(crate) fn update_unstable_expectation_id( - &mut self, - unstable_to_stable: &FxIndexMap, - ) { - if let Level::Expect(expectation_id) | Level::ForceWarning(Some(expectation_id)) = - &mut self.level - && let LintExpectationId::Unstable { attr_id, lint_index } = *expectation_id - { - // The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index. - // The lint index inside the attribute is manually transferred here. - let Some(stable_id) = unstable_to_stable.get(&attr_id) else { - panic!("{expectation_id:?} must have a matching stable id") - }; - - let mut stable_id = *stable_id; - stable_id.set_lint_index(lint_index); - *expectation_id = stable_id; - } - } - /// Indicates whether this diagnostic should show up in cargo's future breakage report. pub(crate) fn has_future_breakage(&self) -> bool { matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. })) @@ -429,7 +405,7 @@ impl DiagInner { &Option, &MultiSpan, &[Subdiag], - &Result, SuggestionsDisabled>, + &Suggestions, Vec<(&DiagArgName, &DiagArgValue)>, &Option, ) { @@ -479,7 +455,7 @@ pub struct Subdiag { /// - The `EmissionGuarantee`, which determines the type returned from `emit`. /// /// Each constructed `Diag` must be consumed by a function such as `emit`, -/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurrs if a `Diag` +/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurs if a `Diag` /// is dropped without being consumed by one of these functions. /// /// If there is some state in a downstream crate you would like to access in @@ -701,10 +677,10 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { " ".repeat(expected_padding), expected_label ))]; - msg.extend(expected.0.into_iter()); + msg.extend(expected.0); msg.push(StringPart::normal(format!("`{expected_extra}\n"))); msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label))); - msg.extend(found.0.into_iter()); + msg.extend(found.0); msg.push(StringPart::normal(format!("`{found_extra}"))); // For now, just attach these as notes. @@ -843,16 +819,32 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self } - /// Disallow attaching suggestions this diagnostic. + /// Disallow attaching suggestions to this diagnostic. /// Any suggestions attached e.g. with the `span_suggestion_*` methods /// (before and after the call to `disable_suggestions`) will be ignored. #[rustc_lint_diagnostics] pub fn disable_suggestions(&mut self) -> &mut Self { - self.suggestions = Err(SuggestionsDisabled); + self.suggestions = Suggestions::Disabled; self } - /// Helper for pushing to `self.suggestions`, if available (not disable). + /// Prevent new suggestions from being added to this diagnostic. + /// + /// Suggestions added before the call to `.seal_suggestions()` will be preserved + /// and new suggestions will be ignored. + #[rustc_lint_diagnostics] + pub fn seal_suggestions(&mut self) -> &mut Self { + if let Suggestions::Enabled(suggestions) = &mut self.suggestions { + let suggestions_slice = std::mem::take(suggestions).into_boxed_slice(); + self.suggestions = Suggestions::Sealed(suggestions_slice); + } + self + } + + /// Helper for pushing to `self.suggestions`. + /// + /// A new suggestion is added if suggestions are enabled for this diagnostic. + /// Otherwise, they are ignored. #[rustc_lint_diagnostics] fn push_suggestion(&mut self, suggestion: CodeSuggestion) { for subst in &suggestion.substitutions { @@ -866,7 +858,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { } } - if let Ok(suggestions) = &mut self.suggestions { + if let Suggestions::Enabled(suggestions) = &mut self.suggestions { suggestions.push(suggestion); } } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 9e3bc3e60b12f..19529f06ef1d2 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -7,9 +7,9 @@ use std::process::ExitStatus; use rustc_ast_pretty::pprust; use rustc_macros::Subdiagnostic; +use rustc_span::Span; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; -use rustc_span::Span; use rustc_target::abi::TargetDataLayoutErrors; use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use rustc_type_ir::{ClosureKind, FloatTy}; @@ -17,8 +17,8 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::diagnostic::DiagLocation; use crate::{ - fluent_generated as fluent, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, - ErrCode, IntoDiagArg, Level, SubdiagMessageOp, Subdiagnostic, + Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, + SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent, }; pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 2bc29dabd18a1..1dc52c4d0a423 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -8,7 +8,7 @@ //! The output types are defined in `rustc_session::config::ErrorOutputType`. use std::borrow::Cow; -use std::cmp::{max, min, Reverse}; +use std::cmp::{Reverse, max, min}; use std::error::Report; use std::io::prelude::*; use std::io::{self, IsTerminal}; @@ -22,7 +22,7 @@ use rustc_error_messages::{FluentArgs, SpanLabel}; use rustc_lint_defs::pluralize; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::{char_width, FileLines, FileName, SourceFile, Span}; +use rustc_span::{FileLines, FileName, SourceFile, Span, char_width}; use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use tracing::{debug, instrument, trace, warn}; @@ -31,7 +31,7 @@ use crate::snippet::{ Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString, }; use crate::styled_buffer::StyledBuffer; -use crate::translation::{to_fluent_args, Translate}; +use crate::translation::{Translate, to_fluent_args}; use crate::{ CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level, MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl, @@ -498,7 +498,7 @@ impl Emitter for HumanEmitter { fn emit_diagnostic(&mut self, mut diag: DiagInner) { let fluent_args = to_fluent_args(diag.args.iter()); - let mut suggestions = diag.suggestions.unwrap_or(vec![]); + let mut suggestions = diag.suggestions.unwrap_tag(); self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( @@ -2300,7 +2300,7 @@ impl HumanEmitter { // For example, for the following: // | // 2 - .await - // 2 + (note the left over whitepsace) + // 2 + (note the left over whitespace) // | // We really want // | diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 32e59f9ab036a..1972a522e394a 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -19,21 +19,22 @@ use derive_setters::Setters; use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_error_messages::FluentArgs; use rustc_lint_defs::Applicability; +use rustc_span::Span; use rustc_span::hygiene::ExpnData; use rustc_span::source_map::SourceMap; -use rustc_span::Span; use serde::Serialize; use termcolor::{ColorSpec, WriteColor}; use crate::diagnostic::IsLint; use crate::emitter::{ - should_show_source_code, ColorConfig, Destination, Emitter, HumanEmitter, - HumanReadableErrorType, + ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, + should_show_source_code, }; use crate::registry::Registry; -use crate::translation::{to_fluent_args, Translate}; +use crate::translation::{Translate, to_fluent_args}; use crate::{ - CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, TerminalUrl, + CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, Suggestions, + TerminalUrl, }; #[cfg(test)] @@ -292,7 +293,7 @@ impl Diagnostic { /// Converts from `rustc_errors::DiagInner` to `Diagnostic`. fn from_errors_diagnostic(diag: crate::DiagInner, je: &JsonEmitter) -> Diagnostic { let args = to_fluent_args(diag.args.iter()); - let sugg = diag.suggestions.iter().flatten().map(|sugg| { + let sugg_to_diag = |sugg: &CodeSuggestion| { let translated_message = je.translate_message(&sugg.msg, &args).map_err(Report::new).unwrap(); Diagnostic { @@ -303,7 +304,12 @@ impl Diagnostic { children: vec![], rendered: None, } - }); + }; + let sugg = match &diag.suggestions { + Suggestions::Enabled(suggestions) => suggestions.iter().map(sugg_to_diag), + Suggestions::Sealed(suggestions) => suggestions.iter().map(sugg_to_diag), + Suggestions::Disabled => [].iter().map(sugg_to_diag), + }; // generate regular command line output and store it in the json diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index 6af376d7afdb2..0de555b83d3ab 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -1,7 +1,7 @@ use std::str; -use rustc_span::source_map::FilePathMapping; use rustc_span::BytePos; +use rustc_span::source_map::FilePathMapping; use serde::Deserialize; use super::*; @@ -69,128 +69,96 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { #[test] fn empty() { - test_positions( - " ", - (0, 1), - SpanTestData { - byte_start: 0, - byte_end: 1, - line_start: 1, - column_start: 1, - line_end: 1, - column_end: 2, - }, - ) + test_positions(" ", (0, 1), SpanTestData { + byte_start: 0, + byte_end: 1, + line_start: 1, + column_start: 1, + line_end: 1, + column_end: 2, + }) } #[test] fn bom() { - test_positions( - "\u{feff} ", - (0, 1), - SpanTestData { - byte_start: 3, - byte_end: 4, - line_start: 1, - column_start: 1, - line_end: 1, - column_end: 2, - }, - ) + test_positions("\u{feff} ", (0, 1), SpanTestData { + byte_start: 3, + byte_end: 4, + line_start: 1, + column_start: 1, + line_end: 1, + column_end: 2, + }) } #[test] fn lf_newlines() { - test_positions( - "\nmod foo;\nmod bar;\n", - (5, 12), - SpanTestData { - byte_start: 5, - byte_end: 12, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }, - ) + test_positions("\nmod foo;\nmod bar;\n", (5, 12), SpanTestData { + byte_start: 5, + byte_end: 12, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }) } #[test] fn crlf_newlines() { - test_positions( - "\r\nmod foo;\r\nmod bar;\r\n", - (5, 12), - SpanTestData { - byte_start: 6, - byte_end: 14, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }, - ) + test_positions("\r\nmod foo;\r\nmod bar;\r\n", (5, 12), SpanTestData { + byte_start: 6, + byte_end: 14, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }) } #[test] fn crlf_newlines_with_bom() { - test_positions( - "\u{feff}\r\nmod foo;\r\nmod bar;\r\n", - (5, 12), - SpanTestData { - byte_start: 9, - byte_end: 17, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }, - ) + test_positions("\u{feff}\r\nmod foo;\r\nmod bar;\r\n", (5, 12), SpanTestData { + byte_start: 9, + byte_end: 17, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }) } #[test] fn span_before_crlf() { - test_positions( - "foo\r\nbar", - (2, 3), - SpanTestData { - byte_start: 2, - byte_end: 3, - line_start: 1, - column_start: 3, - line_end: 1, - column_end: 4, - }, - ) + test_positions("foo\r\nbar", (2, 3), SpanTestData { + byte_start: 2, + byte_end: 3, + line_start: 1, + column_start: 3, + line_end: 1, + column_end: 4, + }) } #[test] fn span_on_crlf() { - test_positions( - "foo\r\nbar", - (3, 4), - SpanTestData { - byte_start: 3, - byte_end: 5, - line_start: 1, - column_start: 4, - line_end: 2, - column_end: 1, - }, - ) + test_positions("foo\r\nbar", (3, 4), SpanTestData { + byte_start: 3, + byte_end: 5, + line_start: 1, + column_start: 4, + line_end: 2, + column_end: 1, + }) } #[test] fn span_after_crlf() { - test_positions( - "foo\r\nbar", - (4, 5), - SpanTestData { - byte_start: 5, - byte_end: 6, - line_start: 2, - column_start: 1, - line_end: 2, - column_end: 2, - }, - ) + test_positions("foo\r\nbar", (4, 5), SpanTestData { + byte_start: 5, + byte_end: 6, + line_start: 2, + column_start: 1, + line_end: 2, + column_end: 2, + }) } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index e08d28a156c71..39acacfbe59c8 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -42,6 +42,7 @@ use std::ops::DerefMut; use std::path::{Path, PathBuf}; use std::{fmt, panic}; +use Level::*; pub use codes::*; pub use diagnostic::{ BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString, @@ -53,29 +54,28 @@ pub use diagnostic_impls::{ IndicateAnonymousLifetime, SingleLabelManySpans, }; pub use emitter::ColorConfig; -use emitter::{is_case_difference, is_different, DynEmitter, Emitter}; +use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; use registry::Registry; +use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; -use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ - fallback_fluent_bundle, fluent_bundle, DiagMessage, FluentBundle, LanguageIdentifier, - LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, + DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, + SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_lint_defs::LintExpectationId; -pub use rustc_lint_defs::{pluralize, Applicability}; +pub use rustc_lint_defs::{Applicability, pluralize}; use rustc_macros::{Decodable, Encodable}; +pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; use rustc_span::source_map::SourceMap; -pub use rustc_span::ErrorGuaranteed; -use rustc_span::{AttrId, Loc, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Loc, Span}; pub use snippet::Style; // Used by external projects such as `rust-gpu`. // See https://github.com/rust-lang/rust/pull/115393. pub use termcolor::{Color, ColorSpec, WriteColor}; use tracing::debug; -use Level::*; pub mod annotate_snippet_emitter_writer; pub mod codes; @@ -126,6 +126,41 @@ impl SuggestionStyle { } } +/// Represents the help messages seen on a diagnostic. +#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] +pub enum Suggestions { + /// Indicates that new suggestions can be added or removed from this diagnostic. + /// + /// `DiagInner`'s new_* methods initialize the `suggestions` field with + /// this variant. Also, this is the default variant for `Suggestions`. + Enabled(Vec), + /// Indicates that suggestions cannot be added or removed from this diagnostic. + /// + /// Gets toggled when `.seal_suggestions()` is called on the `DiagInner`. + Sealed(Box<[CodeSuggestion]>), + /// Indicates that no suggestion is available for this diagnostic. + /// + /// Gets toggled when `.disable_suggestions()` is called on the `DiagInner`. + Disabled, +} + +impl Suggestions { + /// Returns the underlying list of suggestions. + pub fn unwrap_tag(self) -> Vec { + match self { + Suggestions::Enabled(suggestions) => suggestions, + Suggestions::Sealed(suggestions) => suggestions.into_vec(), + Suggestions::Disabled => Vec::new(), + } + } +} + +impl Default for Suggestions { + fn default() -> Self { + Self::Enabled(vec![]) + } +} + #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] pub struct CodeSuggestion { /// Each substitute can have multiple variants due to multiple @@ -497,28 +532,18 @@ struct DiagCtxtInner { future_breakage_diagnostics: Vec, - /// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is - /// dropped. However, it can have values if the compilation is stopped early - /// or is only partially executed. To avoid ICEs, like in rust#94953 we only - /// check if [`Self::unstable_expect_diagnostics`] is empty, if the expectation ids - /// have been converted. - check_unstable_expect_diagnostics: bool, - - /// Expected [`DiagInner`][struct@diagnostic::DiagInner]s store a [`LintExpectationId`] as part - /// of the lint level. [`LintExpectationId`]s created early during the compilation - /// (before `HirId`s have been defined) are not stable and can therefore not be - /// stored on disk. This buffer stores these diagnostics until the ID has been - /// replaced by a stable [`LintExpectationId`]. The [`DiagInner`][struct@diagnostic::DiagInner]s - /// are submitted for storage and added to the list of fulfilled expectations. - unstable_expect_diagnostics: Vec, - /// expected diagnostic will have the level `Expect` which additionally /// carries the [`LintExpectationId`] of the expectation that can be /// marked as fulfilled. This is a collection of all [`LintExpectationId`]s /// that have been marked as fulfilled this way. /// + /// Emitting expectations after having stolen this field can happen. In particular, an + /// `#[expect(warnings)]` can easily make the `UNFULFILLED_LINT_EXPECTATIONS` lint expect + /// itself. To avoid needless complexity in this corner case, we tolerate failing to track + /// those expectations. + /// /// [RFC-2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html - fulfilled_expectations: FxHashSet, + fulfilled_expectations: FxIndexSet, /// The file where the ICE information is stored. This allows delayed_span_bug backtraces to be /// stored along side the main panic backtrace. @@ -546,6 +571,8 @@ pub enum StashKey { /// Query cycle detected, stashing in favor of a better error. Cycle, UndeterminedMacroResolution, + /// Used by `Parser::maybe_recover_trailing_expr` + ExprInPat, } fn default_track_diagnostic(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R { @@ -605,13 +632,6 @@ impl Drop for DiagCtxtInner { ); } } - - if self.check_unstable_expect_diagnostics { - assert!( - self.unstable_expect_diagnostics.is_empty(), - "all diagnostics with unstable expectations should have been converted", - ); - } } } @@ -740,8 +760,6 @@ impl DiagCtxt { emitted_diagnostics, stashed_diagnostics, future_breakage_diagnostics, - check_unstable_expect_diagnostics, - unstable_expect_diagnostics, fulfilled_expectations, ice_file: _, } = inner.deref_mut(); @@ -761,8 +779,6 @@ impl DiagCtxt { *emitted_diagnostics = Default::default(); *stashed_diagnostics = Default::default(); *future_breakage_diagnostics = Default::default(); - *check_unstable_expect_diagnostics = false; - *unstable_expect_diagnostics = Default::default(); *fulfilled_expectations = Default::default(); } @@ -817,7 +833,7 @@ impl<'a> DiagCtxtHandle<'a> { ); } // We delay a bug here so that `-Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs` - // can be used to create a backtrace at the stashing site insted of whenever the + // can be used to create a backtrace at the stashing site instead of whenever the // diagnostic context is dropped and thus delayed bugs are emitted. Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))), DelayedBug => { @@ -1094,44 +1110,10 @@ impl<'a> DiagCtxtHandle<'a> { inner.emitter.emit_unused_externs(lint_level, unused_externs) } - pub fn update_unstable_expectation_id( - &self, - unstable_to_stable: FxIndexMap, - ) { - let mut inner = self.inner.borrow_mut(); - let diags = std::mem::take(&mut inner.unstable_expect_diagnostics); - inner.check_unstable_expect_diagnostics = true; - - if !diags.is_empty() { - inner.suppressed_expected_diag = true; - for mut diag in diags.into_iter() { - diag.update_unstable_expectation_id(&unstable_to_stable); - - // Here the diagnostic is given back to `emit_diagnostic` where it was first - // intercepted. Now it should be processed as usual, since the unstable expectation - // id is now stable. - inner.emit_diagnostic(diag, self.tainted_with_errors); - } - } - - inner - .stashed_diagnostics - .values_mut() - .for_each(|(diag, _guar)| diag.update_unstable_expectation_id(&unstable_to_stable)); - inner - .future_breakage_diagnostics - .iter_mut() - .for_each(|diag| diag.update_unstable_expectation_id(&unstable_to_stable)); - } - /// This methods steals all [`LintExpectationId`]s that are stored inside /// [`DiagCtxtInner`] and indicate that the linked expectation has been fulfilled. #[must_use] - pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet { - assert!( - self.inner.borrow().unstable_expect_diagnostics.is_empty(), - "`DiagCtxtInner::unstable_expect_diagnostics` should be empty at this point", - ); + pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet { std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) } @@ -1440,8 +1422,6 @@ impl DiagCtxtInner { emitted_diagnostics: Default::default(), stashed_diagnostics: Default::default(), future_breakage_diagnostics: Vec::new(), - check_unstable_expect_diagnostics: false, - unstable_expect_diagnostics: Vec::new(), fulfilled_expectations: Default::default(), ice_file: None, } @@ -1471,24 +1451,6 @@ impl DiagCtxtInner { mut diagnostic: DiagInner, taint: Option<&Cell>>, ) -> Option { - match diagnostic.level { - Expect(expect_id) | ForceWarning(Some(expect_id)) => { - // The `LintExpectationId` can be stable or unstable depending on when it was - // created. Diagnostics created before the definition of `HirId`s are unstable and - // can not yet be stored. Instead, they are buffered until the `LintExpectationId` - // is replaced by a stable one by the `LintLevelsBuilder`. - if let LintExpectationId::Unstable { .. } = expect_id { - // We don't call TRACK_DIAGNOSTIC because we wait for the - // unstable ID to be updated, whereupon the diagnostic will be - // passed into this method again. - self.unstable_expect_diagnostics.push(diagnostic); - return None; - } - // Continue through to the `Expect`/`ForceWarning` case below. - } - _ => {} - } - if diagnostic.has_future_breakage() { // Future breakages aren't emitted if they're `Level::Allow` or // `Level::Expect`, but they still need to be constructed and @@ -1564,9 +1526,6 @@ impl DiagCtxtInner { return None; } Expect(expect_id) | ForceWarning(Some(expect_id)) => { - if let LintExpectationId::Unstable { .. } = expect_id { - unreachable!(); // this case was handled at the top of this function - } self.fulfilled_expectations.insert(expect_id); if let Expect(_) = diagnostic.level { // Nothing emitted here for expected lints. diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs index 7557969f374ac..85199c34a147c 100644 --- a/compiler/rustc_errors/src/lock.rs +++ b/compiler/rustc_errors/src/lock.rs @@ -16,11 +16,11 @@ pub(crate) fn acquire_global_lock(name: &str) -> Box { use std::ffi::CString; use std::io; - use windows::core::PCSTR; use windows::Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0}; use windows::Win32::System::Threading::{ - CreateMutexA, ReleaseMutex, WaitForSingleObject, INFINITE, + CreateMutexA, INFINITE, ReleaseMutex, WaitForSingleObject, }; + use windows::core::PCSTR; struct Handle(HANDLE); diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs index b1db44dd215b8..8dd146c1c337f 100644 --- a/compiler/rustc_errors/src/markdown/parse.rs +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -487,7 +487,7 @@ fn is_break_ty(val: &MdTree<'_>) -> bool { || matches!(val, MdTree::PlainText(txt) if txt.trim().is_empty()) } -/// Perform tranformations to text. This splits paragraphs, replaces patterns, +/// Perform transformations to text. This splits paragraphs, replaces patterns, /// and corrects newlines. /// /// To avoid allocating strings (and using a different heavier tt type), our diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index bfe4c9f2a3a2b..17a1635bd1143 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -1,11 +1,11 @@ use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; -use rustc_error_messages::{langid, DiagMessage}; +use rustc_error_messages::{DiagMessage, langid}; +use crate::FluentBundle; use crate::error::{TranslateError, TranslateErrorKind}; use crate::fluent_bundle::*; use crate::translation::Translate; -use crate::FluentBundle; struct Dummy { bundle: FluentBundle, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 8f9104135cddd..d0552a754feb0 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -15,8 +15,8 @@ use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; -use rustc_parse::parser::Parser; use rustc_parse::MACRO_ARGUMENTS; +use rustc_parse::parser::Parser; use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::parse::ParseSess; use rustc_session::{Limit, Session}; @@ -24,9 +24,9 @@ use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{FileName, Span, DUMMY_SP}; -use smallvec::{smallvec, SmallVec}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, FileName, Span}; +use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use crate::base::ast::NestedMetaItem; diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 8ecdb551342dd..b5945759d43a0 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -1,12 +1,12 @@ use rustc_ast::ptr::P; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, attr, token, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, + self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, attr, token, }; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Span}; +use thin_vec::{ThinVec, thin_vec}; use crate::base::ExtCtxt; @@ -152,18 +152,15 @@ impl<'a> ExtCtxt<'a> { } pub fn trait_bound(&self, path: ast::Path, is_const: bool) -> ast::GenericBound { - ast::GenericBound::Trait( - self.poly_trait_ref(path.span, path), - ast::TraitBoundModifiers { - polarity: ast::BoundPolarity::Positive, - constness: if is_const { - ast::BoundConstness::Maybe(DUMMY_SP) - } else { - ast::BoundConstness::Never - }, - asyncness: ast::BoundAsyncness::Normal, + ast::GenericBound::Trait(self.poly_trait_ref(path.span, path), ast::TraitBoundModifiers { + polarity: ast::BoundPolarity::Positive, + constness: if is_const { + ast::BoundConstness::Maybe(DUMMY_SP) + } else { + ast::BoundConstness::Never }, - ) + asyncness: ast::BoundAsyncness::Normal, + }) } pub fn lifetime(&self, span: Span, ident: Ident) -> ast::Lifetime { @@ -232,14 +229,11 @@ impl<'a> ExtCtxt<'a> { } pub fn block_expr(&self, expr: P) -> P { - self.block( - expr.span, - thin_vec![ast::Stmt { - id: ast::DUMMY_NODE_ID, - span: expr.span, - kind: ast::StmtKind::Expr(expr), - }], - ) + self.block(expr.span, thin_vec![ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: expr.span, + kind: ast::StmtKind::Expr(expr), + }]) } pub fn block(&self, span: Span, stmts: ThinVec) -> P { P(ast::Block { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b0d3fecbb479b..3208837427736 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -9,14 +9,14 @@ use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ - AttributeSafety, Features, ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES, + ACCEPTED_FEATURES, AttributeSafety, Features, REMOVED_FEATURES, UNSTABLE_FEATURES, }; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; -use rustc_session::parse::feature_err; use rustc_session::Session; -use rustc_span::symbol::{sym, Symbol}; +use rustc_session::parse::feature_err; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use thin_vec::ThinVec; use tracing::instrument; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0d56a005f159e..079dcee99d3f4 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -8,7 +8,7 @@ use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::visit::{self, try_visit, walk_list, AssocCtxt, Visitor, VisitorResult}; +use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem, @@ -23,12 +23,12 @@ use rustc_parse::parser::{ AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, }; use rustc_parse::validate_attr; -use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; use rustc_session::lint::BuiltinLintDiag; +use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; use rustc_session::parse::feature_err; use rustc_session::{Limit, Session}; use rustc_span::hygiene::SyntaxContext; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{Ident, sym}; use rustc_span::{ErrorGuaranteed, FileName, LocalExpnId, Span}; use smallvec::SmallVec; @@ -41,8 +41,10 @@ use crate::errors::{ }; use crate::fluent_generated; use crate::mbe::diagnostics::annotate_err_with_kind; -use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; -use crate::placeholders::{placeholder, PlaceholderExpander}; +use crate::module::{ + DirOwnership, ParsedExternalMod, mod_dir_path, mod_file_path_from_attr, parse_external_mod, +}; +use crate::placeholders::{PlaceholderExpander, placeholder}; macro_rules! ast_fragments { ( @@ -1202,8 +1204,14 @@ impl InvocationCollectorNode for P { ecx.current_expansion.dir_ownership, *inline, ); + // If the module was parsed from an external file, recover its path. + // This lets `parse_external_mod` catch cycles if it's self-referential. + let file_path = match inline { + Inline::Yes => None, + Inline::No => mod_file_path_from_attr(ecx.sess, &attrs, &dir_path), + }; node.attrs = attrs; - (None, dir_path, dir_ownership) + (file_path, dir_path, dir_ownership) } ModKind::Unloaded => { // We have an outline `mod foo;` so we need to parse the file. diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index 08d4a03945489..e5d098f63d6d1 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -16,8 +16,8 @@ use metavar_expr::MetaVarExpr; use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan}; use rustc_macros::{Decodable, Encodable}; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; /// Contains the sub-token-trees of a "delimited" token tree such as `(a b c)`. /// The delimiters are not represented explicitly in the `tts` vector. diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 5778f6616227a..103bbb05e7ff3 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -12,11 +12,11 @@ use rustc_span::symbol::Ident; use rustc_span::{ErrorGuaranteed, Span}; use tracing::debug; -use super::macro_rules::{parser_from_cx, NoopTracker}; -use crate::expand::{parse_ast_fragment, AstFragmentKind}; +use super::macro_rules::{NoopTracker, parser_from_cx}; +use crate::expand::{AstFragmentKind, parse_ast_fragment}; use crate::mbe::macro_parser::ParseResult::*; use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser}; -use crate::mbe::macro_rules::{try_match_macro, Tracker}; +use crate::mbe::macro_rules::{Tracker, try_match_macro}; pub(super) fn failed_to_match_macro( psess: &ParseSess, diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 68eeba6f415d5..b1d898b69494c 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -108,14 +108,14 @@ use std::iter; use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind}; -use rustc_ast::{NodeId, DUMMY_NODE_ID}; +use rustc_ast::{DUMMY_NODE_ID, NodeId}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_lint_defs::BuiltinLintDiag; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; -use rustc_span::symbol::{kw, MacroRulesNormalizedIdent}; +use rustc_span::symbol::{MacroRulesNormalizedIdent, kw}; use rustc_span::{ErrorGuaranteed, Span}; use smallvec::SmallVec; diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 9011d02da3358..3903203da3dbf 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -75,16 +75,16 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::fmt::Display; use std::rc::Rc; +pub(crate) use NamedMatch::*; +pub(crate) use ParseResult::*; use rustc_ast::token::{self, DocComment, NonterminalKind, Token}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_lint_defs::pluralize; use rustc_parse::parser::{ParseNtResult, Parser}; -use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; use rustc_span::Span; -pub(crate) use NamedMatch::*; -pub(crate) use ParseResult::*; +use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; use crate::mbe::macro_rules::Tracker; use crate::mbe::{KleeneOp, TokenTree}; @@ -398,8 +398,10 @@ pub(crate) enum NamedMatch { fn token_name_eq(t1: &Token, t2: &Token) -> bool { if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = (t1.ident(), t2.ident()) { ident1.name == ident2.name && is_raw1 == is_raw2 - } else if let (Some(ident1), Some(ident2)) = (t1.lifetime(), t2.lifetime()) { - ident1.name == ident2.name + } else if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = + (t1.lifetime(), t2.lifetime()) + { + ident1.name == ident2.name && is_raw1 == is_raw2 } else { t1.kind == t2.kind } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 256713ef73000..f40f99b6ea123 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -8,23 +8,23 @@ use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{NodeId, DUMMY_NODE_ID}; +use rustc_ast::{DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Applicability, ErrorGuaranteed}; use rustc_feature::Features; +use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, }; -use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::parser::{ParseNtResult, Parser, Recovery}; -use rustc_session::parse::ParseSess; use rustc_session::Session; +use rustc_session::parse::ParseSess; +use rustc_span::Span; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent}; -use rustc_span::Span; +use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, kw, sym}; use tracing::{debug, instrument, trace, trace_span}; use super::diagnostics; @@ -33,7 +33,7 @@ use crate::base::{ DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, }; -use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind}; +use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; use crate::mbe; use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg}; use crate::mbe::macro_check; @@ -408,35 +408,29 @@ pub fn compile_declarative_macro( // ...quasiquoting this would be nice. // These spans won't matter, anyways let argument_gram = vec![ - mbe::TokenTree::Sequence( - DelimSpan::dummy(), - mbe::SequenceRepetition { - tts: vec![ - mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), - mbe::TokenTree::token(token::FatArrow, def.span), - mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), - ], - separator: Some(Token::new( - if macro_rules { token::Semi } else { token::Comma }, - def.span, - )), - kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span), - num_captures: 2, - }, - ), + mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition { + tts: vec![ + mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), + mbe::TokenTree::token(token::FatArrow, def.span), + mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), + ], + separator: Some(Token::new( + if macro_rules { token::Semi } else { token::Comma }, + def.span, + )), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span), + num_captures: 2, + }), // to phase into semicolon-termination instead of semicolon-separation - mbe::TokenTree::Sequence( - DelimSpan::dummy(), - mbe::SequenceRepetition { - tts: vec![mbe::TokenTree::token( - if macro_rules { token::Semi } else { token::Comma }, - def.span, - )], - separator: None, - kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span), - num_captures: 0, - }, - ), + mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition { + tts: vec![mbe::TokenTree::token( + if macro_rules { token::Semi } else { token::Comma }, + def.span, + )], + separator: None, + kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span), + num_captures: 0, + }), ]; // Convert it into `MatcherLoc` form. let argument_gram = mbe::macro_parser::compute_locs(&argument_gram); diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 5df0aebfe57bd..f0a6c841f3121 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -1,13 +1,13 @@ use rustc_ast::token::NtExprKind::*; use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token}; -use rustc_ast::{tokenstream, NodeId}; +use rustc_ast::{NodeId, tokenstream}; use rustc_ast_pretty::pprust; use rustc_feature::Features; -use rustc_session::parse::feature_err; use rustc_session::Session; -use rustc_span::edition::Edition; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_session::parse::feature_err; use rustc_span::Span; +use rustc_span::edition::Edition; +use rustc_span::symbol::{Ident, kw, sym}; use crate::errors; use crate::mbe::macro_parser::count_metavar_decls; @@ -207,10 +207,10 @@ fn parse_tree<'a>( Some(&tokenstream::TokenTree::Delimited(delim_span, _, delim, ref tts)) => { if parsing_patterns { if delim != Delimiter::Parenthesis { - span_dollar_dollar_or_metavar_in_the_lhs_err( - sess, - &Token { kind: token::OpenDelim(delim), span: delim_span.entire() }, - ); + span_dollar_dollar_or_metavar_in_the_lhs_err(sess, &Token { + kind: token::OpenDelim(delim), + span: delim_span.entire(), + }); } } else { match delim { @@ -263,10 +263,12 @@ fn parse_tree<'a>( // Count the number of captured "names" (i.e., named metavars) let num_captures = if parsing_patterns { count_metavar_decls(&sequence) } else { 0 }; - TokenTree::Sequence( - delim_span, - SequenceRepetition { tts: sequence, separator, kleene, num_captures }, - ) + TokenTree::Sequence(delim_span, SequenceRepetition { + tts: sequence, + separator, + kleene, + num_captures, + }) } // `tree` is followed by an `ident`. This could be `$meta_var` or the `$crate` @@ -287,10 +289,10 @@ fn parse_tree<'a>( _, )) => { if parsing_patterns { - span_dollar_dollar_or_metavar_in_the_lhs_err( - sess, - &Token { kind: token::Dollar, span: dollar_span2 }, - ); + span_dollar_dollar_or_metavar_in_the_lhs_err(sess, &Token { + kind: token::Dollar, + span: dollar_span2, + }); } else { maybe_emit_macro_metavar_expr_feature(features, sess, dollar_span2); } @@ -315,14 +317,12 @@ fn parse_tree<'a>( // `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to // descend into the delimited set and further parse it. - &tokenstream::TokenTree::Delimited(span, spacing, delim, ref tts) => TokenTree::Delimited( - span, - spacing, - Delimited { + &tokenstream::TokenTree::Delimited(span, spacing, delim, ref tts) => { + TokenTree::Delimited(span, spacing, Delimited { delim, tts: parse(tts, parsing_patterns, sess, node_id, features, edition), - }, - ), + }) + } } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index b06910595bb25..fb6fe0bb1d77b 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -1,18 +1,18 @@ use std::mem; +use rustc_ast::ExprKind; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; -use rustc_ast::ExprKind; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult}; +use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parser::ParseNtResult; use rustc_session::parse::{ParseSess, SymbolGallery}; use rustc_span::hygiene::{LocalExpnId, Transparency}; -use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; -use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext}; -use smallvec::{smallvec, SmallVec}; +use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, sym}; +use rustc_span::{Span, Symbol, SyntaxContext, with_metavar_spans}; +use smallvec::{SmallVec, smallvec}; use crate::errors::{ CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce, @@ -283,9 +283,9 @@ pub(super) fn transcribe<'a>( let kind = token::NtIdent(*ident, *is_raw); TokenTree::token_alone(kind, sp) } - MatchedSingle(ParseNtResult::Lifetime(ident)) => { + MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => { marker.visit_span(&mut sp); - let kind = token::NtLifetime(*ident); + let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } MatchedSingle(ParseNtResult::Nt(nt)) => { @@ -773,18 +773,20 @@ fn extract_symbol_from_pnr<'a>( match pnr { ParseNtResult::Ident(nt_ident, is_raw) => { if let IdentIsRaw::Yes = is_raw { - return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR)); + Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR)) + } else { + Ok(nt_ident.name) } - return Ok(nt_ident.name); } ParseNtResult::Tt(TokenTree::Token( Token { kind: TokenKind::Ident(symbol, is_raw), .. }, _, )) => { if let IdentIsRaw::Yes = is_raw { - return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR)); + Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR)) + } else { + Ok(*symbol) } - return Ok(*symbol); } ParseNtResult::Tt(TokenTree::Token( Token { @@ -792,15 +794,13 @@ fn extract_symbol_from_pnr<'a>( .. }, _, - )) => { - return Ok(*symbol); - } + )) => Ok(*symbol), ParseNtResult::Nt(nt) if let Nonterminal::NtLiteral(expr) = &**nt && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind => { - return Ok(*symbol); + Ok(*symbol) } _ => Err(dcx .struct_err( diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 133483768511b..614f52bbd2851 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -2,13 +2,13 @@ use std::iter::once; use std::path::{self, Path, PathBuf}; use rustc_ast::ptr::P; -use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans}; +use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans, token}; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, validate_attr}; -use rustc_session::parse::ParseSess; use rustc_session::Session; -use rustc_span::symbol::{sym, Ident}; +use rustc_session::parse::ParseSess; use rustc_span::Span; +use rustc_span::symbol::{Ident, sym}; use thin_vec::ThinVec; use crate::base::ModuleData; @@ -171,7 +171,7 @@ fn mod_file_path<'a>( /// Derive a submodule path from the first found `#[path = "path_string"]`. /// The provided `dir_path` is joined with the `path_string`. -fn mod_file_path_from_attr( +pub(crate) fn mod_file_path_from_attr( sess: &Session, attrs: &[Attribute], dir_path: &Path, diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 469bed3cd5926..610c69e9d21b4 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -4,9 +4,9 @@ use rustc_ast::token::Delimiter; use rustc_ast::visit::AssocCtxt; use rustc_ast::{self as ast}; use rustc_data_structures::fx::FxHashMap; -use rustc_span::symbol::Ident; use rustc_span::DUMMY_SP; -use smallvec::{smallvec, SmallVec}; +use rustc_span::symbol::Ident; +use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use crate::expand::{AstFragment, AstFragmentKind}; diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 24f631ed5dc98..dca0516f9f3b3 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -4,8 +4,8 @@ use rustc_ast::tokenstream::TokenStream; use rustc_errors::ErrorGuaranteed; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::config::ProcMacroExecutionStrategy; -use rustc_span::profiling::SpannedEventArgRecorder; use rustc_span::Span; +use rustc_span::profiling::SpannedEventArgRecorder; use crate::base::{self, *}; use crate::{errors, proc_macro_server}; @@ -43,9 +43,9 @@ pub struct BangProcMacro { } impl base::BangProcMacro for BangProcMacro { - fn expand<'cx>( + fn expand( &self, - ecx: &'cx mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, span: Span, input: TokenStream, ) -> Result { @@ -73,9 +73,9 @@ pub struct AttrProcMacro { } impl base::AttrProcMacro for AttrProcMacro { - fn expand<'cx>( + fn expand( &self, - ecx: &'cx mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, span: Span, annotation: TokenStream, annotated: TokenStream, diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 4ff5da1a4bdfa..a7b251ab2527e 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -2,7 +2,7 @@ use std::ops::{Bound, Range}; use ast::token::IdentIsRaw; use pm::bridge::{ - server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, + DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, server, }; use pm::{Delimiter, Level}; use rustc_ast as ast; @@ -18,9 +18,9 @@ use rustc_parse::parser::Parser; use rustc_parse::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; -use rustc_span::symbol::{self, sym, Symbol}; +use rustc_span::symbol::{self, Symbol, sym}; use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use crate::base::ExtCtxt; @@ -229,15 +229,16 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec { + Lifetime(name, is_raw) => { let ident = symbol::Ident::new(name, span).without_first_quote(); trees.extend([ TokenTree::Punct(Punct { ch: b'\'', joint: true, span }), - TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }), + TokenTree::Ident(Ident { sym: ident.name, is_raw: is_raw.into(), span }), ]); } - NtLifetime(ident) => { - let stream = TokenStream::token_alone(token::Lifetime(ident.name), ident.span); + NtLifetime(ident, is_raw) => { + let stream = + TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span); trees.push(TokenTree::Group(Group { delimiter: pm::Delimiter::None, stream: Some(stream), diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 9223c3c322a56..70e92f545c639 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -2,7 +2,7 @@ use rustc_span::symbol::sym; -use super::{to_nonzero, Feature}; +use super::{Feature, to_nonzero}; macro_rules! declare_features { ($( @@ -61,7 +61,7 @@ declare_features! ( /// Allows explicit discriminants on non-unit enum variants. (accepted, arbitrary_enum_discriminant, "1.66.0", Some(60553)), /// Allows using `const` operands in inline assembly. - (accepted, asm_const, "CURRENT_RUSTC_VERSION", Some(93332)), + (accepted, asm_const, "1.82.0", Some(93332)), /// Allows using `sym` operands in inline assembly. (accepted, asm_sym, "1.66.0", Some(93333)), /// Allows the definition of associated constants in `trait` or `impl` blocks. @@ -115,8 +115,10 @@ declare_features! ( (accepted, conservative_impl_trait, "1.26.0", Some(34511)), /// Allows calling constructor functions in `const fn`. (accepted, const_constructor, "1.40.0", Some(61456)), + /// Allows the definition of `const extern fn` and `const unsafe extern fn`. + (accepted, const_extern_fn, "CURRENT_RUSTC_VERSION", Some(64926)), /// Allows basic arithmetic on floating point types in a `const fn`. - (accepted, const_fn_floating_point_arithmetic, "CURRENT_RUSTC_VERSION", Some(57241)), + (accepted, const_fn_floating_point_arithmetic, "1.82.0", Some(57241)), /// Allows using and casting function pointers in a `const fn`. (accepted, const_fn_fn_ptr_basics, "1.61.0", Some(57563)), /// Allows trait bounds in `const fn`. @@ -141,10 +143,14 @@ declare_features! ( (accepted, const_let, "1.33.0", Some(48821)), /// Allows the use of `loop` and `while` in constants. (accepted, const_loop, "1.46.0", Some(52000)), + /// Allows using `&mut` in constant functions. + (accepted, const_mut_refs, "CURRENT_RUSTC_VERSION", Some(57349)), /// Allows panicking during const eval (producing compile-time errors). (accepted, const_panic, "1.57.0", Some(51999)), /// Allows dereferencing raw pointers during const eval. (accepted, const_raw_ptr_deref, "1.58.0", Some(51911)), + /// Allows references to types with interior mutability within constants + (accepted, const_refs_to_cell, "CURRENT_RUSTC_VERSION", Some(80384)), /// Allows implementing `Copy` for closures where possible (RFC 2132). (accepted, copy_closures, "1.26.0", Some(44490)), /// Allows `crate` in paths. @@ -272,7 +278,7 @@ declare_features! ( /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. (accepted, min_const_unsafe_fn, "1.33.0", Some(55607)), /// Allows exhaustive pattern matching on uninhabited types when matched by value. - (accepted, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", Some(119612)), + (accepted, min_exhaustive_patterns, "1.82.0", Some(119612)), /// Allows using `Self` and associated types in struct expressions and patterns. (accepted, more_struct_aliases, "1.16.0", Some(37544)), /// Allows using the MOVBE target feature. @@ -299,7 +305,7 @@ declare_features! ( /// Allows `foo.rs` as an alternative to `foo/mod.rs`. (accepted, non_modrs_mods, "1.30.0", Some(44660)), /// Allows using multiple nested field accesses in offset_of! - (accepted, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(120140)), + (accepted, offset_of_nested, "1.82.0", Some(120140)), /// Allows the use of or-patterns (e.g., `0 | 1`). (accepted, or_patterns, "1.53.0", Some(54883)), /// Allows using `+bundle,+whole-archive` link modifiers with native libs. @@ -312,7 +318,7 @@ declare_features! ( /// Allows parentheses in patterns. (accepted, pattern_parentheses, "1.31.0", Some(51087)), /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. - (accepted, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)), + (accepted, precise_capturing, "1.82.0", Some(123432)), /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356)), /// Allows multi-segment paths in attributes and derives. @@ -326,7 +332,7 @@ declare_features! ( /// Allows keywords to be escaped for use as identifiers. (accepted, raw_identifiers, "1.30.0", Some(48589)), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. - (accepted, raw_ref_op, "CURRENT_RUSTC_VERSION", Some(64490)), + (accepted, raw_ref_op, "1.82.0", Some(64490)), /// Allows relaxing the coherence rules such that /// `impl ForeignTrait for ForeignType` is permitted. (accepted, re_rebalance_coherence, "1.41.0", Some(55437)), @@ -399,11 +405,11 @@ declare_features! ( /// Allows arbitrary delimited token streams in non-macro attributes. (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208)), /// Allows unsafe attributes. - (accepted, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)), + (accepted, unsafe_attributes, "1.82.0", Some(123757)), /// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block. (accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668)), /// Allows unsafe on extern declarations and safety qualifiers over internal items. - (accepted, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)), + (accepted, unsafe_extern_blocks, "1.82.0", Some(123743)), /// Allows importing and reexporting macros with `use`, /// enables macro modularization in general. (accepted, use_extern_macros, "1.30.0", Some(35896)), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e2491922b8df6..17827b4e43b37 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -2,11 +2,11 @@ use std::sync::LazyLock; -use rustc_data_structures::fx::FxHashMap; -use rustc_span::symbol::{sym, Symbol}; use AttributeDuplicates::*; use AttributeGate::*; use AttributeType::*; +use rustc_data_structures::fx::FxHashMap; +use rustc_span::symbol::{Symbol, sym}; use crate::{Features, Stability}; @@ -551,10 +551,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, experimental!(register_tool), ), - gated!( - cmse_nonsecure_entry, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, experimental!(cmse_nonsecure_entry) - ), // RFC 2632 gated!( const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl, @@ -793,6 +789,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), + // Used by the `rustc::untracked_query_information` lint to warn methods which + // might not be stable during incremental compilation. + rustc_attr!( + rustc_lint_untracked_query_information, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + ), // Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic // APIs. Any function with this attribute will be checked by that lint. rustc_attr!( @@ -857,8 +859,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, - "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ - niche optimizations in libcore and libstd and will never be stable", + "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \ + guaranteed niche optimizations in libcore and libstd and will never be stable\n\ + (note that the compiler does not even check whether the type indeed is being non-null-optimized; \ + it is your responsibility to ensure that the attribute is only used on types that are optimized)", ), // ========================================================================== @@ -1180,3 +1184,11 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> } map }); + +pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool { + match sym { + sym::on_unimplemented => true, + sym::do_not_recommend => features.do_not_recommend, + _ => false, + } +} diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index adaaba3cd235e..8f4c0b0ac95f9 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -129,9 +129,10 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option() {`. - (incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)), + (incomplete, unsized_const_params, "1.82.0", Some(95174)), /// Allows unsized fn parameters. (internal, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index ca8bace28f3d1..ead72e2a0e19a 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -11,7 +11,7 @@ use fluent_syntax::parser::ParserError; use proc_macro::{Diagnostic, Level, Span}; use proc_macro2::TokenStream; use quote::quote; -use syn::{parse_macro_input, Ident, LitStr}; +use syn::{Ident, LitStr, parse_macro_input}; use unic_langid::langid; /// Helper function for returning an absolute path for macro-invocation relative file paths. @@ -138,25 +138,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok // with a lowercase as rustc errors do. err.replace_range(0..1, &err.chars().next().unwrap().to_lowercase().to_string()); - let line_starts: Vec = std::iter::once(0) - .chain( - this.source() - .char_indices() - .filter_map(|(i, c)| Some(i + 1).filter(|_| c == '\n')), - ) - .collect(); - let line_start = line_starts - .iter() - .enumerate() - .map(|(line, idx)| (line + 1, idx)) - .filter(|(_, idx)| **idx <= pos.start) - .last() - .unwrap() - .0; - let message = annotate_snippets::Level::Error.title(&err).snippet( Snippet::source(this.source()) - .line_start(line_start) .origin(&relative_ftl_path) .fold(true) .annotation(annotate_snippets::Level::Error.span(pos.start..pos.end - 1)), diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 91eae98071a49..80813af386472 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,5 +1,5 @@ use std::ffi::CString; -use std::path::{absolute, Path, PathBuf}; +use std::path::{Path, PathBuf, absolute}; use std::{fs, io}; // Unfortunately, on windows, it looks like msvcrt.dll is silently translating diff --git a/compiler/rustc_graphviz/src/tests.rs b/compiler/rustc_graphviz/src/tests.rs index 01e6cb9a3daad..712620a2000c7 100644 --- a/compiler/rustc_graphviz/src/tests.rs +++ b/compiler/rustc_graphviz/src/tests.rs @@ -4,7 +4,7 @@ use std::io::prelude::*; use NodeLabels::*; use super::LabelText::{self, EscStr, HtmlStr, LabelStr}; -use super::{render, Edges, GraphWalk, Id, Labeller, Nodes, Style}; +use super::{Edges, GraphWalk, Id, Labeller, Nodes, Style, render}; /// each node is an index in a vector in the graph. type Node = usize; @@ -360,16 +360,12 @@ fn left_aligned_text() { let mut writer = Vec::new(); - let g = LabelledGraphWithEscStrs::new( - "syntax_tree", - labels, - vec![ - edge(0, 1, "then", Style::None), - edge(0, 2, "else", Style::None), - edge(1, 3, ";", Style::None), - edge(2, 3, ";", Style::None), - ], - ); + let g = LabelledGraphWithEscStrs::new("syntax_tree", labels, vec![ + edge(0, 1, "then", Style::None), + edge(0, 2, "else", Style::None), + edge(1, 3, ";", Style::None), + edge(2, 3, ";", Style::None), + ]); render(&g, &mut writer).unwrap(); let mut r = String::new(); diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index bd55617d84ea2..3276f516a52a1 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -6,10 +6,10 @@ use rustc_ast::NodeId; use rustc_data_structures::stable_hasher::ToStableHashKey; use rustc_data_structures::unord::UnordMap; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_span::Symbol; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::kw; -use rustc_span::Symbol; use crate::definitions::DefPathData; use crate::hir; @@ -287,7 +287,10 @@ impl DefKind { #[inline] pub fn is_fn_like(self) -> bool { - matches!(self, DefKind::Fn | DefKind::AssocFn | DefKind::Closure) + matches!( + self, + DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::SyntheticCoroutineBody + ) } /// Whether `query get_codegen_attrs` should be used with this definition. diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 8c2be2152ea3a..9873a58cfe99f 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -11,11 +11,11 @@ use rustc_data_structures::stable_hasher::{Hash64, StableHasher}; use rustc_data_structures::unord::UnordMap; use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable}; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{Symbol, kw, sym}; use tracing::{debug, instrument}; pub use crate::def_id::DefPathHash; -use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId}; use crate::def_path_hash_map::DefPathHashMap; /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa. diff --git a/compiler/rustc_hir/src/diagnostic_items.rs b/compiler/rustc_hir/src/diagnostic_items.rs index 23a83a5011b5a..67e9c9eeedc43 100644 --- a/compiler/rustc_hir/src/diagnostic_items.rs +++ b/compiler/rustc_hir/src/diagnostic_items.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_span::def_id::DefIdMap; use rustc_span::Symbol; +use rustc_span::def_id::DefIdMap; use crate::def_id::DefId; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 57c47d29857c3..71216023ecc33 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -17,18 +17,18 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, ErrorGuaranteed, Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Span}; use rustc_target::asm::InlineAsmRegOrRegClass; use rustc_target::spec::abi::Abi; use smallvec::SmallVec; use tracing::debug; +use crate::LangItem; use crate::def::{CtorKind, DefKind, Res}; use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::FnKind; -use crate::LangItem; #[derive(Debug, Copy, Clone, HashStable_Generic)] pub struct Lifetime { @@ -168,6 +168,19 @@ impl Lifetime { (LifetimeSuggestionPosition::Normal, self.ident.span) } } + + pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) { + debug_assert!(new_lifetime.starts_with('\'')); + let (pos, span) = self.suggestion_position(); + let code = match pos { + LifetimeSuggestionPosition::Normal => format!("{new_lifetime}"), + LifetimeSuggestionPosition::Ampersand => format!("{new_lifetime} "), + LifetimeSuggestionPosition::ElidedPath => format!("<{new_lifetime}>"), + LifetimeSuggestionPosition::ElidedPathArgument => format!("{new_lifetime}, "), + LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lifetime}"), + }; + (span, code) + } } /// A `Path` is essentially Rust's notion of a name; for instance, @@ -1365,7 +1378,8 @@ pub struct LetStmt<'hir> { pub hir_id: HirId, pub span: Span, /// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop - /// desugaring. Otherwise will be `Normal`. + /// desugaring, or `AssignDesugar` if it is the result of a complex + /// assignment desugaring. Otherwise will be `Normal`. pub source: LocalSource, } @@ -1654,10 +1668,17 @@ pub enum ArrayLen<'hir> { } impl ArrayLen<'_> { - pub fn hir_id(&self) -> HirId { + pub fn span(self) -> Span { match self { - ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(ConstArg { hir_id, .. }) => { - *hir_id + ArrayLen::Infer(arg) => arg.span, + ArrayLen::Body(body) => body.span(), + } + } + + pub fn hir_id(self) -> HirId { + match self { + ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(&ConstArg { hir_id, .. }) => { + hir_id } } } @@ -1713,7 +1734,7 @@ impl Expr<'_> { ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node), ExprKind::Unary(..) => ExprPrecedence::Unary, ExprKind::Lit(_) => ExprPrecedence::Lit, - ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, + ExprKind::Cast(..) => ExprPrecedence::Cast, ExprKind::DropTemps(ref expr, ..) => expr.precedence(), ExprKind::If(..) => ExprPrecedence::If, ExprKind::Let(..) => ExprPrecedence::Let, @@ -1731,11 +1752,12 @@ impl Expr<'_> { ExprKind::Continue(..) => ExprPrecedence::Continue, ExprKind::Ret(..) => ExprPrecedence::Ret, ExprKind::Become(..) => ExprPrecedence::Become, - ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm, - ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf, ExprKind::Struct(..) => ExprPrecedence::Struct, ExprKind::Repeat(..) => ExprPrecedence::Repeat, ExprKind::Yield(..) => ExprPrecedence::Yield, + ExprKind::Type(..) | ExprKind::InlineAsm(..) | ExprKind::OffsetOf(..) => { + ExprPrecedence::Mac + } ExprKind::Err(_) => ExprPrecedence::Err, } } @@ -2574,10 +2596,10 @@ impl<'hir> Ty<'hir> { fn visit_ty(&mut self, t: &'v Ty<'v>) { if matches!( &t.kind, - TyKind::Path(QPath::Resolved( - _, - Path { res: crate::def::Res::SelfTyAlias { .. }, .. }, - )) + TyKind::Path(QPath::Resolved(_, Path { + res: crate::def::Res::SelfTyAlias { .. }, + .. + },)) ) { self.0.push(t.span); return; @@ -2905,15 +2927,17 @@ impl<'hir> InlineAsmOperand<'hir> { } pub fn is_clobber(&self) -> bool { - matches!( - self, - InlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(_), late: _, expr: None } - ) + matches!(self, InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(_), + late: _, + expr: None + }) } } #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct InlineAsm<'hir> { + pub asm_macro: ast::AsmMacro, pub template: &'hir [InlineAsmTemplatePiece], pub template_strs: &'hir [(Symbol, Option, Span)], pub operands: &'hir [(InlineAsmOperand<'hir>, Span)], diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index f2142359935b9..3fa06620ea8d1 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -2,10 +2,10 @@ use std::fmt::{self, Debug}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; -use rustc_span::def_id::DefPathHash; use rustc_span::HashStableContext; +use rustc_span::def_id::DefPathHash; -use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID}; +use crate::def_id::{CRATE_DEF_ID, DefId, DefIndex, LocalDefId}; #[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] pub struct OwnerId { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index a54596e3088dc..4da3224578519 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -64,11 +64,11 @@ //! This order consistency is required in a few places in rustc, for //! example coroutine inference, and possibly also HIR borrowck. -use rustc_ast::visit::{try_visit, visit_opt, walk_list, VisitorResult}; +use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list}; use rustc_ast::{Attribute, Label}; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::Span; use crate::hir::*; diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index e7398fd222636..b161e6ba0fa51 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -11,8 +11,8 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; -use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, kw, sym}; use crate::def_id::DefId; use crate::{MethodKind, Target}; @@ -45,7 +45,16 @@ impl LanguageItems { pub fn set(&mut self, item: LangItem, def_id: DefId) { self.items[item as usize] = Some(def_id); - self.reverse_items.insert(def_id, item); + let preexisting = self.reverse_items.insert(def_id, item); + + // This needs to be a bijection. + if let Some(preexisting) = preexisting { + panic!( + "For the bijection of LangItem <=> DefId to work,\ + one item DefId may only be assigned one LangItem. \ + Separate the LangItem definitions for {item:?} and {preexisting:?}." + ); + } } pub fn from_def_id(&self, def_id: DefId) -> Option { diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 73d1ea4070795..2ebbb4a06b6bf 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -1,7 +1,7 @@ use std::iter::Enumerate; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::{DefId, DefIdSet}; diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index f43008eda1181..155270ca6a7c2 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -7,7 +7,7 @@ use std::fmt::{self, Display}; use crate::def::DefKind; -use crate::{hir, Item, ItemKind, TraitItem, TraitItemKind}; +use crate::{Item, ItemKind, TraitItem, TraitItemKind, hir}; #[derive(Copy, Clone, PartialEq, Debug)] pub enum GenericParamKind { diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index 16b3c4a9ab691..5c10fa4697156 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -1,7 +1,7 @@ use rustc_data_structures::stable_hasher::Hash64; use rustc_span::def_id::{DefPathHash, StableCrateId}; use rustc_span::edition::Edition; -use rustc_span::{create_session_globals_then, Symbol}; +use rustc_span::{Symbol, create_session_globals_then}; use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData}; diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index ca133c5965dd0..337859cd1fbb1 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -1,6 +1,6 @@ //! Validity checking for weak lang items -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use crate::LangItem; diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index bde94be6f514e..09d466339ff6f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got} hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here -hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters +hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters .suggestion = use a fully qualified path with inferred lifetimes hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes @@ -48,6 +48,8 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found} +hir_analysis_bad_return_type_notation_position = return type notation not allowed in this position yet + hir_analysis_cannot_capture_late_bound_const = cannot capture late-bound const parameter in {$what} .label = parameter defined here @@ -467,25 +469,6 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]` .label = `#[start]` function is not allowed to be `#[track_caller]` -hir_analysis_static_mut_ref = creating a {$shared} reference to a mutable static - .label = {$shared} reference to mutable static - .note = {$shared -> - [shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - *[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior - } - .suggestion = use `addr_of!` instead to create a raw pointer - .suggestion_mut = use `addr_of_mut!` instead to create a raw pointer - -hir_analysis_static_mut_refs_lint = creating a {$shared} reference to mutable static is discouraged - .label = {$shared} reference to mutable static - .suggestion = use `addr_of!` instead to create a raw pointer - .suggestion_mut = use `addr_of_mut!` instead to create a raw pointer - .note = this will be a hard error in the 2024 edition - .why_note = {$shared -> - [shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - *[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior - } - hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature @@ -497,7 +480,7 @@ hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`, bu hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]` -hir_analysis_too_large_static = extern static is too large for the current architecture +hir_analysis_too_large_static = extern static is too large for the target architecture hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]` .suggestion = remove this annotation diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 46a0d4f498aa9..8d11328743c7e 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -1,8 +1,8 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Limit; -use rustc_span::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_span::Span; +use rustc_span::def_id::{LOCAL_CRATE, LocalDefId}; use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument}; diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index d0b0c08aa798b..caf9960741d71 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -2,12 +2,14 @@ //! [`rustc_middle::ty`] form. use rustc_data_structures::fx::FxIndexMap; -use rustc_hir::def::DefKind; use rustc_hir::LangItem; +use rustc_hir::def::DefKind; use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; -use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_span::def_id::DefId; + +use crate::hir_ty_lowering::OnlySelfBounds; /// Collects together a list of type bounds. These lists of bounds occur in many places /// in Rust's syntax: @@ -50,6 +52,7 @@ impl<'tcx> Bounds<'tcx> { span: Span, polarity: ty::PredicatePolarity, constness: ty::BoundConstness, + only_self_bounds: OnlySelfBounds, ) { let clause = ( bound_trait_ref @@ -66,7 +69,10 @@ impl<'tcx> Bounds<'tcx> { self.clauses.push(clause); } - if !tcx.features().effects { + // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else. + // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated + // type bounds. + if !tcx.features().effects || only_self_bounds.0 { return; } // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the @@ -106,14 +112,11 @@ impl<'tcx> Bounds<'tcx> { // This should work for any bound variables as long as they don't have any // bounds e.g. `for`. // FIXME(effects) reconsider this approach to allow compatibility with `for` - let ty = tcx.replace_bound_vars_uncached( - ty, - FnMutDelegate { - regions: &mut |_| tcx.lifetimes.re_static, - types: &mut |_| tcx.types.unit, - consts: &mut |_| unimplemented!("`~const` does not support const binders"), - }, - ); + let ty = tcx.replace_bound_vars_uncached(ty, FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_static, + types: &mut |_| tcx.types.unit, + consts: &mut |_| unimplemented!("`~const` does not support const binders"), + }); self.effects_min_tys.insert(ty, span); return; @@ -146,11 +149,11 @@ impl<'tcx> Bounds<'tcx> { }; let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args); // make `::Effects: Compat` - let new_trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), - [ty::GenericArg::from(self_ty), compat_val.into()], - ); + let new_trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), [ + ty::GenericArg::from(self_ty), + compat_val.into(), + ]); self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span)); } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e47c707ee18d9..d725772a5b369 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2,10 +2,10 @@ use std::cell::LazyCell; use std::ops::ControlFlow; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_errors::codes::*; use rustc_errors::MultiSpan; -use rustc_hir::def::{CtorKind, DefKind}; +use rustc_errors::codes::*; use rustc_hir::Node; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; @@ -22,8 +22,8 @@ use rustc_middle::ty::{ }; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_target::abi::FieldIdx; -use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_type_ir::fold::TypeFoldable; @@ -1064,20 +1064,29 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); return; } - let e = fields[FieldIdx::ZERO].ty(tcx, args); - if !fields.iter().all(|f| f.ty(tcx, args) == e) { - struct_span_code_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous") - .with_span_label(sp, "SIMD elements must have the same type") + + let array_field = &fields[FieldIdx::ZERO]; + let array_ty = array_field.ty(tcx, args); + let ty::Array(element_ty, len_const) = array_ty.kind() else { + struct_span_code_err!( + tcx.dcx(), + sp, + E0076, + "SIMD vector's only field must be an array" + ) + .with_span_label(tcx.def_span(array_field.did), "not an array") + .emit(); + return; + }; + + if let Some(second_field) = fields.get(FieldIdx::from_u32(1)) { + struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields") + .with_span_label(tcx.def_span(second_field.did), "excess field") .emit(); return; } - let len = if let ty::Array(_ty, c) = e.kind() { - c.try_eval_target_usize(tcx, tcx.param_env(def.did())) - } else { - Some(fields.len() as u64) - }; - if let Some(len) = len { + if let Some(len) = len_const.try_eval_target_usize(tcx, tcx.param_env(def.did())) { if len == 0 { struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); return; @@ -1097,16 +1106,9 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { // These are scalar types which directly match a "machine" type // Yes: Integers, floats, "thin" pointers // No: char, "fat" pointers, compound types - match e.kind() { - ty::Param(_) => (), // pass struct(T, T, T, T) through, let monomorphization catch errors - ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct(u8, u8, u8, u8) is ok - ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct([T; N]) through, let monomorphization catch errors - ty::Array(t, _clen) - if matches!( - t.kind(), - ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) - ) => - { /* struct([f32; 4]) is ok */ } + match element_ty.kind() { + ty::Param(_) => (), // pass struct([T; 4]) through, let monomorphization catch errors + ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok _ => { struct_span_code_err!( tcx.dcx(), @@ -1149,42 +1151,40 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { "type has conflicting packed and align representation hints" ) .emit(); - } else { - if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) { - let mut err = struct_span_code_err!( - tcx.dcx(), - sp, - E0588, - "packed type cannot transitively contain a `#[repr(align)]` type" - ); + } else if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) { + let mut err = struct_span_code_err!( + tcx.dcx(), + sp, + E0588, + "packed type cannot transitively contain a `#[repr(align)]` type" + ); - err.span_note( - tcx.def_span(def_spans[0].0), - format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)), - ); + err.span_note( + tcx.def_span(def_spans[0].0), + format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)), + ); - if def_spans.len() > 2 { - let mut first = true; - for (adt_def, span) in def_spans.iter().skip(1).rev() { - let ident = tcx.item_name(*adt_def); - err.span_note( - *span, - if first { - format!( - "`{}` contains a field of type `{}`", - tcx.type_of(def.did()).instantiate_identity(), - ident - ) - } else { - format!("...which contains a field of type `{ident}`") - }, - ); - first = false; - } + if def_spans.len() > 2 { + let mut first = true; + for (adt_def, span) in def_spans.iter().skip(1).rev() { + let ident = tcx.item_name(*adt_def); + err.span_note( + *span, + if first { + format!( + "`{}` contains a field of type `{}`", + tcx.type_of(def.did()).instantiate_identity(), + ident + ) + } else { + format!("...which contains a field of type `{ident}`") + }, + ); + first = false; } - - err.emit(); } + + err.emit(); } } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 2afed04c5bcd5..9ca5f25447b3e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -5,10 +5,10 @@ use std::iter; use hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; +use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{intravisit, GenericParamKind, ImplItemKind}; +use rustc_hir::{GenericParamKind, ImplItemKind, intravisit}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; @@ -176,15 +176,12 @@ fn compare_method_predicate_entailment<'tcx>( // obligations. let impl_m_def_id = impl_m.def_id.expect_local(); let impl_m_span = tcx.def_span(impl_m_def_id); - let cause = ObligationCause::new( - impl_m_span, - impl_m_def_id, - ObligationCauseCode::CompareImplItem { + let cause = + ObligationCause::new(impl_m_span, impl_m_def_id, ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, - }, - ); + }); // Create mapping from impl to placeholder. let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id); @@ -237,15 +234,12 @@ fn compare_method_predicate_entailment<'tcx>( let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); let predicate = ocx.normalize(&normalize_cause, param_env, predicate); - let cause = ObligationCause::new( - span, - impl_m_def_id, - ObligationCauseCode::CompareImplItem { + let cause = + ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, - }, - ); + }); ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); } @@ -465,15 +459,12 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); - let cause = ObligationCause::new( - return_span, - impl_m_def_id, - ObligationCauseCode::CompareImplItem { + let cause = + ObligationCause::new(return_span, impl_m_def_id, ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, - }, - ); + }); // Create mapping from impl to placeholder. let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id); @@ -561,16 +552,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( idx += 1; ( ty, - Ty::new_placeholder( - tcx, - ty::Placeholder { - universe, - bound: ty::BoundTy { - var: ty::BoundVar::from_usize(idx), - kind: ty::BoundTyKind::Anon, - }, + Ty::new_placeholder(tcx, ty::Placeholder { + universe, + bound: ty::BoundTy { + var: ty::BoundVar::from_usize(idx), + kind: ty::BoundTyKind::Anon, }, - ), + }), ) }) .collect(); @@ -726,7 +714,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( num_trait_args, num_impl_args, def_id, - impl_def_id: impl_m.container_id(tcx), + impl_m_def_id: impl_m.def_id, ty, return_span, }) { @@ -844,12 +832,18 @@ where struct RemapHiddenTyRegions<'tcx> { tcx: TyCtxt<'tcx>, + /// Map from early/late params of the impl to identity regions of the RPITIT (GAT) + /// in the trait. map: FxIndexMap, ty::Region<'tcx>>, num_trait_args: usize, num_impl_args: usize, + /// Def id of the RPITIT (GAT) in the *trait*. def_id: DefId, - impl_def_id: DefId, + /// Def id of the impl method which owns the opaque hidden type we're remapping. + impl_m_def_id: DefId, + /// The hidden type we're remapping. Useful for diagnostics. ty: Ty<'tcx>, + /// Span of the return type. Useful for diagnostics. return_span: Span, } @@ -885,8 +879,7 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { ty::ReLateParam(_) => {} // Remap early-bound regions as long as they don't come from the `impl` itself, // in which case we don't really need to renumber them. - ty::ReEarlyParam(ebr) - if ebr.index >= self.tcx.generics_of(self.impl_def_id).count() as u32 => {} + ty::ReEarlyParam(ebr) if ebr.index as usize >= self.num_impl_args => {} _ => return Ok(region), } @@ -899,7 +892,7 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { ); } } else { - let guar = match region.opt_param_def_id(self.tcx, self.tcx.parent(self.def_id)) { + let guar = match region.opt_param_def_id(self.tcx, self.impl_m_def_id) { Some(def_id) => { let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() { self.tcx.def_span(opaque_ty.def_id) @@ -931,13 +924,10 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { return Err(guar); }; - Ok(ty::Region::new_early_param( - self.tcx, - ty::EarlyParamRegion { - name: e.name, - index: (e.index as usize - self.num_trait_args + self.num_impl_args) as u32, - }, - )) + Ok(ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion { + name: e.name, + index: (e.index as usize - self.num_trait_args + self.num_impl_args) as u32, + })) } } @@ -1038,7 +1028,7 @@ fn report_trait_method_mismatch<'tcx>( false, ); - return diag.emit(); + diag.emit() } fn check_region_bounds_on_impl_item<'tcx>( @@ -1927,15 +1917,12 @@ fn compare_type_predicate_entailment<'tcx>( let cause = ObligationCause::misc(span, impl_ty_def_id); let predicate = ocx.normalize(&cause, param_env, predicate); - let cause = ObligationCause::new( - span, - impl_ty_def_id, - ObligationCauseCode::CompareImplItem { + let cause = + ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_ty.def_id.expect_local(), trait_item_def_id: trait_ty.def_id, kind: impl_ty.kind, - }, - ); + }); ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); } @@ -2173,25 +2160,20 @@ fn param_env_with_gat_bounds<'tcx>( let kind = ty::BoundTyKind::Param(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Ty(kind); bound_vars.push(bound_var); - Ty::new_bound( - tcx, - ty::INNERMOST, - ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) + Ty::new_bound(tcx, ty::INNERMOST, ty::BoundTy { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }) .into() } GenericParamDefKind::Lifetime => { let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind, - }, - ) + ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }) .into() } GenericParamDefKind::Const { .. } => { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index d2b7ede65234f..e07b587508a68 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE}; use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, Reveal}; @@ -13,7 +13,7 @@ use rustc_middle::ty::{ use rustc_span::Span; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt; -use rustc_trait_selection::traits::{elaborate, normalize_param_env_or_error, ObligationCtxt}; +use rustc_trait_selection::traits::{ObligationCtxt, elaborate, normalize_param_env_or_error}; /// Check that an implementation does not refine an RPITIT from a trait method signature. pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index d173915e480b0..97a29b32c0158 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; +use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 83d2c2c1e285f..7da2cd93d4e01 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -6,9 +6,9 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::EntryFnType; -use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; +use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index 22d7d1fea9cb4..64307407b73e3 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -79,11 +79,10 @@ fn handle_static_mut_ref( } else { (errors::MutRefSugg::Shared { lo, hi }, "shared") }; - tcx.emit_node_span_lint( - STATIC_MUT_REFS, - hir_id, + tcx.emit_node_span_lint(STATIC_MUT_REFS, hir_id, span, errors::RefOfMutStatic { span, - errors::RefOfMutStatic { span, sugg, shared }, - ); + sugg, + shared, + }); } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index c2b2f08132ed8..25e219ef3f23a 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -2,7 +2,7 @@ //! intrinsics that the compiler exposes. use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, DiagMessage}; +use rustc_errors::{DiagMessage, struct_span_code_err}; use rustc_hir as hir; use rustc_middle::bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; @@ -190,16 +190,14 @@ pub fn check_intrinsic_type( ]); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { - let region = ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon }, - ); - let env_region = ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_u32(2), kind: ty::BrEnv }, - ); + let region = ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::ZERO, + kind: ty::BrAnon, + }); + let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::from_u32(2), + kind: ty::BrEnv, + }); let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]); (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) }) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 3d5a22fce85af..71eb368185eb8 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -6,8 +6,8 @@ use rustc_hir::{self as hir, LangItem}; use rustc_middle::bug; use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; -use rustc_span::def_id::LocalDefId; use rustc_span::Symbol; +use rustc_span::def_id::LocalDefId; use rustc_target::abi::FieldIdx; use rustc_target::asm::{ InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 6820a44f141bd..d3d88919d8795 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -66,7 +66,6 @@ mod check; mod compare_impl_item; pub mod dropck; mod entry; -mod errs; pub mod intrinsic; pub mod intrinsicck; mod region; @@ -76,7 +75,7 @@ use std::num::NonZero; pub use check::check_abi; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::{pluralize, struct_span_code_err, Diag, ErrorGuaranteed}; +use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; @@ -89,13 +88,13 @@ use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span, Symbol, DUMMY_SP}; +use rustc_span::symbol::{Ident, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; -use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::ObligationCtxt; use tracing::debug; @@ -186,17 +185,15 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) && alloc.inner().provenance().ptrs().len() != 0 - { - if attrs + && attrs .link_section .map(|link_section| !link_section.as_str().starts_with(".init_array")) .unwrap() - { - let msg = "statics with a custom `#[link_section]` must be a \ + { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.dcx().span_err(tcx.def_span(id), msg); - } + tcx.dcx().span_err(tcx.def_span(id), msg); } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 2d6147cff2a5a..1a5f465981287 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -20,8 +20,6 @@ use rustc_middle::ty::TyCtxt; use rustc_span::source_map; use tracing::debug; -use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut}; - #[derive(Debug, Copy, Clone)] struct Context { /// The scope that contains any new variables declared, plus its depth in @@ -229,8 +227,6 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h let stmt_id = stmt.hir_id.local_id; debug!("resolve_stmt(stmt.id={:?})", stmt_id); - maybe_stmt_static_mut(visitor.tcx, *stmt); - // Every statement will clean up the temporaries created during // execution of that statement. Therefore each statement has an // associated destruction scope that represents the scope of the @@ -249,8 +245,6 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) { debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr); - maybe_expr_static_mut(visitor.tcx, *expr); - let prev_cx = visitor.cx; visitor.enter_node_scope_with_dtor(expr.hir_id.local_id); @@ -472,7 +466,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, Some(otherwise)) => { let expr_cx = visitor.cx; - visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen }); + let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { + ScopeData::IfThenRescope + } else { + ScopeData::IfThen + }; + visitor.enter_scope(Scope { id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); visitor.visit_expr(then); @@ -482,7 +481,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, None) => { let expr_cx = visitor.cx; - visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen }); + let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { + ScopeData::IfThenRescope + } else { + ScopeData::IfThen + }; + visitor.enter_scope(Scope { id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); visitor.visit_expr(then); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 359b4729e50a6..f8a19e93a4128 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -4,11 +4,11 @@ use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::codes::*; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; +use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; +use rustc_hir::ItemKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_macros::LintDiagnostic; @@ -21,27 +21,27 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; -use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, sym}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::misc::{ - type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError, + ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty, }; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, }; -use rustc_type_ir::solve::NoSolution; use rustc_type_ir::TypeFlags; +use rustc_type_ir::solve::NoSolution; use tracing::{debug, instrument}; use {rustc_ast as ast, rustc_hir as hir}; use crate::autoderef::Autoderef; use crate::collect::CollectItemTypesVisitor; -use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; +use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; use crate::{errors, fluent_generated as fluent}; pub(super) struct WfCheckingCtxt<'a, 'tcx> { @@ -664,10 +664,10 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( // Same for the region. In our example, 'a corresponds // to the 'me parameter. let region_param = gat_generics.param_at(*region_a_idx, tcx); - let region_param = ty::Region::new_early_param( - tcx, - ty::EarlyParamRegion { index: region_param.index, name: region_param.name }, - ); + let region_param = ty::Region::new_early_param(tcx, ty::EarlyParamRegion { + index: region_param.index, + name: region_param.name, + }); // The predicate we expect to see. (In our example, // `Self: 'me`.) bounds.insert( @@ -693,16 +693,16 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. let region_a_param = gat_generics.param_at(*region_a_idx, tcx); - let region_a_param = ty::Region::new_early_param( - tcx, - ty::EarlyParamRegion { index: region_a_param.index, name: region_a_param.name }, - ); + let region_a_param = ty::Region::new_early_param(tcx, ty::EarlyParamRegion { + index: region_a_param.index, + name: region_a_param.name, + }); // Same for the region. let region_b_param = gat_generics.param_at(*region_b_idx, tcx); - let region_b_param = ty::Region::new_early_param( - tcx, - ty::EarlyParamRegion { index: region_b_param.index, name: region_b_param.name }, - ); + let region_b_param = ty::Region::new_early_param(tcx, ty::EarlyParamRegion { + index: region_b_param.index, + name: region_b_param.name, + }); // The predicate we expect to see. bounds.insert( ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( @@ -1016,7 +1016,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), sym::adt_const_params, )]) } - // Implments `ConstParamTy`, suggest adding the feature to enable. + // Implements `ConstParamTy`, suggest adding the feature to enable. Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]), }; if let Some(features) = may_suggest_feature { @@ -1602,7 +1602,7 @@ fn check_fn_or_method<'tcx>( function: def_id, // Note that the `param_idx` of the output type is // one greater than the index of the last input type. - param_idx: idx.try_into().unwrap(), + param_idx: idx, }), ty, ) @@ -1611,7 +1611,7 @@ fn check_fn_or_method<'tcx>( for (idx, ty) in sig.inputs_and_output.iter().enumerate() { wfcx.register_wf_obligation( arg_span(idx), - Some(WellFormedLoc::Param { function: def_id, param_idx: idx.try_into().unwrap() }), + Some(WellFormedLoc::Param { function: def_id, param_idx: idx }), ty.into(), ); } @@ -1652,6 +1652,13 @@ fn check_fn_or_method<'tcx>( } } +/// The `arbitrary_self_types_pointers` feature implies `arbitrary_self_types`. +#[derive(Clone, Copy, PartialEq)] +enum ArbitrarySelfTypesLevel { + Basic, // just arbitrary_self_types + WithPointers, // both arbitrary_self_types and arbitrary_self_types_pointers +} + #[instrument(level = "debug", skip(wfcx))] fn check_method_receiver<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, @@ -1684,14 +1691,27 @@ fn check_method_receiver<'tcx>( return Ok(()); } - if tcx.features().arbitrary_self_types { - if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { - // Report error; `arbitrary_self_types` was enabled. - return Err(tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })); - } + let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers { + Some(ArbitrarySelfTypesLevel::WithPointers) + } else if tcx.features().arbitrary_self_types { + Some(ArbitrarySelfTypesLevel::Basic) } else { - if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) { - return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { + None + }; + + if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) { + return Err(match arbitrary_self_types_level { + // Wherever possible, emit a message advising folks that the features + // `arbitrary_self_types` or `arbitrary_self_types_pointers` might + // have helped. + None if receiver_is_valid( + wfcx, + span, + receiver_ty, + self_ty, + Some(ArbitrarySelfTypesLevel::Basic), + ) => + { // Report error; would have worked with `arbitrary_self_types`. feature_err( &tcx.sess, @@ -1699,25 +1719,49 @@ fn check_method_receiver<'tcx>( span, format!( "`{receiver_ty}` cannot be used as the type of `self` without \ - the `arbitrary_self_types` feature", + the `arbitrary_self_types` feature", ), ) .with_help(fluent::hir_analysis_invalid_receiver_ty_help) .emit() - } else { - // Report error; would not have worked with `arbitrary_self_types`. + } + None | Some(ArbitrarySelfTypesLevel::Basic) + if receiver_is_valid( + wfcx, + span, + receiver_ty, + self_ty, + Some(ArbitrarySelfTypesLevel::WithPointers), + ) => + { + // Report error; would have worked with `arbitrary_self_types_pointers`. + feature_err( + &tcx.sess, + sym::arbitrary_self_types_pointers, + span, + format!( + "`{receiver_ty}` cannot be used as the type of `self` without \ + the `arbitrary_self_types_pointers` feature", + ), + ) + .with_help(fluent::hir_analysis_invalid_receiver_ty_help) + .emit() + } + _ => + // Report error; would not have worked with `arbitrary_self_types[_pointers]`. + { tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) - }); - } + } + }); } Ok(()) } /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly -/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more -/// strict: `receiver_ty` must implement `Receiver` and directly implement -/// `Deref`. +/// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled. +/// If neither feature is enabled, the requirements are more strict: `receiver_ty` must implement +/// `Receiver` and directly implement `Deref`. /// /// N.B., there are cases this function returns `true` but causes an error to be emitted, /// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the @@ -1727,7 +1771,7 @@ fn receiver_is_valid<'tcx>( span: Span, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, - arbitrary_self_types_enabled: bool, + arbitrary_self_types_enabled: Option, ) -> bool { let infcx = wfcx.infcx; let tcx = wfcx.tcx(); @@ -1745,8 +1789,8 @@ fn receiver_is_valid<'tcx>( let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); - // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`. - if arbitrary_self_types_enabled { + // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`. + if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) { autoderef = autoderef.include_raw_pointers(); } @@ -1772,7 +1816,7 @@ fn receiver_is_valid<'tcx>( // Without `feature(arbitrary_self_types)`, we require that each step in the // deref chain implement `receiver`. - if !arbitrary_self_types_enabled { + if arbitrary_self_types_enabled.is_none() { if !receiver_is_implemented( wfcx, receiver_trait_def_id, diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 9f01f7be80af4..bea8d28a9f756 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -7,20 +7,20 @@ use std::collections::BTreeMap; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; +use rustc_hir::ItemKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_params}; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::misc::{ - type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy, ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason, + type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy, }; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt}; use tracing::debug; @@ -219,7 +219,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw // pointers. This is enforced here: we only allow impls for references, raw pointers, and things // that are effectively repr(transparent) newtypes around types that already hav a - // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those tpyes since some + // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those types since some // of them support an allocator, but we ensure that for the cases where the type implements this // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent) @@ -274,7 +274,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() return false; } - return true; + true }) .collect::>(); @@ -309,11 +309,10 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() tcx, cause.clone(), param_env, - ty::TraitRef::new( - tcx, - dispatch_from_dyn_trait, - [field.ty(tcx, args_a), field.ty(tcx, args_b)], - ), + ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ + field.ty(tcx, args_a), + field.ty(tcx, args_b), + ]), )); } let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index bd8b43e28e540..dfb3c088afb0c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -11,10 +11,10 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; -use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams}; +use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; -use rustc_span::symbol::sym; use rustc_span::ErrorGuaranteed; +use rustc_span::symbol::sym; use crate::errors; @@ -22,36 +22,38 @@ use crate::errors; pub(crate) fn crate_inherent_impls( tcx: TyCtxt<'_>, (): (), -) -> Result<&'_ CrateInherentImpls, ErrorGuaranteed> { +) -> (&'_ CrateInherentImpls, Result<(), ErrorGuaranteed>) { let mut collect = InherentCollect { tcx, impls_map: Default::default() }; + let mut res = Ok(()); for id in tcx.hir().items() { res = res.and(collect.check_item(id)); } - res?; - Ok(tcx.arena.alloc(collect.impls_map)) + + (tcx.arena.alloc(collect.impls_map), res) } -pub(crate) fn crate_incoherent_impls( +pub(crate) fn crate_inherent_impls_validity_check( tcx: TyCtxt<'_>, - simp: SimplifiedType, -) -> Result<&[DefId], ErrorGuaranteed> { - let crate_map = tcx.crate_inherent_impls(())?; - Ok(tcx.arena.alloc_from_iter( + (): (), +) -> Result<(), ErrorGuaranteed> { + tcx.crate_inherent_impls(()).1 +} + +pub(crate) fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { + let (crate_map, _) = tcx.crate_inherent_impls(()); + tcx.arena.alloc_from_iter( crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()), - )) + ) } /// On-demand query: yields a vector of the inherent impls for a specific type. -pub(crate) fn inherent_impls( - tcx: TyCtxt<'_>, - ty_def_id: LocalDefId, -) -> Result<&[DefId], ErrorGuaranteed> { - let crate_map = tcx.crate_inherent_impls(())?; - Ok(match crate_map.inherent_impls.get(&ty_def_id) { +pub(crate) fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] { + let (crate_map, _) = tcx.crate_inherent_impls(()); + match crate_map.inherent_impls.get(&ty_def_id) { Some(v) => &v[..], None => &[], - }) + } } struct InherentCollect<'tcx> { @@ -93,7 +95,8 @@ impl<'tcx> InherentCollect<'tcx> { } } - if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) { + if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer) + { self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); } else { bug!("unexpected self type: {:?}", self_ty); @@ -132,7 +135,7 @@ impl<'tcx> InherentCollect<'tcx> { } } - if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) { + if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::InstantiateWithInfer) { self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); } else { bug!("unexpected primitive type: {:?}", ty); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 6825c2e33fe71..b8066b4b47d90 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -177,8 +177,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { return Ok(()); } - let impls = self.tcx.inherent_impls(id.owner_id)?; - + let impls = self.tcx.inherent_impls(id.owner_id); let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id()); let impls_items = impls @@ -252,13 +251,10 @@ impl<'tcx> InherentOverlapChecker<'tcx> { for ident in &idents_to_add { connected_region_ids.insert(*ident, id_to_set); } - connected_regions.insert( - id_to_set, - ConnectedRegion { - idents: idents_to_add, - impl_blocks: std::iter::once(i).collect(), - }, - ); + connected_regions.insert(id_to_set, ConnectedRegion { + idents: idents_to_add, + impl_blocks: std::iter::once(i).collect(), + }); } // Take the only id inside the list &[id_to_set] => { diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index db809e4837d66..b25406583f6c4 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -7,12 +7,12 @@ use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; -use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::LangItem; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_session::parse::feature_err; -use rustc_span::{sym, ErrorGuaranteed}; +use rustc_span::{ErrorGuaranteed, sym}; use tracing::debug; use crate::errors; @@ -53,17 +53,15 @@ fn enforce_trait_manually_implementable( ) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); - if tcx.is_lang_item(trait_def_id, LangItem::Freeze) { - if !tcx.features().freeze_impls { - feature_err( - &tcx.sess, - sym::freeze_impls, - impl_header_span, - "explicit impls for the `Freeze` trait are not permitted", - ) - .with_span_label(impl_header_span, format!("impl of `Freeze` not allowed")) - .emit(); - } + if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls { + feature_err( + &tcx.sess, + sym::freeze_impls, + impl_header_span, + "explicit impls for the `Freeze` trait are not permitted", + ) + .with_span_label(impl_header_span, format!("impl of `Freeze` not allowed")) + .emit(); } // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` @@ -126,7 +124,10 @@ fn enforce_empty_impls_for_marker_traits( pub(crate) fn provide(providers: &mut Providers) { use self::builtin::coerce_unsized_info; - use self::inherent_impls::{crate_incoherent_impls, crate_inherent_impls, inherent_impls}; + use self::inherent_impls::{ + crate_incoherent_impls, crate_inherent_impls, crate_inherent_impls_validity_check, + inherent_impls, + }; use self::inherent_impls_overlap::crate_inherent_impls_overlap_check; use self::orphan::orphan_check_impl; @@ -135,6 +136,7 @@ pub(crate) fn provide(providers: &mut Providers) { crate_inherent_impls, crate_incoherent_impls, inherent_impls, + crate_inherent_impls_validity_check, crate_inherent_impls_overlap_check, coerce_unsized_info, orphan_check_impl, diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 7513f680271e3..d66114a50d78b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -4,11 +4,11 @@ use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir::Safety; -use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::ImplPolarity::*; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ImplTraitHeader, TraitDef, TyCtxt}; -use rustc_span::def_id::LocalDefId; use rustc_span::ErrorGuaranteed; +use rustc_span::def_id::LocalDefId; pub(super) fn check_item( tcx: TyCtxt<'_>, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 53105f337c4a8..93b021be24584 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -23,11 +23,11 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ - struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, StashKey, E0228, + Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, walk_generics, Visitor}; +use rustc_hir::intravisit::{self, Visitor, walk_generics}; use rustc_hir::{self as hir, GenericParamKind, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; @@ -36,8 +36,8 @@ use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::abi; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; @@ -460,7 +460,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { [] => (generics.span, format!("<{lt_name}>")), [bound, ..] => (bound.span.shrink_to_lo(), format!("{lt_name}, ")), }; - mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { + mpart_sugg = Some(errors::AssociatedItemTraitUninferredGenericParamsMultipartSuggestion { fspan: lt_sp, first: sugg, sspan: span.with_hi(item_segment.ident.span.lo()), @@ -502,11 +502,12 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } Ty::new_error( self.tcx(), - self.tcx().dcx().emit_err(errors::AssociatedTypeTraitUninferredGenericParams { + self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams { span, inferred_sugg, bound, mpart_sugg, + what: "type", }), ) } @@ -1037,7 +1038,7 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> { /// Check the uniqueness of fields in a struct variant, and recursively /// check the nested fields if it is an unnamed field with type of an - /// annoymous adt. + /// anonymous adt. fn check_field(&mut self, field: &hir::FieldDef<'_>) { if field.ident.name != kw::Underscore { self.check_field_decl(field.ident, field.span.into()); @@ -1491,7 +1492,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( Some(ty) => { let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; // Typeck doesn't expect erased regions to be returned from `type_of`. - // This is a heuristic approach. If the scope has region paramters, + // This is a heuristic approach. If the scope has region parameters, // we should change fn_sig's lifetime from `ReErased` to `ReError`, // otherwise to `ReStatic`. let has_region_params = generics.params.iter().any(|param| match param.kind { @@ -1698,8 +1699,6 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> ty::Generics { let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); + if let Some(sig) = node.fn_sig() + && let Some(sig_id) = sig.decl.opt_delegation_sig_id() + { + return inherit_generics_for_delegation_item(tcx, def_id, sig_id); + } + let parent_def_id = match node { Node::ImplItem(_) | Node::TraitItem(_) @@ -229,16 +235,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // inherit the generics of the item. Some(parent.to_def_id()) } - ItemKind::Fn(sig, _, _) => { - // For a delegation item inherit generics from callee. - if let Some(sig_id) = sig.decl.opt_delegation_sig_id() - && let Some(generics) = - inherit_generics_for_delegation_item(tcx, def_id, sig_id) - { - return generics; - } - None - } _ => None, }, _ => None, diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d62727e76b586..7557219aaa693 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -1,16 +1,18 @@ -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::util; +use rustc_middle::ty::fold::shift_vars; use rustc_middle::ty::{ - self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_type_ir::Upcast; use tracing::{debug, instrument}; use super::ItemCtxt; +use super::predicates_of::assert_only_contains_predicates_from; use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter}; /// For associated types we include both bounds written on the type @@ -41,14 +43,18 @@ fn associated_type_bounds<'tcx>( let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { - match pred.kind().skip_binder() { - ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty, - ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty() == item_ty, - ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty, - _ => false, - } - }); + let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); + let bounds_from_parent = + trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| { + remap_gat_vars_and_recurse_into_nested_projections( + tcx, + filter, + item_trait_ref, + assoc_item_def_id, + span, + clause, + ) + }); let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent)); debug!( @@ -56,9 +62,232 @@ fn associated_type_bounds<'tcx>( tcx.def_path_str(assoc_item_def_id.to_def_id()), all_bounds ); + + assert_only_contains_predicates_from(filter, all_bounds, item_ty); + all_bounds } +/// The code below is quite involved, so let me explain. +/// +/// We loop here, because we also want to collect vars for nested associated items as +/// well. For example, given a clause like `Self::A::B`, we want to add that to the +/// item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is +/// rigid. +/// +/// Secondly, regarding bound vars, when we see a where clause that mentions a GAT +/// like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into +/// an item bound on the GAT, where all of the GAT args are substituted with the GAT's +/// param regions, and then keep all of the other late-bound vars in the bound around. +/// We need to "compress" the binder so that it doesn't mention any of those vars that +/// were mapped to params. +fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( + tcx: TyCtxt<'tcx>, + filter: PredicateFilter, + item_trait_ref: ty::TraitRef<'tcx>, + assoc_item_def_id: LocalDefId, + span: Span, + clause: ty::Clause<'tcx>, +) -> Option<(ty::Clause<'tcx>, Span)> { + let mut clause_ty = match clause.kind().skip_binder() { + ty::ClauseKind::Trait(tr) => tr.self_ty(), + ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(), + ty::ClauseKind::TypeOutlives(outlives) => outlives.0, + _ => return None, + }; + + let gat_vars = loop { + if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() { + if alias_ty.trait_ref(tcx) == item_trait_ref + && alias_ty.def_id == assoc_item_def_id.to_def_id() + { + // We have found the GAT in question... + // Return the vars, since we may need to remap them. + break &alias_ty.args[item_trait_ref.args.len()..]; + } else { + // Only collect *self* type bounds if the filter is for self. + match filter { + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + return None; + } + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {} + } + + clause_ty = alias_ty.self_ty(); + continue; + } + } + + return None; + }; + + // Special-case: No GAT vars, no mapping needed. + if gat_vars.is_empty() { + return Some((clause, span)); + } + + // First, check that all of the GAT args are substituted with a unique late-bound arg. + // If we find a duplicate, then it can't be mapped to the definition's params. + let mut mapping = FxIndexMap::default(); + let generics = tcx.generics_of(assoc_item_def_id); + for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { + let existing = match var.unpack() { + ty::GenericArgKind::Lifetime(re) => { + if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() { + mapping.insert(bv.var, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + ty::GenericArgKind::Type(ty) => { + if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() { + mapping.insert(bv.var, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + ty::GenericArgKind::Const(ct) => { + if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() { + mapping.insert(bv, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + }; + + if existing.is_some() { + return None; + } + } + + // Finally, map all of the args in the GAT to the params we expect, and compress + // the remaining late-bound vars so that they count up from var 0. + let mut folder = + MapAndCompressBoundVars { tcx, binder: ty::INNERMOST, still_bound_vars: vec![], mapping }; + let pred = clause.kind().skip_binder().fold_with(&mut folder); + + Some(( + ty::Binder::bind_with_vars(pred, tcx.mk_bound_variable_kinds(&folder.still_bound_vars)) + .upcast(tcx), + span, + )) +} + +/// Given some where clause like `for<'b, 'c> >::Gat<'b>: Bound<'c>`, +/// the mapping will map `'b` back to the GAT's `'b_identity`. Then we need to compress the +/// remaining bound var `'c` to index 0. +/// +/// This folder gives us: `for<'c> >::Gat<'b_identity>: Bound<'c>`, +/// which is sufficient for an item bound for `Gat`, since all of the GAT's args are identity. +struct MapAndCompressBoundVars<'tcx> { + tcx: TyCtxt<'tcx>, + /// How deep are we? Makes sure we don't touch the vars of nested binders. + binder: ty::DebruijnIndex, + /// List of bound vars that remain unsubstituted because they were not + /// mentioned in the GAT's args. + still_bound_vars: Vec, + /// Subtle invariant: If the `GenericArg` is bound, then it should be + /// stored with the debruijn index of `INNERMOST` so it can be shifted + /// correctly during substitution. + mapping: FxIndexMap>, +} + +impl<'tcx> TypeFolder> for MapAndCompressBoundVars<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_binder(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> + where + ty::Binder<'tcx, T>: TypeSuperFoldable>, + { + self.binder.shift_in(1); + let out = t.super_fold_with(self); + self.binder.shift_out(1); + out + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !ty.has_bound_vars() { + return ty; + } + + if let ty::Bound(binder, old_bound) = *ty.kind() + && self.binder == binder + { + let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { + mapped.expect_ty() + } else { + // If we didn't find a mapped generic, then make a new one. + // Allocate a new var idx, and insert a new bound ty. + let var = ty::BoundVar::from_usize(self.still_bound_vars.len()); + self.still_bound_vars.push(ty::BoundVariableKind::Ty(old_bound.kind)); + let mapped = Ty::new_bound(self.tcx, ty::INNERMOST, ty::BoundTy { + var, + kind: old_bound.kind, + }); + self.mapping.insert(old_bound.var, mapped.into()); + mapped + }; + + shift_vars(self.tcx, mapped, self.binder.as_u32()) + } else { + ty.super_fold_with(self) + } + } + + fn fold_region(&mut self, re: ty::Region<'tcx>) -> ty::Region<'tcx> { + if let ty::ReBound(binder, old_bound) = re.kind() + && self.binder == binder + { + let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { + mapped.expect_region() + } else { + let var = ty::BoundVar::from_usize(self.still_bound_vars.len()); + self.still_bound_vars.push(ty::BoundVariableKind::Region(old_bound.kind)); + let mapped = ty::Region::new_bound(self.tcx, ty::INNERMOST, ty::BoundRegion { + var, + kind: old_bound.kind, + }); + self.mapping.insert(old_bound.var, mapped.into()); + mapped + }; + + shift_vars(self.tcx, mapped, self.binder.as_u32()) + } else { + re + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if !ct.has_bound_vars() { + return ct; + } + + if let ty::ConstKind::Bound(binder, old_var) = ct.kind() + && self.binder == binder + { + let mapped = if let Some(mapped) = self.mapping.get(&old_var) { + mapped.expect_const() + } else { + let var = ty::BoundVar::from_usize(self.still_bound_vars.len()); + self.still_bound_vars.push(ty::BoundVariableKind::Const); + let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, var); + self.mapping.insert(old_var, mapped.into()); + mapped + }; + + shift_vars(self.tcx, mapped, self.binder.as_u32()) + } else { + ct.super_fold_with(self) + } + } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if !p.has_bound_vars() { p } else { p.super_fold_with(self) } + } +} + /// Opaque types don't inherit bounds from their parent: for return position /// impl trait it isn't possible to write a suitable predicate on the /// containing function and for type-alias impl trait we don't have a backwards @@ -108,18 +337,21 @@ pub(super) fn explicit_item_bounds_with_filter( Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return ty::EarlyBinder::bind(opaque_type_bounds( + let item_ty = Ty::new_projection_from_args( + tcx, + def_id.to_def_id(), + ty::GenericArgs::identity_for_item(tcx, def_id), + ); + let bounds = opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, - Ty::new_projection_from_args( - tcx, - def_id.to_def_id(), - ty::GenericArgs::identity_for_item(tcx, def_id), - ), + item_ty, item.span, filter, - )); + ); + assert_only_contains_predicates_from(filter, bounds, item_ty); + return ty::EarlyBinder::bind(bounds); } Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!( tcx.def_span(def_id), @@ -167,7 +399,9 @@ pub(super) fn explicit_item_bounds_with_filter( }) => { let args = GenericArgs::identity_for_item(tcx, def_id); let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) + let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter); + assert_only_contains_predicates_from(filter, bounds, item_ty); + bounds } // Since RPITITs are lowered as projections in `::lower_ty`, when we're // asking for the item bounds of the *opaques* in a trait's default method signature, we @@ -184,15 +418,18 @@ pub(super) fn explicit_item_bounds_with_filter( }; let args = GenericArgs::identity_for_item(tcx, def_id); let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - tcx.arena.alloc_slice( + let bounds = &*tcx.arena.alloc_slice( &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) .to_vec() .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }), - ) + ); + assert_only_contains_predicates_from(filter, bounds, item_ty); + bounds } hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], _ => bug!("item_bounds called on {:?}", def_id), }; + ty::EarlyBinder::bind(bounds) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a47aaf25e95a8..9e9704622052f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -9,7 +9,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Ident; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; use crate::bounds::Bounds; @@ -138,6 +138,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); + if let Some(sig) = node.fn_sig() + && let Some(sig_id) = sig.decl.opt_delegation_sig_id() + { + return inherit_predicates_for_delegation_item(tcx, def_id, sig_id); + } + let mut is_trait = None; let mut is_default_impl_trait = None; @@ -164,16 +170,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => { is_trait = Some(self_bounds); } - - ItemKind::Fn(sig, _, _) => { - // For a delegation item inherit predicates from callee. - if let Some(sig_id) = sig.decl.opt_delegation_sig_id() - && let Some(predicates) = - inherit_predicates_for_delegation_item(tcx, def_id, sig_id) - { - return predicates; - } - } _ => {} } }; @@ -244,7 +240,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen for predicate in hir_generics.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { - let ty = icx.lower_ty(bound_pred.bounded_ty); + let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty); + let bound_vars = tcx.late_bound_vars(bound_pred.hir_id); // Keep the type around in a dummy predicate, in case of no bounds. // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` @@ -382,10 +379,10 @@ fn compute_bidirectional_outlives_predicates<'tcx>( for param in opaque_own_params { let orig_lifetime = tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()); if let ty::ReEarlyParam(..) = *orig_lifetime { - let dup_lifetime = ty::Region::new_early_param( - tcx, - ty::EarlyParamRegion { index: param.index, name: param.name }, - ); + let dup_lifetime = ty::Region::new_early_param(tcx, ty::EarlyParamRegion { + index: param.index, + name: param.name, + }); let span = tcx.def_span(param.def_id); predicates.push(( ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_lifetime, dup_lifetime)) @@ -680,9 +677,63 @@ pub(super) fn implied_predicates_with_filter<'tcx>( _ => {} } + assert_only_contains_predicates_from(filter, implied_bounds, tcx.types.self_param); + ty::EarlyBinder::bind(implied_bounds) } +// Make sure when elaborating supertraits, probing for associated types, etc., +// we really truly are elaborating clauses that have `Self` as their self type. +// This is very important since downstream code relies on this being correct. +pub(super) fn assert_only_contains_predicates_from<'tcx>( + filter: PredicateFilter, + bounds: &'tcx [(ty::Clause<'tcx>, Span)], + ty: Ty<'tcx>, +) { + if !cfg!(debug_assertions) { + return; + } + + match filter { + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + for (clause, _) in bounds { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) => { + assert_eq!( + trait_predicate.self_ty(), + ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + ty::ClauseKind::Projection(projection_predicate) => { + assert_eq!( + projection_predicate.self_ty(), + ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + ty::ClauseKind::TypeOutlives(outlives_predicate) => { + assert_eq!( + outlives_predicate.0, ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(_, _) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => { + bug!( + "unexpected non-`Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + } + } + } + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {} + } +} + /// Returns the predicates defined on `item_def_id` of the form /// `X: Foo` where `X` is the type parameter `def_id`. #[instrument(level = "trace", skip(tcx))] @@ -774,6 +825,10 @@ impl<'tcx> ItemCtxt<'tcx> { continue; }; + // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we + // want to only consider predicates with `Self: ...`, but we don't want + // `OnlySelfBounds(true)` since we want to collect the nested associated + // type bound as well. let (only_self_bounds, assoc_name) = match filter { PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { (OnlySelfBounds(false), None) @@ -784,14 +839,10 @@ impl<'tcx> ItemCtxt<'tcx> { } }; - // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we - // want to only consider predicates with `Self: ...`, but we don't want - // `OnlySelfBounds(true)` since we want to collect the nested associated - // type bound as well. let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) { ty } else if matches!(filter, PredicateFilter::All) { - self.lower_ty(predicate.bounded_ty) + self.lowerer().lower_ty_maybe_return_type_notation(predicate.bounded_ty) } else { continue; }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index fe46eb583f1df..c9b949ad88d54 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -21,9 +21,9 @@ use rustc_middle::middle::resolve_bound_vars::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::symbol::{Ident, sym}; use tracing::{debug, debug_span, instrument}; use crate::errors; @@ -584,7 +584,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | Res::SelfTyParam { trait_: def_id } => { self.resolve_type_ref(def_id.expect_local(), param.hir_id); } - Res::Err => {} Res::SelfTyAlias { alias_to, .. } => { self.tcx.dcx().emit_err(errors::PreciseCaptureSelfAlias { span: param.ident.span, @@ -593,11 +592,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }); } res => { - self.tcx.dcx().emit_err(errors::BadPreciseCapture { - span: param.ident.span, - kind: "type or const", - found: res.descr().to_string(), - }); + self.tcx.dcx().span_delayed_bug( + param.ident.span, + format!("expected type or const param, found {res:?}"), + ); } }, } @@ -891,7 +889,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { (pair, r) }) .unzip(); + self.record_late_bound_vars(hir_id, binders); + + // If this is an RTN type in the self type, then append those to the binder. + self.try_append_return_type_notation_params(hir_id, bounded_ty); + // Even if there are no lifetimes defined here, we still wrap it in a binder // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth @@ -1191,23 +1194,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { (generics.span, "<'a>".to_owned()) }; - let lifetime_sugg = match lifetime_ref.suggestion_position() { - (hir::LifetimeSuggestionPosition::Normal, span) => { - (span, "'a".to_owned()) - } - (hir::LifetimeSuggestionPosition::Ampersand, span) => { - (span, "'a ".to_owned()) - } - (hir::LifetimeSuggestionPosition::ElidedPath, span) => { - (span, "<'a>".to_owned()) - } - (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => { - (span, "'a, ".to_owned()) - } - (hir::LifetimeSuggestionPosition::ObjectDefault, span) => { - (span, "+ 'a".to_owned()) - } - }; + let lifetime_sugg = lifetime_ref.suggestion("'a"); let suggestions = vec![lifetime_sugg, new_param_sugg]; diag.span_label( @@ -1653,9 +1640,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // } // ``` // and a bound that looks like: - // `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>` + // `for<'a> T::Trait<'a, x(..): for<'b> Other<'b>>` // this is going to expand to something like: - // `for<'a> for<'r, T> >::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. + // `for<'a> for<'r> >::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { let bound_vars = if let Some(type_def_id) = type_def_id @@ -1743,7 +1730,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { ) }; - use smallvec::{smallvec, SmallVec}; + use smallvec::{SmallVec, smallvec}; let mut stack: SmallVec<[(DefId, SmallVec<[ty::BoundVariableKind; 8]>); 8]> = smallvec![(def_id, smallvec![])]; let mut visited: FxHashSet = FxHashSet::default(); @@ -1857,6 +1844,178 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id); assert_eq!(old_value, Some(bad_def)); } + + // When we have a return type notation type in a where clause, like + // `where ::method(..): Send`, we need to introduce new bound + // vars to the existing where clause's binder, to represent the lifetimes + // elided by the return-type-notation syntax. + // + // For example, given + // ``` + // trait Foo { + // async fn x<'r>(); + // } + // ``` + // and a bound that looks like: + // `for<'a, 'b> >::x(): Other<'b>` + // this is going to expand to something like: + // `for<'a, 'b, 'r> >::x::<'r, T>::{opaque#0}: Other<'b>`. + // + // We handle this similarly for associated-type-bound style return-type-notation + // in `visit_segment_args`. + fn try_append_return_type_notation_params( + &mut self, + hir_id: HirId, + hir_ty: &'tcx hir::Ty<'tcx>, + ) { + let hir::TyKind::Path(qpath) = hir_ty.kind else { + // We only care about path types here. All other self types + // (including nesting the RTN type in another type) don't do + // anything. + return; + }; + + let (mut bound_vars, item_def_id, item_segment) = match qpath { + // If we have a fully qualified method, then we don't need to do any special lookup. + hir::QPath::Resolved(_, path) + if let [.., item_segment] = &path.segments[..] + && item_segment.args.is_some_and(|args| { + matches!( + args.parenthesized, + hir::GenericArgsParentheses::ReturnTypeNotation + ) + }) => + { + match path.res { + Res::Err => return, + Res::Def(DefKind::AssocFn, item_def_id) => (vec![], item_def_id, item_segment), + _ => bug!("only expected method resolution for fully qualified RTN"), + } + } + + // If we have a type-dependent path, then we do need to do some lookup. + hir::QPath::TypeRelative(qself, item_segment) + if item_segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + // First, ignore a qself that isn't a type or `Self` param. Those are the + // only ones that support `T::Assoc` anyways in HIR lowering. + let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind else { + return; + }; + match path.res { + Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => { + // Get the generics of this type's hir owner. This is *different* + // from the generics of the parameter's definition, since we want + // to be able to resolve an RTN path on a nested body (e.g. method + // inside an impl) using the where clauses on the method. + // FIXME(return_type_notation): Think of some better way of doing this. + let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics() + else { + return; + }; + + // Look for the first bound that contains an associated type that + // matches the segment that we're looking for. We ignore any subsequent + // bounds since we'll be emitting a hard error in HIR lowering, so this + // is purely speculative. + let one_bound = generics.predicates.iter().find_map(|predicate| { + let hir::WherePredicate::BoundPredicate(predicate) = predicate else { + return None; + }; + let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = + predicate.bounded_ty.kind + else { + return None; + }; + if bounded_path.res != path.res { + return None; + } + predicate.bounds.iter().find_map(|bound| { + let hir::GenericBound::Trait(trait_, _) = bound else { + return None; + }; + BoundVarContext::supertrait_hrtb_vars( + self.tcx, + trait_.trait_ref.trait_def_id()?, + item_segment.ident, + ty::AssocKind::Fn, + ) + }) + }); + let Some((bound_vars, assoc_item)) = one_bound else { + return; + }; + (bound_vars, assoc_item.def_id, item_segment) + } + // If we have a self type alias (in an impl), try to resolve an + // associated item from one of the supertraits of the impl's trait. + Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. } => { + let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = self + .tcx + .hir_node_by_def_id(impl_def_id.expect_local()) + .expect_item() + .kind + else { + return; + }; + let Some(trait_def_id) = trait_ref.trait_def_id() else { + return; + }; + let Some((bound_vars, assoc_item)) = BoundVarContext::supertrait_hrtb_vars( + self.tcx, + trait_def_id, + item_segment.ident, + ty::AssocKind::Fn, + ) else { + return; + }; + (bound_vars, assoc_item.def_id, item_segment) + } + _ => return, + } + } + + _ => return, + }; + + // Append the early-bound vars on the function, and then the late-bound ones. + // We actually turn type parameters into higher-ranked types here, but we + // deny them later in HIR lowering. + bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| { + match param.kind { + ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( + ty::BoundRegionKind::BrNamed(param.def_id, param.name), + ), + ty::GenericParamDefKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) + } + ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, + } + })); + bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars()); + + // SUBTLE: Stash the old bound vars onto the *item segment* before appending + // the new bound vars. We do this because we need to know how many bound vars + // are present on the binder explicitly (i.e. not return-type-notation vars) + // to do bound var shifting correctly in HIR lowering. + // + // For example, in `where for<'a> >::method(..): Other`, + // the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's + // parent) will include `'a` AND all the early- and late-bound vars of the + // method. But when lowering the RTN type, we just want the list of vars + // we used to resolve the trait ref. We explicitly stored those back onto + // the item segment, since there's no other good place to put them. + // + // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`. + // And this is exercised in: + // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`. + let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap(); + let existing_bound_vars_saved = existing_bound_vars.clone(); + existing_bound_vars.extend(bound_vars); + self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved); + } } /// Detects late-bound lifetimes and inserts them into diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 5cb90e97eefe0..48b5e87cbd033 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -1,19 +1,19 @@ use core::ops::ControlFlow; -use rustc_errors::{Applicability, StashKey}; +use rustc_errors::{Applicability, StashKey, Suggestions}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::HirId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Ident; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use tracing::debug; -use super::{bad_placeholder, ItemCtxt}; +use super::{ItemCtxt, bad_placeholder}; use crate::errors::TypeofReservedKeywordUsed; use crate::hir_ty_lowering::HirTyLowerer; @@ -670,7 +670,7 @@ fn infer_placeholder_type<'tcx>( // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. // We are typeck and have the real type, so remove that and suggest the actual type. - if let Ok(suggestions) = &mut err.suggestions { + if let Suggestions::Enabled(suggestions) = &mut err.suggestions { suggestions.clear(); } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 7f4a8208faaed..fcea0052546f5 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -2,7 +2,7 @@ use rustc_errors::StashKey; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; +use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; @@ -381,24 +381,22 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( } mir_opaque_ty.ty + } else if let Some(guar) = tables.tainted_by_errors { + // Some error in the owner fn prevented us from populating + // the `concrete_opaque_types` table. + Ty::new_error(tcx, guar) } else { - if let Some(guar) = tables.tainted_by_errors { - // Some error in the owner fn prevented us from populating - // the `concrete_opaque_types` table. - Ty::new_error(tcx, guar) + // Fall back to the RPIT we inferred during HIR typeck + if let Some(hir_opaque_ty) = hir_opaque_ty { + hir_opaque_ty.ty } else { - // Fall back to the RPIT we inferred during HIR typeck - if let Some(hir_opaque_ty) = hir_opaque_ty { - hir_opaque_ty.ty - } else { - // We failed to resolve the opaque type or it - // resolves to itself. We interpret this as the - // no values of the hidden type ever being constructed, - // so we can just make the hidden type be `!`. - // For backwards compatibility reasons, we fall back to - // `()` until we the diverging default is changed. - Ty::new_diverging_default(tcx) - } + // We failed to resolve the opaque type or it + // resolves to itself. We interpret this as the + // no values of the hidden type ever being constructed, + // so we can just make the hidden type be `!`. + // For backwards compatibility reasons, we fall back to + // `()` until we the diverging default is changed. + Ty::new_diverging_default(tcx) } } } diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 20aaa43219f34..1ccb7faaf3053 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -1,3 +1,7 @@ +//! Support inheriting generic parameters and predicates for function delegation. +//! +//! For more information about delegation design, see the tracking issue #118212. + use std::assert_matches::debug_assert_matches; use rustc_data_structures::fx::FxHashMap; @@ -5,7 +9,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::ErrorGuaranteed; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_type_ir::visit::TypeVisitableExt; type RemapTable = FxHashMap; @@ -37,10 +41,10 @@ impl<'tcx> TypeFolder> for ParamIndexRemapper<'tcx> { if let ty::ReEarlyParam(param) = r.kind() && let Some(index) = self.remap_table.get(¶m.index).copied() { - return ty::Region::new_early_param( - self.tcx, - ty::EarlyParamRegion { index, name: param.name }, - ); + return ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion { + index, + name: param.name, + }); } r } @@ -76,127 +80,381 @@ fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind { } } +/// Given the current context(caller and callee `FnKind`), it specifies +/// the policy of predicates and generic parameters inheritance. +#[derive(Clone, Copy, Debug, PartialEq)] +enum InheritanceKind { + /// Copying all predicates and parameters, including those of the parent + /// container. + /// + /// Boolean value defines whether the `Self` parameter or `Self: Trait` + /// predicate are copied. It's always equal to `false` except when + /// delegating from a free function to a trait method. + /// + /// FIXME(fn_delegation): This often leads to type inference + /// errors. Support providing generic arguments or restrict use sites. + WithParent(bool), + /// The trait implementation should be compatible with the original trait. + /// Therefore, for trait implementations only the method's own parameters + /// and predicates are copied. + Own, +} + +struct GenericsBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + sig_id: DefId, + parent: Option, + inh_kind: InheritanceKind, +} + +impl<'tcx> GenericsBuilder<'tcx> { + fn new(tcx: TyCtxt<'tcx>, sig_id: DefId) -> GenericsBuilder<'tcx> { + GenericsBuilder { tcx, sig_id, parent: None, inh_kind: InheritanceKind::WithParent(false) } + } + + fn with_parent(mut self, parent: DefId) -> Self { + self.parent = Some(parent); + self + } + + fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self { + self.inh_kind = inh_kind; + self + } + + fn build(self) -> ty::Generics { + let mut own_params = vec![]; + + let sig_generics = self.tcx.generics_of(self.sig_id); + if let InheritanceKind::WithParent(has_self) = self.inh_kind + && let Some(parent_def_id) = sig_generics.parent + { + let sig_parent_generics = self.tcx.generics_of(parent_def_id); + own_params.append(&mut sig_parent_generics.own_params.clone()); + if !has_self { + own_params.remove(0); + } + } + own_params.append(&mut sig_generics.own_params.clone()); + + // Lifetime parameters must be declared before type and const parameters. + // Therefore, When delegating from a free function to a associated function, + // generic parameters need to be reordered: + // + // trait Trait<'a, A> { + // fn foo<'b, B>(...) {...} + // } + // + // reuse Trait::foo; + // desugaring: + // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) { + // Trait::foo(...) + // } + own_params.sort_by_key(|key| key.kind.is_ty_or_const()); + + let param_def_id_to_index = + own_params.iter().map(|param| (param.def_id, param.index)).collect(); + + let (parent_count, has_self) = if let Some(def_id) = self.parent { + let parent_generics = self.tcx.generics_of(def_id); + let parent_kind = self.tcx.def_kind(def_id); + (parent_generics.count(), parent_kind == DefKind::Trait) + } else { + (0, false) + }; + + for (idx, param) in own_params.iter_mut().enumerate() { + param.index = (idx + parent_count) as u32; + // FIXME(fn_delegation): Default parameters are not inherited, because they are + // not permitted in functions. Therefore, there are 2 options here: + // + // - We can create non-default generic parameters. + // - We can substitute default parameters into the signature. + // + // At the moment, first option has been selected as the most general. + if let ty::GenericParamDefKind::Type { has_default, .. } + | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind + { + *has_default = false; + } + } + + ty::Generics { + parent: self.parent, + parent_count, + own_params, + param_def_id_to_index, + has_self, + has_late_bound_regions: sig_generics.has_late_bound_regions, + host_effect_index: sig_generics.host_effect_index, + } + } +} + +struct PredicatesBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + sig_id: DefId, + parent: Option, + inh_kind: InheritanceKind, + args: ty::GenericArgsRef<'tcx>, +} + +impl<'tcx> PredicatesBuilder<'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + args: ty::GenericArgsRef<'tcx>, + sig_id: DefId, + ) -> PredicatesBuilder<'tcx> { + PredicatesBuilder { + tcx, + sig_id, + parent: None, + inh_kind: InheritanceKind::WithParent(false), + args, + } + } + + fn with_parent(mut self, parent: DefId) -> Self { + self.parent = Some(parent); + self + } + + fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self { + self.inh_kind = inh_kind; + self + } + + fn build(self) -> ty::GenericPredicates<'tcx> { + struct PredicatesCollector<'tcx> { + tcx: TyCtxt<'tcx>, + preds: Vec<(ty::Clause<'tcx>, Span)>, + args: ty::GenericArgsRef<'tcx>, + } + + impl<'tcx> PredicatesCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> { + PredicatesCollector { tcx, preds: vec![], args } + } + + fn with_own_preds( + mut self, + f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>, + def_id: DefId, + ) -> Self { + let preds = f(def_id).instantiate_own(self.tcx, self.args); + self.preds.extend(preds); + self + } + + fn with_preds( + mut self, + f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy, + def_id: DefId, + ) -> Self { + let preds = f(def_id); + if let Some(parent_def_id) = preds.parent { + self = self.with_own_preds(f, parent_def_id); + } + self.with_own_preds(f, def_id) + } + } + let collector = PredicatesCollector::new(self.tcx, self.args); + + // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate. + // Note: `predicates_of` query can also add inferred outlives predicates, but that + // is not the case here as `sig_id` is either a trait or a function. + let preds = match self.inh_kind { + InheritanceKind::WithParent(false) => { + collector.with_preds(|def_id| self.tcx.explicit_predicates_of(def_id), self.sig_id) + } + InheritanceKind::WithParent(true) => { + collector.with_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id) + } + InheritanceKind::Own => { + collector.with_own_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id) + } + } + .preds; + + ty::GenericPredicates { + parent: self.parent, + predicates: self.tcx.arena.alloc_from_iter(preds), + // FIXME(fn_delegation): Support effects. + effects_min_tys: ty::List::empty(), + } + } +} + +struct GenericArgsBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + remap_table: RemapTable, + sig_id: DefId, + def_id: LocalDefId, +} + +impl<'tcx> GenericArgsBuilder<'tcx> { + fn new(tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId) -> GenericArgsBuilder<'tcx> { + GenericArgsBuilder { tcx, remap_table: FxHashMap::default(), sig_id, def_id } + } + + fn build_from_args(mut self, args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> { + let caller_generics = self.tcx.generics_of(self.def_id); + let callee_generics = self.tcx.generics_of(self.sig_id); + + for caller_param in &caller_generics.own_params { + let callee_index = + callee_generics.param_def_id_to_index(self.tcx, caller_param.def_id).unwrap(); + self.remap_table.insert(callee_index, caller_param.index); + } + + let mut folder = ParamIndexRemapper { tcx: self.tcx, remap_table: self.remap_table }; + args.fold_with(&mut folder) + } +} + fn create_generic_args<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, ) -> ty::GenericArgsRef<'tcx> { - let caller_generics = tcx.generics_of(def_id); - let callee_generics = tcx.generics_of(sig_id); + let builder = GenericArgsBuilder::new(tcx, sig_id, def_id); let caller_kind = fn_kind(tcx, def_id.into()); let callee_kind = fn_kind(tcx, sig_id); - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. match (caller_kind, callee_kind) { - (FnKind::Free, _) => { - // Lifetime parameters must be declared before type and const parameters. - // Therefore, When delegating from a free function to a associated function, - // generic parameters need to be reordered: - // - // trait Trait<'a, A> { - // fn foo<'b, B>(...) {...} - // } - // - // reuse Trait::foo; - // desugaring: - // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) { - // Trait::foo(...) - // } - let mut remap_table = RemapTable::default(); - for caller_param in &caller_generics.own_params { - let callee_index = - callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap(); - remap_table.insert(callee_index, caller_param.index); - } - let mut folder = ParamIndexRemapper { tcx, remap_table }; - ty::GenericArgs::identity_for_item(tcx, sig_id).fold_with(&mut folder) + (FnKind::Free, FnKind::Free) + | (FnKind::Free, FnKind::AssocTrait) + | (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) + | (FnKind::AssocTrait, FnKind::AssocTrait) => { + let args = ty::GenericArgs::identity_for_item(tcx, sig_id); + builder.build_from_args(args) } - // FIXME(fn_delegation): Only `Self` param supported here. - (FnKind::AssocTraitImpl, FnKind::AssocTrait) - | (FnKind::AssocInherentImpl, FnKind::AssocTrait) => { + + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + let callee_generics = tcx.generics_of(sig_id); + let parent = tcx.parent(def_id.into()); + let parent_args = + tcx.impl_trait_header(parent).unwrap().trait_ref.instantiate_identity().args; + + let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id); + let method_args = tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count)); + let method_args = builder.build_from_args(method_args); + + tcx.mk_args_from_iter(parent_args.iter().chain(method_args)) + } + + (FnKind::AssocInherentImpl, FnKind::AssocTrait) => { let parent = tcx.parent(def_id.into()); let self_ty = tcx.type_of(parent).instantiate_identity(); let generic_self_ty = ty::GenericArg::from(self_ty); - tcx.mk_args_from_iter(std::iter::once(generic_self_ty)) + + let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id); + let trait_args = builder.build_from_args(trait_args); + + let args = std::iter::once(generic_self_ty).chain(trait_args.iter().skip(1)); + tcx.mk_args_from_iter(args) } - _ => ty::GenericArgs::identity_for_item(tcx, sig_id), + + // For trait impl's `sig_id` is always equal to the corresponding trait method. + (FnKind::AssocTraitImpl, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), } } +// FIXME(fn_delegation): Move generics inheritance to the AST->HIR lowering. +// For now, generic parameters are not propagated to the generated call, +// which leads to inference errors: +// +// fn foo(x: i32) {} +// +// reuse foo as bar; +// desugaring: +// fn bar() { +// foo::<_>() // ERROR: type annotations needed +// } pub(crate) fn inherit_generics_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, -) -> Option { - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. - if fn_kind(tcx, def_id.into()) != FnKind::Free { - return None; - } +) -> ty::Generics { + let builder = GenericsBuilder::new(tcx, sig_id); - let mut own_params = vec![]; - - let callee_generics = tcx.generics_of(sig_id); - if let Some(parent_sig_id) = callee_generics.parent { - let parent_sig_generics = tcx.generics_of(parent_sig_id); - own_params.append(&mut parent_sig_generics.own_params.clone()); - } - own_params.append(&mut callee_generics.own_params.clone()); + let caller_kind = fn_kind(tcx, def_id.into()); + let callee_kind = fn_kind(tcx, sig_id); + match (caller_kind, callee_kind) { + (FnKind::Free, FnKind::Free) + | (FnKind::Free, FnKind::AssocTrait) => builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build(), + + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .with_inheritance_kind(InheritanceKind::Own) + .build() + } - // Lifetimes go first. - own_params.sort_by_key(|key| key.kind.is_ty_or_const()); + (FnKind::AssocInherentImpl, FnKind::AssocTrait) + | (FnKind::AssocTrait, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() + } - for (idx, param) in own_params.iter_mut().enumerate() { - param.index = idx as u32; - // Default parameters are not inherited: they are not allowed - // in fn's. - if let ty::GenericParamDefKind::Type { has_default, .. } - | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind - { - *has_default = false; + (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() } - } - let param_def_id_to_index = - own_params.iter().map(|param| (param.def_id, param.index)).collect(); - - Some(ty::Generics { - parent: None, - parent_count: 0, - own_params, - param_def_id_to_index, - has_self: false, - has_late_bound_regions: callee_generics.has_late_bound_regions, - host_effect_index: callee_generics.host_effect_index, - }) + // For trait impl's `sig_id` is always equal to the corresponding trait method. + (FnKind::AssocTraitImpl, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), + } } pub(crate) fn inherit_predicates_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, -) -> Option> { - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. - if fn_kind(tcx, def_id.into()) != FnKind::Free { - return None; - } - - let callee_predicates = tcx.predicates_of(sig_id); +) -> ty::GenericPredicates<'tcx> { let args = create_generic_args(tcx, def_id, sig_id); + let builder = PredicatesBuilder::new(tcx, args, sig_id); - let mut preds = vec![]; - if let Some(parent_id) = callee_predicates.parent { - preds.extend(tcx.predicates_of(parent_id).instantiate_own(tcx, args)); - } - preds.extend(callee_predicates.instantiate_own(tcx, args)); + let caller_kind = fn_kind(tcx, def_id.into()); + let callee_kind = fn_kind(tcx, sig_id); + match (caller_kind, callee_kind) { + (FnKind::Free, FnKind::Free) + | (FnKind::Free, FnKind::AssocTrait) => { + builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build() + } + + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .with_inheritance_kind(InheritanceKind::Own) + .build() + } + + (FnKind::AssocInherentImpl, FnKind::AssocTrait) + | (FnKind::AssocTrait, FnKind::AssocTrait) + | (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() + } - Some(ty::GenericPredicates { - parent: None, - predicates: tcx.arena.alloc_from_iter(preds), - effects_min_tys: ty::List::empty(), - }) + // For trait impl's `sig_id` is always equal to the corresponding trait method. + (FnKind::AssocTraitImpl, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), + } } fn check_constraints<'tcx>( @@ -224,19 +482,6 @@ fn check_constraints<'tcx>( emit("recursive delegation is not supported yet"); } - if fn_kind(tcx, def_id.into()) != FnKind::Free { - let sig_generics = tcx.generics_of(sig_id); - let parent = tcx.parent(def_id.into()); - let parent_generics = tcx.generics_of(parent); - - let parent_has_self = parent_generics.has_self as usize; - let sig_has_self = sig_generics.has_self as usize; - - if sig_generics.count() > sig_has_self || parent_generics.count() > parent_has_self { - emit("early bound generics are not supported for associated delegation items"); - } - } - ret } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 39df18ff658cd..4edb68e61999e 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -780,14 +780,15 @@ pub(crate) struct PlaceholderNotAllowedItemSignatures { #[derive(Diagnostic)] #[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = E0212)] -pub(crate) struct AssociatedTypeTraitUninferredGenericParams { +pub(crate) struct AssociatedItemTraitUninferredGenericParams { #[primary_span] pub span: Span, #[suggestion(style = "verbose", applicability = "maybe-incorrect", code = "{bound}")] pub inferred_sugg: Option, pub bound: String, #[subdiagnostic] - pub mpart_sugg: Option, + pub mpart_sugg: Option, + pub what: &'static str, } #[derive(Subdiagnostic)] @@ -795,7 +796,7 @@ pub(crate) struct AssociatedTypeTraitUninferredGenericParams { hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion, applicability = "maybe-incorrect" )] -pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { +pub(crate) struct AssociatedItemTraitUninferredGenericParamsMultipartSuggestion { #[suggestion_part(code = "{first}")] pub fspan: Span, pub first: String, @@ -1522,57 +1523,6 @@ pub(crate) struct OnlyCurrentTraitsPointerSugg<'a> { pub ptr_ty: Ty<'a>, } -#[derive(Diagnostic)] -#[diag(hir_analysis_static_mut_ref, code = E0796)] -#[note] -pub(crate) struct StaticMutRef<'a> { - #[primary_span] - #[label] - pub span: Span, - #[subdiagnostic] - pub sugg: MutRefSugg, - pub shared: &'a str, -} - -#[derive(Subdiagnostic)] -pub(crate) enum MutRefSugg { - #[multipart_suggestion( - hir_analysis_suggestion, - style = "verbose", - applicability = "maybe-incorrect" - )] - Shared { - #[suggestion_part(code = "addr_of!(")] - lo: Span, - #[suggestion_part(code = ")")] - hi: Span, - }, - #[multipart_suggestion( - hir_analysis_suggestion_mut, - style = "verbose", - applicability = "maybe-incorrect" - )] - Mut { - #[suggestion_part(code = "addr_of_mut!(")] - lo: Span, - #[suggestion_part(code = ")")] - hi: Span, - }, -} - -// STATIC_MUT_REF lint -#[derive(LintDiagnostic)] -#[diag(hir_analysis_static_mut_refs_lint)] -#[note] -#[note(hir_analysis_why_note)] -pub(crate) struct RefOfMutStatic<'a> { - #[label] - pub span: Span, - #[subdiagnostic] - pub sugg: MutRefSugg, - pub shared: &'a str, -} - #[derive(Diagnostic)] #[diag(hir_analysis_not_supported_delegation)] pub(crate) struct UnsupportedDelegation<'a> { @@ -1744,3 +1694,10 @@ pub(crate) struct CmseCallGeneric { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_bad_return_type_notation_position)] +pub(crate) struct BadReturnTypeNotation { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs index af2bb053c0ab4..b6cffb90805b3 100644 --- a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs +++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs @@ -1,3 +1,4 @@ +use rustc_errors::E0799; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -43,7 +44,7 @@ pub(crate) struct BadPreciseCapture { } #[derive(Diagnostic)] -#[diag(hir_analysis_precise_capture_self_alias)] +#[diag(hir_analysis_precise_capture_self_alias, code = E0799)] pub(crate) struct PreciseCaptureSelfAlias { #[primary_span] pub span: Span, diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index da89f5769d1fc..5ae7944f6d53e 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -1,12 +1,12 @@ use std::iter; +use GenericArgsInfo::*; use rustc_errors::codes::*; -use rustc_errors::{pluralize, Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan}; +use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize}; use rustc_hir as hir; use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; use rustc_span::def_id::DefId; use tracing::debug; -use GenericArgsInfo::*; /// Handles the `wrong number of type / lifetime / ... arguments` family of error messages. pub(crate) struct WrongNumberOfGenericArgs<'a, 'tcx> { @@ -827,20 +827,18 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self + && let Some(span) = self.gen_args.span_ext() + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - if let Some(span) = self.gen_args.span_ext() - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) - { - let sugg = vec![ - ( - self.path_segment.ident.span, - format!("{}::{}", snippet, self.path_segment.ident), - ), - (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()), - ]; + let sugg = vec![ + ( + self.path_segment.ident.span, + format!("{}::{}", snippet, self.path_segment.ident), + ), + (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()), + ]; - err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); - } + err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); } } } @@ -1050,7 +1048,18 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { }, ); - err.span_suggestion(span, msg, "", Applicability::MaybeIncorrect); + if span.is_empty() { + // HACK: Avoid ICE when types with the same name with `derive`s are in the same scope: + // struct NotSM; + // #[derive(PartialEq, Eq)] + // struct NotSM(T); + // With the above code, the suggestion would be to remove the generics of the first + // `NotSM`, which doesn't *have* generics, so we would suggest to remove no code with + // no code, which would trigger an `assert!` later. Ideally, we would do something a + // bit more principled. See closed PR #109082. + } else { + err.span_suggestion(span, msg, "", Applicability::MaybeIncorrect); + } } else if redundant_lifetime_args && redundant_type_or_const_args { remove_lifetime_args(err); remove_type_or_const_args(err); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 70a3c744c78a2..45cd46e3df296 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -4,17 +4,19 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; +use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_span::symbol::Ident; -use rustc_span::{sym, ErrorGuaranteed, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use rustc_trait_selection::traits; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use smallvec::SmallVec; use tracing::{debug, instrument}; +use super::errors::GenericsArgsErrExtend; use crate::bounds::Bounds; use crate::errors; use crate::hir_ty_lowering::{ @@ -332,74 +334,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .or_insert(constraint.span); let projection_term = if let ty::AssocKind::Fn = assoc_kind { - let mut emitted_bad_param_err = None; - // If we have an method return type bound, then we need to instantiate - // the method's early bound params with suitable late-bound params. - let mut num_bound_vars = candidate.bound_vars().len(); - let args = - candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| { - let arg = match param.kind { - ty::GenericParamDefKind::Lifetime => ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), - }, - ) - .into(), - ty::GenericParamDefKind::Type { .. } => { - let guar = *emitted_bad_param_err.get_or_insert_with(|| { - self.dcx().emit_err( - crate::errors::ReturnTypeNotationIllegalParam::Type { - span: path_span, - param_span: tcx.def_span(param.def_id), - }, - ) - }); - Ty::new_error(tcx, guar).into() - } - ty::GenericParamDefKind::Const { .. } => { - let guar = *emitted_bad_param_err.get_or_insert_with(|| { - self.dcx().emit_err( - crate::errors::ReturnTypeNotationIllegalParam::Const { - span: path_span, - param_span: tcx.def_span(param.def_id), - }, - ) - }); - ty::Const::new_error(tcx, guar).into() - } - }; - num_bound_vars += 1; - arg - }); - - // Next, we need to check that the return-type notation is being used on - // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). - let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output(); - let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() - && tcx.is_impl_trait_in_trait(alias_ty.def_id) - { - alias_ty.into() - } else { - return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { - span: constraint.span, - ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), - fn_span: tcx.hir().span_if_local(assoc_item.def_id), - note: (), - })); - }; - - // Finally, move the fn return type's bound vars over to account for the early bound - // params (and trait ref's late bound params). This logic is very similar to - // `rustc_middle::ty::predicate::Clause::instantiate_supertrait` - // and it's no coincidence why. - let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args); - let bound_vars = tcx.late_bound_vars(constraint.hir_id); - ty::Binder::bind_with_vars(instantiation_output, bound_vars) + ty::Binder::bind_with_vars( + self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(), + bound_vars, + ) } else { // Create the generic arguments for the associated type or constant by joining the // parent arguments (the arguments of the trait) and the own arguments (the ones of @@ -525,11 +464,272 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Ok(()) } + + /// Lower a type, possibly specially handling the type if it's a return type notation + /// which we otherwise deny in other positions. + pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + let hir::TyKind::Path(qpath) = hir_ty.kind else { + return self.lower_ty(hir_ty); + }; + + let tcx = self.tcx(); + match qpath { + hir::QPath::Resolved(opt_self_ty, path) + if let [mod_segments @ .., trait_segment, item_segment] = &path.segments[..] + && item_segment.args.is_some_and(|args| { + matches!( + args.parenthesized, + hir::GenericArgsParentheses::ReturnTypeNotation + ) + }) => + { + // We don't allow generics on the module segments. + let _ = + self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None); + + let item_def_id = match path.res { + Res::Def(DefKind::AssocFn, item_def_id) => item_def_id, + Res::Err => { + return Ty::new_error_with_message( + tcx, + hir_ty.span, + "failed to resolve RTN", + ); + } + _ => bug!("only expected method resolution for fully qualified RTN"), + }; + let trait_def_id = tcx.parent(item_def_id); + + // Good error for `where Trait::method(..): Send`. + let Some(self_ty) = opt_self_ty else { + return self.error_missing_qpath_self_ty( + trait_def_id, + hir_ty.span, + item_segment, + ); + }; + let self_ty = self.lower_ty(self_ty); + + let trait_ref = self.lower_mono_trait_ref( + hir_ty.span, + trait_def_id, + self_ty, + trait_segment, + false, + ty::BoundConstness::NotConst, + ); + + // SUBTLE: As noted at the end of `try_append_return_type_notation_params` + // in `resolve_bound_vars`, we stash the explicit bound vars of the where + // clause onto the item segment of the RTN type. This allows us to know + // how many bound vars are *not* coming from the signature of the function + // from lowering RTN itself. + // + // For example, in `where for<'a> >::method(..): Other`, + // the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's + // parent) will include `'a` AND all the early- and late-bound vars of the + // method. But when lowering the RTN type, we just want the list of vars + // we used to resolve the trait ref. We explicitly stored those back onto + // the item segment, since there's no other good place to put them. + let candidate = + ty::Binder::bind_with_vars(trait_ref, tcx.late_bound_vars(item_segment.hir_id)); + + match self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) { + Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty), + Err(guar) => Ty::new_error(tcx, guar), + } + } + hir::QPath::TypeRelative(qself, item_segment) + if item_segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + match self + .resolve_type_relative_return_type_notation( + qself, + item_segment, + hir_ty.hir_id, + hir_ty.span, + ) + .and_then(|(candidate, item_def_id)| { + self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) + }) { + Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty), + Err(guar) => Ty::new_error(tcx, guar), + } + } + _ => self.lower_ty(hir_ty), + } + } + + /// Perform type-dependent lookup for a *method* for return type notation. + /// This generally mirrors `::lower_assoc_path`. + fn resolve_type_relative_return_type_notation( + &self, + qself: &'tcx hir::Ty<'tcx>, + item_segment: &'tcx hir::PathSegment<'tcx>, + qpath_hir_id: HirId, + span: Span, + ) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> { + let tcx = self.tcx(); + let qself_ty = self.lower_ty(qself); + let assoc_ident = item_segment.ident; + let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { + path.res + } else { + Res::Err + }; + + let bound = match (qself_ty.kind(), qself_res) { + (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => { + // `Self` in an impl of a trait -- we have a concrete self type and a + // trait reference. + let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { + // A cycle error occurred, most likely. + self.dcx().span_bug(span, "expected cycle error"); + }; + + self.probe_single_bound_for_assoc_item( + || { + traits::supertraits( + tcx, + ty::Binder::dummy(trait_ref.instantiate_identity()), + ) + }, + AssocItemQSelf::SelfTyAlias, + ty::AssocKind::Fn, + assoc_ident, + span, + None, + )? + } + ( + &ty::Param(_), + Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), + ) => self.probe_single_ty_param_bound_for_assoc_item( + param_did.expect_local(), + qself.span, + ty::AssocKind::Fn, + assoc_ident, + span, + )?, + _ => { + if let Err(reported) = qself_ty.error_reported() { + return Err(reported); + } else { + // FIXME(return_type_notation): Provide some structured suggestion here. + let err = struct_span_code_err!( + self.dcx(), + span, + E0223, + "ambiguous associated function" + ); + return Err(err.emit()); + } + } + }; + + // Don't let `T::method` resolve to some `for<'a> >::method`, + // which may happen via a higher-ranked where clause or supertrait. + // This is the same restrictions as associated types; even though we could + // support it, it just makes things a lot more difficult to support in + // `resolve_bound_vars`, since we'd need to introduce those as elided + // bound vars on the where clause too. + if bound.has_bound_vars() { + return Err(self.tcx().dcx().emit_err( + errors::AssociatedItemTraitUninferredGenericParams { + span, + inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())), + bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),), + mpart_sugg: None, + what: "function", + }, + )); + } + + let trait_def_id = bound.def_id(); + let assoc_ty = self + .probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id) + .expect("failed to find associated type"); + + Ok((bound, assoc_ty.def_id)) + } + + /// Do the common parts of lowering an RTN type. This involves extending the + /// candidate binder to include all of the early- and late-bound vars that are + /// defined on the function itself, and constructing a projection to the RPITIT + /// return type of that function. + fn lower_return_type_notation_ty( + &self, + candidate: ty::PolyTraitRef<'tcx>, + item_def_id: DefId, + path_span: Span, + ) -> Result, ErrorGuaranteed> { + let tcx = self.tcx(); + let mut emitted_bad_param_err = None; + // If we have an method return type bound, then we need to instantiate + // the method's early bound params with suitable late-bound params. + let mut num_bound_vars = candidate.bound_vars().len(); + let args = candidate.skip_binder().args.extend_to(tcx, item_def_id, |param, _| { + let arg = match param.kind { + ty::GenericParamDefKind::Lifetime => { + ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::from_usize(num_bound_vars), + kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), + }) + .into() + } + ty::GenericParamDefKind::Type { .. } => { + let guar = *emitted_bad_param_err.get_or_insert_with(|| { + self.dcx().emit_err(crate::errors::ReturnTypeNotationIllegalParam::Type { + span: path_span, + param_span: tcx.def_span(param.def_id), + }) + }); + Ty::new_error(tcx, guar).into() + } + ty::GenericParamDefKind::Const { .. } => { + let guar = *emitted_bad_param_err.get_or_insert_with(|| { + self.dcx().emit_err(crate::errors::ReturnTypeNotationIllegalParam::Const { + span: path_span, + param_span: tcx.def_span(param.def_id), + }) + }); + ty::Const::new_error(tcx, guar).into() + } + }; + num_bound_vars += 1; + arg + }); + + // Next, we need to check that the return-type notation is being used on + // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). + let output = tcx.fn_sig(item_def_id).skip_binder().output(); + let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() + && tcx.is_impl_trait_in_trait(alias_ty.def_id) + { + alias_ty + } else { + return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { + span: path_span, + ty: tcx.liberate_late_bound_regions(item_def_id, output), + fn_span: tcx.hir().span_if_local(item_def_id), + note: (), + })); + }; + + // Finally, move the fn return type's bound vars over to account for the early bound + // params (and trait ref's late bound params). This logic is very similar to + // `rustc_middle::ty::predicate::Clause::instantiate_supertrait` + // and it's no coincidence why. + let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); + Ok(ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args)) + } } /// Detect and reject early-bound & escaping late-bound generic params in the type of assoc const bindings. /// -/// FIXME(const_generics): This is a temporary and semi-artifical restriction until the +/// FIXME(const_generics): This is a temporary and semi-artificial restriction until the /// arrival of *generic const generics*[^1]. /// /// It might actually be possible that we can already support early-bound generic params diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 1b73cecd6664b..5150db7f51b19 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -72,8 +72,11 @@ fn is_valid_cmse_inputs<'tcx>( let mut span = None; let mut accum = 0u64; - for (index, arg_def) in fn_sig.inputs().iter().enumerate() { - let layout = tcx.layout_of(ParamEnv::reveal_all().and(*arg_def.skip_binder()))?; + // this type is only used for layout computation, which does not rely on regions + let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); + + for (index, ty) in fn_sig.inputs().iter().enumerate() { + let layout = tcx.layout_of(ParamEnv::reveal_all().and(*ty))?; let align = layout.layout.align().abi.bytes(); let size = layout.layout.size().bytes(); @@ -98,7 +101,10 @@ fn is_valid_cmse_output<'tcx>( tcx: TyCtxt<'tcx>, fn_sig: ty::PolyFnSig<'tcx>, ) -> Result> { - let mut ret_ty = fn_sig.output().skip_binder(); + // this type is only used for layout computation, which does not rely on regions + let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); + + let mut ret_ty = fn_sig.output(); let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?; let size = layout.layout.size().bytes(); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index af319fd53bde7..5775a8867b16a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, + Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -12,16 +12,16 @@ use rustc_middle::bug; use rustc_middle::query::Key; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; use rustc_middle::ty::{ - self, suggest_constraining_type_param, AdtDef, Binder, GenericParamDefKind, TraitRef, Ty, - TyCtxt, TypeVisitableExt, + self, AdtDef, Binder, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeVisitableExt, + suggest_constraining_type_param, }; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span, Symbol, DUMMY_SP}; +use rustc_span::symbol::{Ident, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; use rustc_trait_selection::error_reporting::traits::report_object_safety_error; use rustc_trait_selection::traits::{ - object_safety_violations_for_assoc_item, FulfillmentError, TraitAliasExpansionInfo, + FulfillmentError, TraitAliasExpansionInfo, object_safety_violations_for_assoc_item, }; use crate::errors::{ @@ -834,17 +834,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into_iter() .map(|(trait_, mut assocs)| { assocs.sort(); - format!( - "{} in `{trait_}`", - match &assocs[..] { - [] => String::new(), - [only] => format!("`{only}`"), - [assocs @ .., last] => format!( - "{} and `{last}`", - assocs.iter().map(|a| format!("`{a}`")).collect::>().join(", ") - ), - } - ) + format!("{} in `{trait_}`", match &assocs[..] { + [] => String::new(), + [only] => format!("`{only}`"), + [assocs @ .., last] => format!( + "{} and `{last}`", + assocs.iter().map(|a| format!("`{a}`")).collect::>().join(", ") + ), + }) }) .collect::>(); names.sort(); @@ -1031,7 +1028,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .. }) = node && let Some(ty_def_id) = qself_ty.ty_def_id() - && let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id) + && let [inherent_impl] = tcx.inherent_impls(ty_def_id) && let name = format!("{ident2}_{ident3}") && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx .associated_items(inherent_impl) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 8d5f98c7372e1..6e8a9ded4f370 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -1,10 +1,10 @@ use rustc_ast::ast::ParamKindOrd; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, struct_span_code_err}; use rustc_hir as hir; +use rustc_hir::GenericArg; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::GenericArg; use rustc_middle::ty::{ self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 7be45463f1512..1fbf70fa20157 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -3,8 +3,8 @@ use rustc_errors::codes::*; use rustc_errors::{Diag, EmissionGuarantee, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS; use rustc_lint_defs::Applicability; +use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS; use rustc_span::Span; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; @@ -133,9 +133,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; }; let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name); - if sugg.is_empty() { - return; - }; diag.multipart_suggestion( format!( "alternatively use a blanket implementation to implement `{of_trait_name}` for \ @@ -170,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0` // and suggest `Trait0`. + // Functions are found in three different contexts. + // 1. Independent functions + // 2. Functions inside trait blocks + // 3. Functions inside impl blocks let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => { (sig, generics, None) @@ -180,6 +181,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { owner_id, .. }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))), + hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(sig, _), + generics, + owner_id, + .. + }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))), _ => return false, }; let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { @@ -187,6 +194,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())]; let mut is_downgradable = true; + + // Check if trait object is safe for suggesting dynamic dispatch. let is_object_safe = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { objects.iter().all(|(o, _)| match o.trait_ref.path.res { @@ -202,8 +211,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } _ => false, }; + + let borrowed = matches!( + tcx.parent_hir_node(self_ty.hir_id), + hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. }) + ); + + // Suggestions for function return type. if let hir::FnRetTy::Return(ty) = sig.decl.output - && ty.hir_id == self_ty.hir_id + && ty.peel_refs().hir_id == self_ty.hir_id { let pre = if !is_object_safe { format!("`{trait_name}` is not object safe, ") @@ -214,14 +230,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \ single underlying type", ); + diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable); + + // Suggest `Box` for return type if is_object_safe { - diag.multipart_suggestion_verbose( - "alternatively, you can return an owned trait object", + // If the return type is `&Trait`, we don't want + // the ampersand to be displayed in the `Box` + // suggestion. + let suggestion = if borrowed { + vec![(ty.span, format!("Box"))] + } else { vec![ (ty.span.shrink_to_lo(), "Box".to_string()), - ], + ] + }; + + diag.multipart_suggestion_verbose( + "alternatively, you can return an owned trait object", + suggestion, Applicability::MachineApplicable, ); } else if is_downgradable { @@ -230,24 +258,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } return true; } + + // Suggestions for function parameters. for ty in sig.decl.inputs { - if ty.hir_id != self_ty.hir_id { + if ty.peel_refs().hir_id != self_ty.hir_id { continue; } let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name); - if !sugg.is_empty() { - diag.multipart_suggestion_verbose( - format!("use a new generic type parameter, constrained by `{trait_name}`"), - sugg, - Applicability::MachineApplicable, - ); - diag.multipart_suggestion_verbose( - "you can also use an opaque type, but users won't be able to specify the type \ - parameter when calling the `fn`, having to rely exclusively on type inference", - impl_sugg, - Applicability::MachineApplicable, - ); - } + diag.multipart_suggestion_verbose( + format!("use a new generic type parameter, constrained by `{trait_name}`"), + sugg, + Applicability::MachineApplicable, + ); + diag.multipart_suggestion_verbose( + "you can also use an opaque type, but users won't be able to specify the type \ + parameter when calling the `fn`, having to rely exclusively on type inference", + impl_sugg, + Applicability::MachineApplicable, + ); if !is_object_safe { diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`")); if is_downgradable { @@ -255,14 +283,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { diag.downgrade_to_delayed_bug(); } } else { + // No ampersand in suggestion if it's borrowed already + let (dyn_str, paren_dyn_str) = + if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") }; + let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind { // There are more than one trait bound, we need surrounding parentheses. vec![ - (self_ty.span.shrink_to_lo(), "&(dyn ".to_string()), + (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()), (self_ty.span.shrink_to_hi(), ")".to_string()), ] } else { - vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())] + vec![(self_ty.span.shrink_to_lo(), dyn_str.to_string())] }; diag.multipart_suggestion_verbose( format!( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 36c26f91089c3..d7d4a98e63fe6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -26,7 +26,7 @@ use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::codes::*; use rustc_errors::{ - struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, + Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -44,8 +44,8 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::abi; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; @@ -53,8 +53,8 @@ use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::{debug, debug_span, instrument}; use crate::bounds::Bounds; -use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; -use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend}; +use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy}; +use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; use crate::require_c_abi_if_c_variadic; @@ -562,13 +562,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.const_param_default(param.def_id) .instantiate(tcx, preceding_args) .into() + } else if infer_args { + self.lowerer.ct_infer(Some(param), self.span).into() } else { - if infer_args { - self.lowerer.ct_infer(Some(param), self.span).into() - } else { - // We've already errored above about the mismatch. - ty::Const::new_misc_error(tcx).into() - } + // We've already errored above about the mismatch. + ty::Const::new_misc_error(tcx).into() } } } @@ -721,6 +719,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, polarity, constness, + only_self_bounds, ); let mut dup_constraints = FxIndexMap::default(); @@ -815,17 +814,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Search for a trait bound on a type parameter whose trait defines the associated type given by `assoc_name`. + /// Search for a trait bound on a type parameter whose trait defines the associated item + /// given by `assoc_name` and `kind`. /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. /// /// `ty_param_def_id` is the `LocalDefId` of the type parameter. #[instrument(level = "debug", skip_all, ret)] - fn probe_single_ty_param_bound_for_assoc_ty( + fn probe_single_ty_param_bound_for_assoc_item( &self, ty_param_def_id: LocalDefId, ty_param_span: Span, + kind: ty::AssocKind, assoc_name: Ident, span: Span, ) -> Result, ErrorGuaranteed> { @@ -843,7 +844,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name) }, AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), - ty::AssocKind::Type, + kind, assoc_name, span, None, @@ -986,7 +987,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// We **don't** support paths whose self type is an arbitrary type like `Struct::Ty` where /// struct `Struct` impls an in-scope trait that defines an associated type called `Ty`. /// For the latter case, we report ambiguity. - /// While desirable to support, the implemention would be non-trivial. Tracked in [#22519]. + /// While desirable to support, the implementation would be non-trivial. Tracked in [#22519]. /// /// At the time of writing, *inherent associated types* are also resolved here. This however /// is [problematic][iat]. A proper implementation would be as non-trivial as the one @@ -1083,9 +1084,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ( &ty::Param(_), Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), - ) => self.probe_single_ty_param_bound_for_assoc_ty( + ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), qself.span, + ty::AssocKind::Type, assoc_ident, span, )?, @@ -1270,7 +1272,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } let candidates: Vec<_> = tcx - .inherent_impls(adt_did)? + .inherent_impls(adt_did) .iter() .filter_map(|&impl_| { let (item, scope) = @@ -1547,48 +1549,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?trait_def_id); let Some(self_ty) = opt_self_ty else { - let path_str = tcx.def_path_str(trait_def_id); - - let def_id = self.item_def_id(); - debug!(item_def_id = ?def_id); - - // FIXME: document why/how this is different from `tcx.local_parent(def_id)` - let parent_def_id = - tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); - debug!(?parent_def_id); - - // If the trait in segment is the same as the trait defining the item, - // use the `` syntax in the error. - let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; - let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; - - let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { - vec!["Self".to_string()] - } else { - // Find all the types that have an `impl` for the trait. - tcx.all_impls(trait_def_id) - .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) - .filter(|header| { - // Consider only accessible traits - tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) - && header.polarity != ty::ImplPolarity::Negative - }) - .map(|header| header.trait_ref.instantiate_identity().self_ty()) - // We don't care about blanket impls. - .filter(|self_ty| !self_ty.has_non_region_param()) - .map(|self_ty| tcx.erase_regions(self_ty).to_string()) - .collect() - }; - // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that - // references the trait. Relevant for the first case in - // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` - let reported = self.report_ambiguous_assoc_ty( - span, - &type_names, - &[path_str], - item_segment.ident.name, - ); - return Ty::new_error(tcx, reported); + return self.error_missing_qpath_self_ty(trait_def_id, span, item_segment); }; debug!(?self_ty); @@ -1602,6 +1563,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_projection_from_args(tcx, item_def_id, item_args) } + fn error_missing_qpath_self_ty( + &self, + trait_def_id: DefId, + span: Span, + item_segment: &hir::PathSegment<'tcx>, + ) -> Ty<'tcx> { + let tcx = self.tcx(); + let path_str = tcx.def_path_str(trait_def_id); + + let def_id = self.item_def_id(); + debug!(item_def_id = ?def_id); + + // FIXME: document why/how this is different from `tcx.local_parent(def_id)` + let parent_def_id = + tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); + debug!(?parent_def_id); + + // If the trait in segment is the same as the trait defining the item, + // use the `` syntax in the error. + let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; + let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; + + let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { + vec!["Self".to_string()] + } else { + // Find all the types that have an `impl` for the trait. + tcx.all_impls(trait_def_id) + .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) + .filter(|header| { + // Consider only accessible traits + tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) + && header.polarity != ty::ImplPolarity::Negative + }) + .map(|header| header.trait_ref.instantiate_identity().self_ty()) + // We don't care about blanket impls. + .filter(|self_ty| !self_ty.has_non_region_param()) + .map(|self_ty| tcx.erase_regions(self_ty).to_string()) + .collect() + }; + // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that + // references the trait. Relevant for the first case in + // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` + let reported = + self.report_ambiguous_assoc_ty(span, &type_names, &[path_str], item_segment.ident.name); + Ty::new_error(tcx, reported) + } + pub fn prohibit_generic_args<'a>( &self, segments: impl Iterator> + Clone, @@ -1932,7 +1940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .tcx() .dcx() .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted"); - Ty::new_error(self.tcx(), e) + Ty::new_error(tcx, e) } Res::Def(..) => { assert_eq!( @@ -2063,6 +2071,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr) } + // If we encounter a fully qualified path with RTN generics, then it must have + // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore + // it's certainly in an illegal position. + hir::TyKind::Path(hir::QPath::Resolved(_, path)) + if path.segments.last().and_then(|segment| segment.args).is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + Ty::new_error(tcx, guar) + } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2087,6 +2106,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } } + // If we encounter a type relative path with RTN generics, then it must have + // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore + // it's certainly in an illegal position. + hir::TyKind::Path(hir::QPath::TypeRelative(_, segment)) + if segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + Ty::new_error(tcx, guar) + } hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => { debug!(?qself, ?segment); let ty = self.lower_ty(qself); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 8853886371033..87a240f626c3f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{ use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::traits::report_object_safety_error; use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations}; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; use super::HirTyLowerer; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 147646930dde3..0355adfcb11e1 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -68,15 +68,15 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt}; +use rustc_trait_selection::traits::{self, ObligationCtxt, translate_args_with_cause, wf}; use tracing::{debug, instrument}; use crate::errors::GenericArgsOnOverriddenImpl; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1481a4dd141b2..92d85d48a42c0 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -100,8 +100,8 @@ use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::parse::feature_err; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; @@ -170,7 +170,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _ = tcx.ensure().coherent_trait(trait_def_id); } // these queries are executed for side-effects (error reporting): - let _ = tcx.ensure().crate_inherent_impls(()); + let _ = tcx.ensure().crate_inherent_impls_validity_check(()); let _ = tcx.ensure().crate_inherent_impls_overlap_check(()); }); diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index a1eccc91dea82..0c9f5ba8b6fa8 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_middle::ty::{self, GenericArg, GenericArgKind, Region, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_type_ir::outlives::{push_outlives_components, Component}; +use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::smallvec; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index ace183986bd00..dbaf9c2c6f075 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -1,7 +1,7 @@ use std::fmt::Write; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_middle::ty::{GenericArgs, TyCtxt}; use rustc_span::symbol::sym; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ac6707f931602..1c52283d537d3 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -18,9 +18,9 @@ use rustc_hir::{ HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TraitBoundModifier, }; -use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::FileName; +use rustc_span::source_map::SourceMap; +use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_target::spec::abi::Abi; use {rustc_ast as ast, rustc_hir as hir}; @@ -2026,13 +2026,10 @@ impl<'a> State<'a> { let generic_params = generic_params .iter() .filter(|p| { - matches!( - p, - GenericParam { - kind: GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit }, - .. - } - ) + matches!(p, GenericParam { + kind: GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit }, + .. + }) }) .collect::>(); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index afaa4a1ac6d8b..bf8ed017cf703 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -389,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // check that the `if` expr without `else` is the fn body's expr if expr.span == sp { - return self.get_fn_decl(hir_id).map(|(_, fn_decl, _)| { + return self.get_fn_decl(hir_id).map(|(_, fn_decl)| { let (ty, span) = match fn_decl.output { hir::FnRetTy::DefaultReturn(span) => ("()".to_string(), span), hir::FnRetTy::Return(ty) => (ty_to_string(&self.tcx, ty), ty.span), diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index a4eec5f05a8ff..13ba615d4c927 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -13,17 +13,17 @@ use rustc_middle::ty::adjustment::{ }; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::{Ident, sym}; use rustc_target::spec::abi; use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use tracing::{debug, instrument, trace}; -use super::method::probe::ProbeScope; use super::method::MethodCallee; +use super::method::probe::ProbeScope; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::errors; @@ -58,7 +58,7 @@ pub(crate) fn check_legal_trait_for_method_call( enum CallStep<'tcx> { Builtin(Ty<'tcx>), DeferredClosure(LocalDefId, ty::FnSig<'tcx>), - /// E.g., enum variant constructors. + /// Call overloading when callee implements one of the Fn* traits. Overloaded(MethodCallee<'tcx>), } @@ -156,16 +156,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_sig, ); let adjustments = self.adjust_steps(autoderef); - self.record_deferred_call_resolution( - def_id, - DeferredCallResolution { - call_expr, - callee_expr, - closure_ty: adjusted_ty, - adjustments, - fn_sig: closure_sig, - }, - ); + self.record_deferred_call_resolution(def_id, DeferredCallResolution { + call_expr, + callee_expr, + closure_ty: adjusted_ty, + adjustments, + fn_sig: closure_sig, + }); return Some(CallStep::DeferredClosure(def_id, closure_sig)); } @@ -202,16 +199,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coroutine_closure_sig.abi, ); let adjustments = self.adjust_steps(autoderef); - self.record_deferred_call_resolution( - def_id, - DeferredCallResolution { - call_expr, - callee_expr, - closure_ty: adjusted_ty, - adjustments, - fn_sig: call_sig, - }, - ); + self.record_deferred_call_resolution(def_id, DeferredCallResolution { + call_expr, + callee_expr, + closure_ty: adjusted_ty, + adjustments, + fn_sig: call_sig, + }); return Some(CallStep::DeferredClosure(def_id, call_sig)); } @@ -503,18 +497,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fn_sig = self.instantiate_binder_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig); let fn_sig = self.normalize(call_expr.span, fn_sig); - // Call the generic checker. - let expected_arg_tys = self.expected_inputs_for_expected_output( - call_expr.span, - expected, - fn_sig.output(), - fn_sig.inputs(), - ); self.check_argument_types( call_expr.span, call_expr, fn_sig.inputs(), - expected_arg_tys, + fn_sig.output(), + expected, arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::DontTupleArguments, @@ -560,11 +548,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, self.misc(span), self.param_env, - ty::TraitRef::new( - self.tcx, - fn_once_def_id, - [arg_ty.into(), fn_sig.inputs()[0].into(), const_param], - ), + ty::TraitRef::new(self.tcx, fn_once_def_id, [ + arg_ty.into(), + fn_sig.inputs()[0].into(), + const_param, + ]), )); self.register_predicate(traits::Obligation::new( @@ -866,19 +854,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // don't know the full details yet (`Fn` vs `FnMut` etc), but we // do know the types expected for each argument and the return // type. - - let expected_arg_tys = self.expected_inputs_for_expected_output( - call_expr.span, - expected, - fn_sig.output(), - fn_sig.inputs(), - ); - self.check_argument_types( call_expr.span, call_expr, fn_sig.inputs(), - expected_arg_tys, + fn_sig.output(), + expected, arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::TupleArguments, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 1db2c865b4077..fcd2940b83ae3 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -32,17 +32,18 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_hir::{self as hir, ExprKind}; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_middle::bug; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; @@ -152,12 +153,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[derive(Copy, Clone, Debug)] -pub enum CastError { +enum CastError<'tcx> { ErrorGuaranteed(ErrorGuaranteed), CastToBool, CastToChar, - DifferingKinds, + DifferingKinds { + src_kind: PointerKind<'tcx>, + dst_kind: PointerKind<'tcx>, + }, /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`). SizedUnsizedCast, IllegalCast, @@ -177,7 +181,7 @@ pub enum CastError { ForeignNonExhaustiveAdt, } -impl From for CastError { +impl From for CastError<'_> { fn from(err: ErrorGuaranteed) -> Self { CastError::ErrorGuaranteed(err) } @@ -251,7 +255,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } - fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) { + fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError<'tcx>) { match e { CastError::ErrorGuaranteed(_) => { // an error has already been reported @@ -284,14 +288,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { let mut err = make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx); if self.cast_ty.is_integral() { - err.help(format!( - "cast through {} first", - match e { - CastError::NeedViaPtr => "a raw pointer", - CastError::NeedViaThinPtr => "a thin pointer", - e => unreachable!("control flow means we should never encounter a {e:?}"), - } - )); + err.help(format!("cast through {} first", match e { + CastError::NeedViaPtr => "a raw pointer", + CastError::NeedViaThinPtr => "a thin pointer", + e => unreachable!("control flow means we should never encounter a {e:?}"), + })); } self.try_suggest_collection_to_bool(fcx, &mut err); @@ -306,10 +307,52 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::IllegalCast => { make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx).emit(); } - CastError::DifferingKinds => { - make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx) - .with_note("vtable kinds may not match") - .emit(); + CastError::DifferingKinds { src_kind, dst_kind } => { + let mut err = + make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx); + + match (src_kind, dst_kind) { + (PointerKind::VTable(_), PointerKind::VTable(_)) => { + err.note("the trait objects may have different vtables"); + } + ( + PointerKind::OfParam(_) | PointerKind::OfAlias(_), + PointerKind::OfParam(_) + | PointerKind::OfAlias(_) + | PointerKind::VTable(_) + | PointerKind::Length, + ) + | ( + PointerKind::VTable(_) | PointerKind::Length, + PointerKind::OfParam(_) | PointerKind::OfAlias(_), + ) => { + err.note("the pointers may have different metadata"); + } + (PointerKind::VTable(_), PointerKind::Length) + | (PointerKind::Length, PointerKind::VTable(_)) => { + err.note("the pointers have different metadata"); + } + ( + PointerKind::Thin, + PointerKind::Thin + | PointerKind::VTable(_) + | PointerKind::Length + | PointerKind::OfParam(_) + | PointerKind::OfAlias(_), + ) + | ( + PointerKind::VTable(_) + | PointerKind::Length + | PointerKind::OfParam(_) + | PointerKind::OfAlias(_), + PointerKind::Thin, + ) + | (PointerKind::Length, PointerKind::Length) => { + span_bug!(self.span, "unexpected cast error: {e:?}") + } + } + + err.emit(); } CastError::CastToBool => { let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); @@ -620,12 +663,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - fcx.tcx.emit_node_span_lint( - lint, - self.expr.hir_id, - self.span, - errors::TrivialCast { numeric, expr_ty, cast_ty }, - ); + fcx.tcx.emit_node_span_lint(lint, self.expr.hir_id, self.span, errors::TrivialCast { + numeric, + expr_ty, + cast_ty, + }); } #[instrument(skip(fcx), level = "debug")] @@ -650,7 +692,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // cannot distinguish. This would cause us to erroneously discard a cast which will // lead to a borrowck error like #113257. // We still did a coercion above to unify inference variables for `ptr as _` casts. - // This does cause us to miss some trivial casts in the trival cast lint. + // This does cause us to miss some trivial casts in the trivial cast lint. debug!(" -> PointerCast"); } else { self.trivial_cast_lint(fcx); @@ -674,10 +716,20 @@ impl<'a, 'tcx> CastCheck<'tcx> { /// Checks a cast, and report an error if one exists. In some cases, this /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. - fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { + fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result> { use rustc_middle::ty::cast::CastTy::*; use rustc_middle::ty::cast::IntTy::*; + if self.cast_ty.is_dyn_star() { + if fcx.tcx.features().dyn_star { + span_bug!(self.span, "should be handled by `coerce`"); + } else { + // Report "casting is invalid" rather than "non-primitive cast" + // if the feature is not enabled. + return Err(CastError::IllegalCast); + } + } + let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) { (Some(t_from), Some(t_cast)) => (t_from, t_cast), @@ -732,12 +784,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { } _ => return Err(CastError::NonScalar), }; - if let ty::Adt(adt_def, _) = *self.expr_ty.kind() { - if adt_def.did().krate != LOCAL_CRATE { - if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) { - return Err(CastError::ForeignNonExhaustiveAdt); - } - } + if let ty::Adt(adt_def, _) = *self.expr_ty.kind() + && adt_def.did().krate != LOCAL_CRATE + && adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) + { + return Err(CastError::ForeignNonExhaustiveAdt); } match (t_from, t_cast) { // These types have invariants! can't cast into them. @@ -785,16 +836,6 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), - - (_, DynStar) => { - if fcx.tcx.features().dyn_star { - bug!("should be handled by `coerce`") - } else { - Err(CastError::IllegalCast) - } - } - - (DynStar, _) => Err(CastError::IllegalCast), } } @@ -803,27 +844,34 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx: &FnCtxt<'a, 'tcx>, m_src: ty::TypeAndMut<'tcx>, m_dst: ty::TypeAndMut<'tcx>, - ) -> Result { + ) -> Result> { debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}"); - // ptr-ptr cast. vtables must match. + // ptr-ptr cast. metadata must match. let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?); let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?); - match (src_kind, dst_kind) { - // We can't cast if target pointer kind is unknown - (_, None) => Err(CastError::UnknownCastPtrKind), - // Cast to thin pointer is OK - (_, Some(PointerKind::Thin)) => Ok(CastKind::PtrPtrCast), + // We can't cast if target pointer kind is unknown + let Some(dst_kind) = dst_kind else { + return Err(CastError::UnknownCastPtrKind); + }; + + // Cast to thin pointer is OK + if dst_kind == PointerKind::Thin { + return Ok(CastKind::PtrPtrCast); + } - // We can't cast to fat pointer if source pointer kind is unknown - (None, _) => Err(CastError::UnknownExprPtrKind), + // We can't cast to fat pointer if source pointer kind is unknown + let Some(src_kind) = src_kind else { + return Err(CastError::UnknownCastPtrKind); + }; + match (src_kind, dst_kind) { // thin -> fat? report invalid cast (don't complain about vtable kinds) - (Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast), + (PointerKind::Thin, _) => Err(CastError::SizedUnsizedCast), // trait object -> trait object? need to do additional checks - (Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => { + (PointerKind::VTable(src_tty), PointerKind::VTable(dst_tty)) => { match (src_tty.principal(), dst_tty.principal()) { // A + SrcAuto> -> B + DstAuto>. need to make sure // - `Src` and `Dst` traits are the same @@ -839,7 +887,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Note that trait upcasting goes through a different mechanism (`coerce_unsized`) // and is unaffected by this check. if src_principal.def_id() != dst_principal.def_id() { - return Err(CastError::DifferingKinds); + return Err(CastError::DifferingKinds { src_kind, dst_kind }); } // We need to reconstruct trait object types. @@ -865,7 +913,16 @@ impl<'a, 'tcx> CastCheck<'tcx> { )); // `dyn Src = dyn Dst`, this checks for matching traits/generics - fcx.demand_eqtype(self.span, src_obj, dst_obj); + // This is `demand_eqtype`, but inlined to give a better error. + let cause = fcx.misc(self.span); + if fcx + .at(&cause, fcx.param_env) + .eq(DefineOpaqueTypes::Yes, src_obj, dst_obj) + .map(|infer_ok| fcx.register_infer_ok_obligations(infer_ok)) + .is_err() + { + return Err(CastError::DifferingKinds { src_kind, dst_kind }); + } // Check that `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`. // Emit an FCW otherwise. @@ -910,17 +967,17 @@ impl<'a, 'tcx> CastCheck<'tcx> { // dyn Trait -> dyn Auto? should be ok, but we used to not allow it. // FIXME: allow this - (Some(_), None) => Err(CastError::DifferingKinds), + (Some(_), None) => Err(CastError::DifferingKinds { src_kind, dst_kind }), // dyn Auto -> dyn Trait? not ok. - (None, Some(_)) => Err(CastError::DifferingKinds), + (None, Some(_)) => Err(CastError::DifferingKinds { src_kind, dst_kind }), } } // fat -> fat? metadata kinds must match - (Some(src_kind), Some(dst_kind)) if src_kind == dst_kind => Ok(CastKind::PtrPtrCast), + (src_kind, dst_kind) if src_kind == dst_kind => Ok(CastKind::PtrPtrCast), - (_, _) => Err(CastError::DifferingKinds), + (_, _) => Err(CastError::DifferingKinds { src_kind, dst_kind }), } } @@ -928,7 +985,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { &self, fcx: &FnCtxt<'a, 'tcx>, m_cast: ty::TypeAndMut<'tcx>, - ) -> Result { + ) -> Result> { // fptr-ptr cast. must be to thin ptr match fcx.pointer_kind(m_cast.ty, self.span)? { @@ -942,7 +999,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { &self, fcx: &FnCtxt<'a, 'tcx>, m_expr: ty::TypeAndMut<'tcx>, - ) -> Result { + ) -> Result> { // ptr-addr cast. must be from thin ptr match fcx.pointer_kind(m_expr.ty, self.span)? { @@ -957,7 +1014,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx: &FnCtxt<'a, 'tcx>, m_expr: ty::TypeAndMut<'tcx>, m_cast: ty::TypeAndMut<'tcx>, - ) -> Result { + ) -> Result> { // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const if m_expr.mutbl >= m_cast.mutbl { if let ty::Array(ety, _) = m_expr.ty.kind() { @@ -992,7 +1049,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { &self, fcx: &FnCtxt<'a, 'tcx>, m_cast: TypeAndMut<'tcx>, - ) -> Result { + ) -> Result> { // ptr-addr cast. pointer must be thin. match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 9346ff2d6ef6f..f2d3a3b509a00 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -191,21 +191,18 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, Some(span)); // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` - let panic_info_ty = tcx.type_of(panic_info_did).instantiate( - tcx, - &[ty::GenericArg::from(ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon }, - ))], - ); + let panic_info_ty = tcx.type_of(panic_info_did).instantiate(tcx, &[ty::GenericArg::from( + ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::from_u32(1), + kind: ty::BrAnon, + }), + )]); let panic_info_ref_ty = Ty::new_imm_ref( tcx, - ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon }, - ), + ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::ZERO, + kind: ty::BrAnon, + }), panic_info_ty, ); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 5117eef9ed8f5..3e7ce2955fc05 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -14,14 +14,14 @@ use rustc_middle::span_bug; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::traits::ArgKind; use rustc_trait_selection::traits; use rustc_type_ir::ClosureKind; use tracing::{debug, instrument, trace}; -use super::{check_fn, CoroutineTypes, Expectation, FnCtxt}; +use super::{CoroutineTypes, Expectation, FnCtxt, check_fn}; /// What signature do we *expect* the closure to have from context? #[derive(Debug, Clone, TypeFoldable, TypeVisitable)] @@ -103,15 +103,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => self.next_ty_var(expr_span), }; - let closure_args = ty::ClosureArgs::new( - tcx, - ty::ClosureArgsParts { - parent_args, - closure_kind_ty, - closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig), - tupled_upvars_ty, - }, - ); + let closure_args = ty::ClosureArgs::new(tcx, ty::ClosureArgsParts { + parent_args, + closure_kind_ty, + closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig), + tupled_upvars_ty, + }); (Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None) } @@ -180,18 +177,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => tcx.types.unit, }; - let coroutine_args = ty::CoroutineArgs::new( - tcx, - ty::CoroutineArgsParts { - parent_args, - kind_ty, - resume_ty, - yield_ty, - return_ty: liberated_sig.output(), - witness: interior, - tupled_upvars_ty, - }, - ); + let coroutine_args = ty::CoroutineArgs::new(tcx, ty::CoroutineArgsParts { + parent_args, + kind_ty, + resume_ty, + yield_ty, + return_ty: liberated_sig.output(), + witness: interior, + tupled_upvars_ty, + }); ( Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args), @@ -222,9 +216,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let coroutine_captures_by_ref_ty = self.next_ty_var(expr_span); - let closure_args = ty::CoroutineClosureArgs::new( - tcx, - ty::CoroutineClosureArgsParts { + let closure_args = + ty::CoroutineClosureArgs::new(tcx, ty::CoroutineClosureArgsParts { parent_args, closure_kind_ty, signature_parts_ty: Ty::new_fn_ptr( @@ -245,8 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tupled_upvars_ty, coroutine_captures_by_ref_ty, coroutine_witness_ty: interior, - }, - ); + }); let coroutine_kind_ty = match expected_kind { Some(kind) => Ty::from_coroutine_closure_kind(tcx, kind), @@ -605,7 +597,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Abi::Rust, )); - return Some(ExpectedSig { cause_span, sig }); + Some(ExpectedSig { cause_span, sig }) } fn sig_of_closure( diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index d97c590bd4109..b08c5bc6d9a36 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -38,7 +38,7 @@ use std::ops::Deref; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, Applicability, Diag}; +use rustc_errors::{Applicability, Diag, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; @@ -58,18 +58,18 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{BytePos, DesugaringKind, Span, DUMMY_SP}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, }; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; -use crate::errors::SuggestBoxingForReturnImplTrait; use crate::FnCtxt; +use crate::errors::SuggestBoxingForReturnImplTrait; struct Coerce<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -214,6 +214,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => { return self.coerce_dyn_star(a, b, predicates, region); } + ty::Adt(pin, _) + if self.tcx.features().pin_ergonomics + && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => + { + return self.coerce_pin(a, b); + } _ => {} } @@ -528,24 +534,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // the reborrow in coerce_borrowed_ptr will pick it up. let mutbl = AutoBorrowMutability::new(mutbl_b, AllowTwoPhase::No); - Some(( - Adjustment { kind: Adjust::Deref(None), target: ty_a }, - Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), - target: Ty::new_ref(self.tcx, r_borrow, ty_a, mutbl_b), - }, - )) + Some((Adjustment { kind: Adjust::Deref(None), target: ty_a }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), + target: Ty::new_ref(self.tcx, r_borrow, ty_a, mutbl_b), + })) } (&ty::Ref(_, ty_a, mt_a), &ty::RawPtr(_, mt_b)) => { coerce_mutbls(mt_a, mt_b)?; - Some(( - Adjustment { kind: Adjust::Deref(None), target: ty_a }, - Adjustment { - kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)), - target: Ty::new_ptr(self.tcx, ty_a, mt_b), - }, - )) + Some((Adjustment { kind: Adjust::Deref(None), target: ty_a }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)), + target: Ty::new_ptr(self.tcx, ty_a, mt_b), + })) } _ => None, }; @@ -567,11 +567,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut selcx = traits::SelectionContext::new(self); // Create an obligation for `Source: CoerceUnsized`. - let cause = ObligationCause::new( - self.cause.span, - self.body_id, - ObligationCauseCode::Coercion { source, target }, - ); + let cause = + ObligationCause::new(self.cause.span, self.body_id, ObligationCauseCode::Coercion { + source, + target, + }); // Use a FIFO queue for this custom fulfillment procedure. // @@ -769,11 +769,70 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { )); Ok(InferOk { - value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b), + value: ( + vec![Adjustment { kind: Adjust::Pointer(PointerCoercion::DynStar), target: b }], + b, + ), obligations, }) } + /// Applies reborrowing for `Pin` + /// + /// We currently only support reborrowing `Pin<&mut T>` as `Pin<&mut T>`. This is accomplished + /// by inserting a call to `Pin::as_mut` during MIR building. + /// + /// In the future we might want to support other reborrowing coercions, such as: + /// - `Pin<&mut T>` as `Pin<&T>` + /// - `Pin<&T>` as `Pin<&T>` + /// - `Pin>` as `Pin<&T>` + /// - `Pin>` as `Pin<&mut T>` + #[instrument(skip(self), level = "trace")] + fn coerce_pin(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + // We need to make sure the two types are compatible for coercion. + // Then we will build a ReborrowPin adjustment and return that as an InferOk. + + // Right now we can only reborrow if this is a `Pin<&mut T>`. + let extract_pin_mut = |ty: Ty<'tcx>| { + // Get the T out of Pin + let (pin, ty) = match ty.kind() { + ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { + (*pin, args[0].expect_ty()) + } + _ => { + debug!("can't reborrow {:?} as pinned", ty); + return Err(TypeError::Mismatch); + } + }; + // Make sure the T is something we understand (just `&mut U` for now) + match ty.kind() { + ty::Ref(region, ty, mutbl) => Ok((pin, *region, *ty, *mutbl)), + _ => { + debug!("can't reborrow pin of inner type {:?}", ty); + Err(TypeError::Mismatch) + } + } + }; + + let (pin, a_region, a_ty, mut_a) = extract_pin_mut(a)?; + let (_, b_region, _b_ty, mut_b) = extract_pin_mut(b)?; + + coerce_mutbls(mut_a, mut_b)?; + + // update a with b's mutability since we'll be coercing mutability + let a = Ty::new_adt( + self.tcx, + pin, + self.tcx.mk_args(&[Ty::new_ref(self.tcx, a_region, a_ty, mut_b).into()]), + ); + + // To complete the reborrow, we need to make sure we can unify the inner types, and if so we + // add the adjustments. + self.unify_and(a, b, |_inner_ty| { + vec![Adjustment { kind: Adjust::ReborrowPin(b_region, mut_b), target: b }] + }) + } + fn coerce_from_safe_fn( &self, a: Ty<'tcx>, @@ -959,10 +1018,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // regionck knows that the region for `a` must be valid here. if is_ref { self.unify_and(a_unsafe, b, |target| { - vec![ - Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target }, - ] + vec![Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), + target, + }] }) } else if mt_a.mutbl != mutbl_b { self.unify_and(a_unsafe, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer))) @@ -1049,7 +1108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// trait or region sub-obligations. (presumably we could, but it's not /// particularly important for diagnostics...) pub(crate) fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option> { - self.autoderef(DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| { + self.autoderef(DUMMY_SP, expr_ty).silence_errors().nth(1).and_then(|(deref_ty, _)| { self.infcx .type_implements_trait( self.tcx.lang_items().deref_mut_trait()?, @@ -1179,10 +1238,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => span_bug!(new.span, "should not try to coerce a {new_ty} to a fn pointer"), }; for expr in exprs.iter().map(|e| e.as_coercion_site()) { - self.apply_adjustments( - expr, - vec![Adjustment { kind: prev_adjustment.clone(), target: fn_ptr }], - ); + self.apply_adjustments(expr, vec![Adjustment { + kind: prev_adjustment.clone(), + target: fn_ptr, + }]); } self.apply_adjustments(new, vec![Adjustment { kind: next_adjustment, target: fn_ptr }]); return Ok(fn_ptr); @@ -1860,10 +1919,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }; // If this is due to an explicit `return`, suggest adding a return type. - if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(block_or_return_id) + if let Some((fn_id, fn_decl)) = fcx.get_fn_decl(block_or_return_id) && !due_to_block { - fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id); + fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, fn_id); } // If this is due to a block, then maybe we forgot a `return`/`break`. diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 0da299f017942..cfa8fc4bbf2e6 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AssocItem, Ty, TypeFoldable, TypeVisitableExt}; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCause; use tracing::instrument; @@ -1042,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } } - return false; + false } fn explain_self_literal( diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index 3066561a31d6d..1a10e19d0a5e9 100644 --- a/compiler/rustc_hir_typeck/src/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs @@ -1,6 +1,6 @@ use std::{cmp, ops}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; /// Tracks whether executing a node may exit normally (versus /// return/break/panic, which "diverge", leaving dead code in their diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 4d2770d2e50e2..a692642ccfcc2 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -711,7 +711,7 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> { #[derive(Diagnostic)] #[diag(hir_typeck_pass_to_variadic_function, code = E0617)] -pub(crate) struct PassToVariadicFunction<'tcx, 'a> { +pub(crate) struct PassToVariadicFunction<'a, 'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 1362d3626efd4..b34ed4640db12 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -7,7 +7,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, Subdiagnostic, + Applicability, Diag, ErrorGuaranteed, StashKey, Subdiagnostic, pluralize, struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -17,26 +17,28 @@ use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; use rustc_infer::infer; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; -use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::parse::feature_err; +use rustc_span::Span; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; -use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; use smallvec::SmallVec; use tracing::{debug, instrument, trace}; use {rustc_ast as ast, rustc_hir as hir}; +use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; +use crate::TupleArgumentsFlag::DontTupleArguments; use crate::coercion::{CoerceMany, DynamicCoerceMany}; use crate::errors::{ AddressOfTemporaryTaken, FieldMultiplySpecifiedInInitializer, @@ -44,11 +46,9 @@ use crate::errors::{ ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo, YieldExprOutsideOfCoroutine, }; -use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; -use crate::TupleArgumentsFlag::DontTupleArguments; use crate::{ - cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct, BreakableCtxt, - CoroutineTypes, Diverges, FnCtxt, Needs, + BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, cast, fatally_break_rust, + report_unexpected_variant_res, type_error_struct, }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -72,10 +72,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let adj_ty = self.next_ty_var(expr.span); - self.apply_adjustments( - expr, - vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty }], - ); + self.apply_adjustments(expr, vec![Adjustment { + kind: Adjust::NeverToAny, + target: adj_ty, + }]); ty = adj_ty; } @@ -447,7 +447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this time with enough precision to check that the value // whose address was taken can actually be made to live as long // as it needs to live. - let region = self.next_region_var(infer::AddrOfRegion(expr.span)); + let region = self.next_region_var(infer::BorrowRegion(expr.span)); Ty::new_ref(self.tcx, region, ty, mutbl) } } @@ -774,7 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.ret_coercion_span.set(Some(expr.span)); } let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) { + if let Some((_, fn_decl)) = self.get_fn_decl(expr.hir_id) { coercion.coerce_forced_unit( self, &cause, @@ -1491,8 +1491,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let count = self.lower_array_length(count); - if let Some(count) = count.try_eval_target_usize(tcx, self.param_env) { + let count_span = count.span(); + let count = self.try_structurally_resolve_const(count_span, self.lower_array_length(count)); + + if let Some(count) = count.try_to_target_usize(tcx) { self.suggest_array_len(expr, count); } @@ -1520,19 +1522,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(tcx, guar); } - self.check_repeat_element_needs_copy_bound(element, count, element_ty); + // If the length is 0, we don't create any elements, so we don't copy any. + // If the length is 1, we don't copy that one element, we move it. Only check + // for `Copy` if the length is larger, or unevaluated. + // FIXME(min_const_generic_exprs): We could perhaps defer this check so that + // we don't require `::CONST` doesn't unnecessarily require `Copy`. + if count.try_to_target_usize(tcx).is_none_or(|x| x > 1) { + self.enforce_repeat_element_needs_copy_bound(element, element_ty); + } let ty = Ty::new_array_with_const_len(tcx, t, count); - self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None)); - ty } - fn check_repeat_element_needs_copy_bound( + /// Requires that `element_ty` is `Copy` (unless it's a const expression itself). + fn enforce_repeat_element_needs_copy_bound( &self, element: &hir::Expr<'_>, - count: ty::Const<'tcx>, element_ty: Ty<'tcx>, ) { let tcx = self.tcx; @@ -1565,27 +1572,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => traits::IsConstable::No, }; - // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we - // don't copy that one element, we move it. Only check for Copy if the length is larger. - if count.try_eval_target_usize(tcx, self.param_env).is_none_or(|len| len > 1) { - let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); - let code = traits::ObligationCauseCode::RepeatElementCopy { - is_constable, - elt_type: element_ty, - elt_span: element.span, - elt_stmt_span: self - .tcx - .hir() - .parent_iter(element.hir_id) - .find_map(|(_, node)| match node { - hir::Node::Item(it) => Some(it.span), - hir::Node::Stmt(stmt) => Some(stmt.span), - _ => None, - }) - .expect("array repeat expressions must be inside an item or statement"), - }; - self.require_type_meets(element_ty, element.span, code, lang_item); - } + let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let code = traits::ObligationCauseCode::RepeatElementCopy { + is_constable, + elt_type: element_ty, + elt_span: element.span, + elt_stmt_span: self + .tcx + .hir() + .parent_iter(element.hir_id) + .find_map(|(_, node)| match node { + hir::Node::Item(it) => Some(it.span), + hir::Node::Stmt(stmt) => Some(stmt.span), + _ => None, + }) + .expect("array repeat expressions must be inside an item or statement"), + }; + self.require_type_meets(element_ty, element.span, code, lang_item); } fn check_expr_tuple( @@ -1673,15 +1676,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let tcx = self.tcx; - let expected_inputs = - self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]); - let adt_ty_hint = if let Some(expected_inputs) = expected_inputs { - expected_inputs.get(0).cloned().unwrap_or(adt_ty) - } else { - adt_ty - }; - // re-link the regions that EIfEO can erase. - self.demand_eqtype(span, adt_ty_hint, adt_ty); + let adt_ty = self.resolve_vars_with_obligations(adt_ty); + let adt_ty_hint = expected.only_has_type(self).and_then(|expected| { + self.fudge_inference_if_ok(|| { + let ocx = ObligationCtxt::new(self); + ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?; + if !ocx.select_where_possible().is_empty() { + return Err(TypeError::Mismatch); + } + Ok(self.resolve_vars_if_possible(adt_ty)) + }) + .ok() + }); + if let Some(adt_ty_hint) = adt_ty_hint { + // re-link the variables that the fudging above can create. + self.demand_eqtype(span, adt_ty_hint, adt_ty); + } let ty::Adt(adt, args) = adt_ty.kind() else { span_bug!(span, "non-ADT passed to check_expr_struct_fields"); @@ -1773,16 +1783,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Make sure the programmer specified correct number of fields. - if adt_kind == AdtKind::Union { - if hir_fields.len() != 1 { - struct_span_code_err!( - self.dcx(), - span, - E0784, - "union expressions should have exactly one field", - ) - .emit(); - } + if adt_kind == AdtKind::Union && hir_fields.len() != 1 { + struct_span_code_err!( + self.dcx(), + span, + E0784, + "union expressions should have exactly one field", + ) + .emit(); } // If check_expr_struct_fields hit an error, do not attempt to populate @@ -2118,7 +2126,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .inherent_impls(def_id) .into_iter() - .flatten() .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. .filter(|item| { @@ -2795,9 +2802,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { len: ty::Const<'tcx>, ) { err.span_label(field.span, "unknown field"); - if let (Some(len), Ok(user_index)) = - (len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::()) - { + if let (Some(len), Ok(user_index)) = ( + self.try_structurally_resolve_const(base.span, len).try_to_target_usize(self.tcx), + field.as_str().parse::(), + ) { let help = "instead of using tuple indexing, use array indexing"; let applicability = if len < user_index { Applicability::MachineApplicable @@ -2859,13 +2867,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (expr_t, "") }; for (found_fields, args) in - self.get_field_candidates_considering_privacy(span, ty, mod_id, id) + self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, id) { let field_names = found_fields.iter().map(|field| field.name).collect::>(); let mut candidate_fields: Vec<_> = found_fields .into_iter() .filter_map(|candidate_field| { - self.check_for_nested_field_satisfying( + self.check_for_nested_field_satisfying_condition_for_diag( span, &|candidate_field, _| candidate_field.ident(self.tcx()) == field, candidate_field, @@ -2897,21 +2905,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_fields.iter().map(|path| format!("{unwrap}{path}")), Applicability::MaybeIncorrect, ); - } else { - if let Some(field_name) = find_best_match_for_name(&field_names, field.name, None) { - err.span_suggestion_verbose( - field.span, - "a field with a similar name exists", - format!("{unwrap}{}", field_name), - Applicability::MaybeIncorrect, - ); - } else if !field_names.is_empty() { - let is = if field_names.len() == 1 { " is" } else { "s are" }; - err.note(format!( - "available field{is}: {}", - self.name_series_display(field_names), - )); - } + } else if let Some(field_name) = + find_best_match_for_name(&field_names, field.name, None) + { + err.span_suggestion_verbose( + field.span, + "a field with a similar name exists", + format!("{unwrap}{}", field_name), + Applicability::MaybeIncorrect, + ); + } else if !field_names.is_empty() { + let is = if field_names.len() == 1 { " is" } else { "s are" }; + err.note( + format!("available field{is}: {}", self.name_series_display(field_names),), + ); } } err @@ -2929,7 +2936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .with_span_label(field.span, "private field") } - pub(crate) fn get_field_candidates_considering_privacy( + pub(crate) fn get_field_candidates_considering_privacy_for_diag( &self, span: Span, base_ty: Ty<'tcx>, @@ -2938,7 +2945,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); - self.autoderef(span, base_ty) + let mut autoderef = self.autoderef(span, base_ty).silence_errors(); + let deref_chain: Vec<_> = autoderef.by_ref().collect(); + + // Don't probe if we hit the recursion limit, since it may result in + // quadratic blowup if we then try to further deref the results of this + // function. This is a best-effort method, after all. + if autoderef.reached_recursion_limit() { + return vec![]; + } + + deref_chain + .into_iter() .filter_map(move |(base_t, _)| { match base_t.kind() { ty::Adt(base_def, args) if !base_def.is_enum() => { @@ -2971,7 +2989,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This method is called after we have encountered a missing field error to recursively /// search for the field - pub(crate) fn check_for_nested_field_satisfying( + pub(crate) fn check_for_nested_field_satisfying_condition_for_diag( &self, span: Span, matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool, @@ -2996,20 +3014,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if matches(candidate_field, field_ty) { return Some(field_path); } else { - for (nested_fields, subst) in - self.get_field_candidates_considering_privacy(span, field_ty, mod_id, hir_id) + for (nested_fields, subst) in self + .get_field_candidates_considering_privacy_for_diag( + span, field_ty, mod_id, hir_id, + ) { // recursively search fields of `candidate_field` if it's a ty::Adt for field in nested_fields { - if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - matches, - field, - subst, - field_path.clone(), - mod_id, - hir_id, - ) { + if let Some(field_path) = self + .check_for_nested_field_satisfying_condition_for_diag( + span, + matches, + field, + subst, + field_path.clone(), + mod_id, + hir_id, + ) + { return Some(field_path); } } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index da8c0ad3a30e2..bb5f351137305 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -6,9 +6,9 @@ use std::cell::{Ref, RefCell}; use std::ops::Deref; use std::slice::from_ref; +use hir::Expr; use hir::def::DefKind; use hir::pat_util::EnumerateAndAdjustIterator as _; -use hir::Expr; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def::{CtorOf, Res}; @@ -20,11 +20,11 @@ use rustc_middle::hir::place::ProjectionKind; pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{ - self, adjustment, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, + self, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment, }; use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, trace}; use ty::BorrowKind::ImmBorrow; @@ -151,7 +151,8 @@ pub trait TypeInformationCtxt<'tcx> { } impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { - type TypeckResults<'a> = Ref<'a, ty::TypeckResults<'tcx>> + type TypeckResults<'a> + = Ref<'a, ty::TypeckResults<'tcx>> where Self: 'a; @@ -195,7 +196,8 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { } impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { - type TypeckResults<'a> = &'tcx ty::TypeckResults<'tcx> + type TypeckResults<'a> + = &'tcx ty::TypeckResults<'tcx> where Self: 'a; @@ -757,9 +759,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx for adjustment in adjustments { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { - adjustment::Adjust::NeverToAny - | adjustment::Adjust::Pointer(_) - | adjustment::Adjust::DynStar => { + adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. self.consume_or_copy(&place_with_id, place_with_id.hir_id); @@ -780,6 +780,16 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx adjustment::Adjust::Borrow(ref autoref) => { self.walk_autoref(expr, &place_with_id, autoref); } + + adjustment::Adjust::ReborrowPin(_, mutbl) => { + // Reborrowing a Pin is like a combinations of a deref and a borrow, so we do + // both. + let bk = match mutbl { + ty::Mutability::Not => ty::BorrowKind::ImmBorrow, + ty::Mutability::Mut => ty::BorrowKind::MutBorrow, + }; + self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); + } } place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?; } @@ -1284,7 +1294,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) | adjustment::Adjust::Borrow(_) - | adjustment::Adjust::DynStar => { + | adjustment::Adjust::ReborrowPin(..) => { // Result is an rvalue. Ok(self.cat_rvalue(expr.hir_id, target)) } diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 79b02a7f04593..4fd508ab896e7 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -5,18 +5,18 @@ use rustc_data_structures::graph::vec_graph::VecGraph; use rustc_data_structures::graph::{self}; use rustc_data_structures::unord::{UnordBag, UnordMap, UnordSet}; use rustc_hir as hir; -use rustc_hir::intravisit::Visitor; use rustc_hir::HirId; +use rustc_hir::intravisit::Visitor; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::debug; -use crate::{errors, FnCtxt, TypeckRootCtxt}; +use crate::{FnCtxt, TypeckRootCtxt, errors}; #[derive(Copy, Clone)] pub(crate) enum DivergingFallbackBehavior { @@ -603,12 +603,12 @@ fn compute_unsafe_infer_vars<'a, 'tcx>( root_ctxt.tcx.hir().maybe_body_owned_by(body_id).expect("body id must have an owner"); let mut res = UnordMap::default(); - struct UnsafeInferVarsVisitor<'a, 'tcx, 'r> { + struct UnsafeInferVarsVisitor<'a, 'tcx> { root_ctxt: &'a TypeckRootCtxt<'tcx>, - res: &'r mut UnordMap, + res: &'a mut UnordMap, } - impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_, '_> { + impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_> { fn visit_expr(&mut self, ex: &'_ hir::Expr<'_>) { let typeck_results = self.root_ctxt.typeck_results.borrow(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 97c27680959f0..2c469c0d52c4f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -20,7 +20,6 @@ use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryRespons use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ @@ -29,21 +28,21 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; -use rustc_span::symbol::{kw, sym}; -use rustc_span::Span; +use rustc_span::symbol::kw; use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::traits::{ - self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt, + self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt, }; use tracing::{debug, instrument}; use crate::callee::{self, DeferredCallResolution}; use crate::errors::{self, CtorIsPrivate}; use crate::method::{self, MethodCallee}; -use crate::{rvalue_scopes, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; +use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, rvalue_scopes}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the @@ -225,10 +224,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("fcx {}", self.tag()); if Self::can_contain_user_lifetime_bounds((args, user_self_ty)) { - let canonicalized = self.canonicalize_user_type_annotation(UserType::TypeOf( - def_id, - UserArgs { args, user_self_ty }, - )); + let canonicalized = + self.canonicalize_user_type_annotation(UserType::TypeOf(def_id, UserArgs { + args, + user_self_ty, + })); debug!(?canonicalized); self.write_user_type_annotation(hir_id, canonicalized); } @@ -271,13 +271,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let autoborrow_mut = adj.iter().any(|adj| { - matches!( - adj, - &Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), - .. - } - ) + matches!(adj, &Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), + .. + }) }); match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) { @@ -689,42 +686,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { vec![ty_error; len] } - /// Unifies the output type with the expected type early, for more coercions - /// and forward type information on the input expressions. - #[instrument(skip(self, call_span), level = "debug")] - pub(crate) fn expected_inputs_for_expected_output( - &self, - call_span: Span, - expected_ret: Expectation<'tcx>, - formal_ret: Ty<'tcx>, - formal_args: &[Ty<'tcx>], - ) -> Option>> { - let formal_ret = self.resolve_vars_with_obligations(formal_ret); - let ret_ty = expected_ret.only_has_type(self)?; - - let expect_args = self - .fudge_inference_if_ok(|| { - let ocx = ObligationCtxt::new(self); - - // Attempt to apply a subtyping relationship between the formal - // return type (likely containing type variables if the function - // is polymorphic) and the expected return type. - // No argument expectations are produced if unification fails. - let origin = self.misc(call_span); - ocx.sup(&origin, self.param_env, ret_ty, formal_ret)?; - if !ocx.select_where_possible().is_empty() { - return Err(TypeError::Mismatch); - } - - // Record all the argument types, with the args - // produced from the above subtyping unification. - Ok(Some(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect())) - }) - .unwrap_or_default(); - debug!(?formal_args, ?formal_ret, ?expect_args, ?expected_ret); - expect_args - } - pub(crate) fn resolve_lang_item_path( &self, lang_item: hir::LangItem, @@ -896,38 +857,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } - /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a - /// suggestion can be made, `None` otherwise. + /// Given a `HirId`, return the `HirId` of the enclosing function and its `FnDecl`. pub(crate) fn get_fn_decl( &self, blk_id: HirId, - ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> { + ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>)> { // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or // `while` before reaching it, as block tail returns are not available in them. self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| { match self.tcx.hir_node(item_id) { Node::Item(&hir::Item { - ident, - kind: hir::ItemKind::Fn(ref sig, ..), - owner_id, - .. - }) => { - // This is less than ideal, it will not suggest a return type span on any - // method called `main`, regardless of whether it is actually the entry point, - // but it will still present it as the reason for the expected type. - Some((owner_id.def_id, sig.decl, ident.name != sym::main)) - } + kind: hir::ItemKind::Fn(ref sig, ..), owner_id, .. + }) => Some((owner_id.def_id, sig.decl)), Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(ref sig, ..), owner_id, .. - }) => Some((owner_id.def_id, sig.decl, true)), - // FIXME: Suggestable if this is not a trait implementation + }) => Some((owner_id.def_id, sig.decl)), Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, ..), owner_id, .. - }) => Some((owner_id.def_id, sig.decl, false)), + }) => Some((owner_id.def_id, sig.decl)), Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }), @@ -938,33 +889,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(async_closures): Implement this. return None; } - hir::ClosureKind::Closure => Some((def_id, fn_decl, true)), + hir::ClosureKind::Closure => Some((def_id, fn_decl)), hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( _, hir::CoroutineSource::Fn, )) => { - let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) { + let (sig, owner_id) = match self.tcx.parent_hir_node(hir_id) { Node::Item(&hir::Item { - ident, kind: hir::ItemKind::Fn(ref sig, ..), owner_id, .. - }) => (ident, sig, owner_id), + }) => (sig, owner_id), Node::TraitItem(&hir::TraitItem { - ident, kind: hir::TraitItemKind::Fn(ref sig, ..), owner_id, .. - }) => (ident, sig, owner_id), + }) => (sig, owner_id), Node::ImplItem(&hir::ImplItem { - ident, kind: hir::ImplItemKind::Fn(ref sig, ..), owner_id, .. - }) => (ident, sig, owner_id), + }) => (sig, owner_id), _ => return None, }; - Some((owner_id.def_id, sig.decl, ident.name != sym::main)) + Some((owner_id.def_id, sig.decl)) } _ => None, } @@ -1018,16 +966,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut sp = MultiSpan::from_span(path_segment.ident.span); sp.push_span_label( path_segment.ident.span, - format!( - "this call modifies {} in-place", - match rcvr.kind { - ExprKind::Path(QPath::Resolved( - None, - hir::Path { segments: [segment], .. }, - )) => format!("`{}`", segment.ident), - _ => "its receiver".to_string(), - } - ), + format!("this call modifies {} in-place", match rcvr.kind { + ExprKind::Path(QPath::Resolved(None, hir::Path { segments: [segment], .. })) => + format!("`{}`", segment.ident), + _ => "its receiver".to_string(), + }), ); let modifies_rcvr_note = @@ -1284,7 +1227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer_args_for_err: &'a FxHashSet, segments: &'tcx [hir::PathSegment<'tcx>], } - impl<'tcx, 'a> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> { + impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> { fn args_for_def_id( &mut self, def_id: DefId, @@ -1438,10 +1381,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This also occurs for an enum variant on a type alias. let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args)); let self_ty = self.normalize(span, self_ty); - match self.at(&self.misc(span), self.param_env).sub( + match self.at(&self.misc(span), self.param_env).eq( DefineOpaqueTypes::Yes, - self_ty, impl_ty, + self_ty, ) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { @@ -1527,6 +1470,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self, sp), ret)] + pub fn try_structurally_resolve_const(&self, sp: Span, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + // FIXME(min_const_generic_exprs): We could process obligations here if `ct` is a var. + + if self.next_trait_solver() + && let ty::ConstKind::Unevaluated(..) = ct.kind() + { + // We need to use a separate variable here as otherwise the temporary for + // `self.fulfillment_cx.borrow_mut()` is alive in the `Err` branch, resulting + // in a reentrant borrow, causing an ICE. + let result = self + .at(&self.misc(sp), self.param_env) + .structurally_normalize_const(ct, &mut **self.fulfillment_cx.borrow_mut()); + match result { + Ok(normalized_ct) => normalized_ct, + Err(errors) => { + let guar = self.err_ctxt().report_fulfillment_errors(errors); + return ty::Const::new_error(self.tcx, guar); + } + } + } else if self.tcx.features().generic_const_exprs { + ct.normalize(self.tcx, self.param_env) + } else { + ct + } + } + /// Resolves `ty` by a single level if `ty` is a type variable. /// /// When the new solver is enabled, this will also attempt to normalize diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index a8ba9f139cc7e..f93d0e9340613 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -5,8 +5,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; use rustc_trait_selection::traits; use crate::FnCtxt; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs index cb77d3f85d935..358bc389bd138 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs @@ -307,7 +307,7 @@ impl<'tcx> ArgMatrix<'tcx> { permutation.into_iter().map(|x| x.unwrap()).collect(); return Some(Issue::Permutation(final_permutation)); } - return None; + None } // Obviously, detecting exact user intention is impossible, so the goal here is to @@ -410,6 +410,6 @@ impl<'tcx> ArgMatrix<'tcx> { // sort errors with same type by the order they appear in the source // so that suggestion will be handled properly, see #112507 errors.sort(); - return (errors, matched_inputs); + (errors, matched_inputs) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index eebb0217990df..550c58b5a17c6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -4,8 +4,8 @@ use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; use rustc_errors::{ - a_or_an, display_list_with_comma_and, pluralize, Applicability, Diag, ErrorGuaranteed, - MultiSpan, StashKey, + Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, + display_list_with_comma_and, pluralize, }; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -17,32 +17,33 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_index::IndexVec; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace}; use rustc_middle::ty::adjustment::AllowTwoPhase; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::Session; -use rustc_span::symbol::{kw, Ident}; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, kw}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; +use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext}; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; +use crate::Expectation::*; +use crate::TupleArgumentsFlag::*; use crate::coercion::CoerceMany; use crate::errors::SuggestPtrNullMut; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; use crate::fn_ctxt::infer::FnCall; use crate::gather_locals::Declaration; +use crate::method::MethodCallee; use crate::method::probe::IsSuggestion; use crate::method::probe::Mode::MethodCall; use crate::method::probe::ProbeScope::TraitsInScope; -use crate::method::MethodCallee; -use crate::Expectation::*; -use crate::TupleArgumentsFlag::*; use crate::{ - errors, struct_span_code_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, - TupleArgumentsFlag, + BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, TupleArgumentsFlag, errors, + struct_span_code_err, }; #[derive(Clone, Copy, Default)] @@ -124,6 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Err(guar) = has_error { let err_inputs = self.err_args(args_no_rcvr.len(), guar); + let err_output = Ty::new_error(self.tcx, guar); let err_inputs = match tuple_arguments { DontTupleArguments => err_inputs, @@ -134,28 +136,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, expr, &err_inputs, - None, + err_output, + NoExpectation, args_no_rcvr, false, tuple_arguments, method.ok().map(|method| method.def_id), ); - return Ty::new_error(self.tcx, guar); + return err_output; } let method = method.unwrap(); - // HACK(eddyb) ignore self in the definition (see above). - let expected_input_tys = self.expected_inputs_for_expected_output( - sp, - expected, - method.sig.output(), - &method.sig.inputs()[1..], - ); self.check_argument_types( sp, expr, &method.sig.inputs()[1..], - expected_input_tys, + method.sig.output(), + expected, args_no_rcvr, method.sig.c_variadic, tuple_arguments, @@ -175,8 +172,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &'tcx hir::Expr<'tcx>, // Types (as defined in the *signature* of the target function) formal_input_tys: &[Ty<'tcx>], - // More specific expected types, after unifying with caller output types - expected_input_tys: Option>>, + formal_output: Ty<'tcx>, + // Expected output from the parent expression or statement + expectation: Expectation<'tcx>, // The expressions for each provided argument provided_args: &'tcx [hir::Expr<'tcx>], // Whether the function is variadic, for example when imported from C @@ -210,6 +208,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + // First, let's unify the formal method signature with the expectation eagerly. + // We use this to guide coercion inference; it's output is "fudged" which means + // any remaining type variables are assigned to new, unrelated variables. This + // is because the inference guidance here is only speculative. + let formal_output = self.resolve_vars_with_obligations(formal_output); + let expected_input_tys: Option> = expectation + .only_has_type(self) + .and_then(|expected_output| { + self.fudge_inference_if_ok(|| { + let ocx = ObligationCtxt::new(self); + + // Attempt to apply a subtyping relationship between the formal + // return type (likely containing type variables if the function + // is polymorphic) and the expected return type. + // No argument expectations are produced if unification fails. + let origin = self.misc(call_span); + ocx.sup(&origin, self.param_env, expected_output, formal_output)?; + if !ocx.select_where_possible().is_empty() { + return Err(TypeError::Mismatch); + } + + // Record all the argument types, with the args + // produced from the above subtyping unification. + Ok(Some( + formal_input_tys + .iter() + .map(|&ty| self.resolve_vars_if_possible(ty)) + .collect(), + )) + }) + .ok() + }) + .unwrap_or_default(); + let mut err_code = E0061; // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here @@ -292,21 +324,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerce_error = self.coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None).err(); - if coerce_error.is_some() { return Compatibility::Incompatible(coerce_error); } - // 3. Check if the formal type is a supertype of the checked one - // and register any such obligations for future type checks - let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup( + // 3. Check if the formal type is actually equal to the checked one + // and register any such obligations for future type checks. + let formal_ty_error = self.at(&self.misc(provided_arg.span), self.param_env).eq( DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty, ); // If neither check failed, the types are compatible - match supertype_error { + match formal_ty_error { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); Compatibility::Compatible @@ -475,6 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_def_id, call_span, call_expr, + tuple_arguments, ); } } @@ -489,6 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_def_id: Option, call_span: Span, call_expr: &'tcx hir::Expr<'tcx>, + tuple_arguments: TupleArgumentsFlag, ) -> ErrorGuaranteed { // Next, let's construct the error let (error_span, call_ident, full_call_span, call_name, is_method) = match &call_expr.kind { @@ -834,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); suggest_confusable(&mut err); return err.emit(); @@ -970,6 +1004,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); suggest_confusable(&mut err); return err.emit(); @@ -1417,6 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); // And add a suggestion block for all of the parameters @@ -1842,7 +1878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that highlight errors inline. let mut sp = blk.span; let mut fn_span = None; - if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) { + if let Some((fn_def_id, decl)) = self.get_fn_decl(blk.hir_id) { let ret_sp = decl.output.span(); if let Some(block_sp) = self.parent_item_span(blk.hir_id) { // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the @@ -2188,21 +2224,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { matched_inputs: &IndexVec>, formal_and_expected_inputs: &IndexVec, Ty<'tcx>)>, is_method: bool, + tuple_arguments: TupleArgumentsFlag, ) { let Some(mut def_id) = callable_def_id else { return; }; + // If we're calling a method of a Fn/FnMut/FnOnce trait object implicitly + // (eg invoking a closure) we want to point at the underlying callable, + // not the method implicitly invoked (eg call_once). if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) - // Possibly points at either impl or trait item, so try to get it - // to point to trait item, then get the parent. - // This parent might be an impl in the case of an inherent function, - // but the next check will fail. + // Since this is an associated item, it might point at either an impl or a trait item. + // We want it to always point to the trait item. + // If we're pointing at an inherent function, we don't need to do anything, + // so we fetch the parent and verify if it's a trait item. && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id) && let Some(callee_ty) = callee_ty + // TupleArguments is set only when this is an implicit call (my_closure(...)) rather than explicit (my_closure.call(...)) + && tuple_arguments == TupleArguments { let callee_ty = callee_ty.peel_refs(); match *callee_ty.kind() { @@ -2272,166 +2314,173 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let mut spans: MultiSpan = def_span.into(); - let params_with_generics = self.get_hir_params_with_generics(def_id, is_method); - let mut generics_with_unmatched_params = Vec::new(); + if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) + { + debug_assert_eq!(params_with_generics.len(), matched_inputs.len()); - let check_for_matched_generics = || { - if matched_inputs.iter().any(|x| x.is_some()) - && params_with_generics.iter().any(|x| x.0.is_some()) - { - for (idx, (generic, _)) in params_with_generics.iter().enumerate() { - // Param has to have a generic and be matched to be relevant - if matched_inputs[idx.into()].is_none() { - continue; - } + let mut generics_with_unmatched_params = Vec::new(); - let Some(generic) = generic else { - continue; - }; + let check_for_matched_generics = || { + if matched_inputs.iter().any(|x| x.is_some()) + && params_with_generics.iter().any(|x| x.0.is_some()) + { + for (idx, (generic, _)) in params_with_generics.iter().enumerate() { + // Param has to have a generic and be matched to be relevant + if matched_inputs[idx.into()].is_none() { + continue; + } - for unmatching_idx in idx + 1..params_with_generics.len() { - if matched_inputs[unmatching_idx.into()].is_none() - && let Some(unmatched_idx_param_generic) = - params_with_generics[unmatching_idx].0 - && unmatched_idx_param_generic.name.ident() == generic.name.ident() - { - // We found a parameter that didn't match that needed to - return true; + let Some(generic) = generic else { + continue; + }; + + for unmatching_idx in idx + 1..params_with_generics.len() { + if matched_inputs[unmatching_idx.into()].is_none() + && let Some(unmatched_idx_param_generic) = + params_with_generics[unmatching_idx].0 + && unmatched_idx_param_generic.name.ident() + == generic.name.ident() + { + // We found a parameter that didn't match that needed to + return true; + } } } } - } - false - }; - - let check_for_matched_generics = check_for_matched_generics(); - - for (idx, (generic_param, param)) in - params_with_generics.iter().enumerate().filter(|(idx, _)| { - check_for_matched_generics - || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) - }) - { - let Some(generic_param) = generic_param else { - spans.push_span_label(param.span, ""); - continue; + false }; - let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics - .iter() - .enumerate() - .filter(|(other_idx, (other_generic_param, _))| { - if *other_idx == idx { - return false; - } - let Some(other_generic_param) = other_generic_param else { - return false; - }; - if matched_inputs[idx.into()].is_none() - && matched_inputs[(*other_idx).into()].is_none() - { - return false; - } - if matched_inputs[idx.into()].is_some() - && matched_inputs[(*other_idx).into()].is_some() - { - return false; - } - other_generic_param.name.ident() == generic_param.name.ident() + let check_for_matched_generics = check_for_matched_generics(); + + for (idx, (generic_param, param)) in + params_with_generics.iter().enumerate().filter(|(idx, _)| { + check_for_matched_generics + || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) }) - .map(|(other_idx, (_, other_param))| (other_idx, *other_param)) - .collect(); + { + let Some(generic_param) = generic_param else { + spans.push_span_label(param.span, ""); + continue; + }; - if !other_params_matched.is_empty() { - let other_param_matched_names: Vec = other_params_matched + let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics .iter() - .map(|(_, other_param)| { - if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind { - format!("`{ident}`") - } else { - "{unknown}".to_string() + .enumerate() + .filter(|(other_idx, (other_generic_param, _))| { + if *other_idx == idx { + return false; + } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[idx.into()].is_none() + && matched_inputs[(*other_idx).into()].is_none() + { + return false; } + if matched_inputs[idx.into()].is_some() + && matched_inputs[(*other_idx).into()].is_some() + { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() }) + .map(|(other_idx, (_, other_param))| (other_idx, *other_param)) .collect(); - let matched_ty = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) - .sort_string(self.tcx); + if !other_params_matched.is_empty() { + let other_param_matched_names: Vec = other_params_matched + .iter() + .map(|(_, other_param)| { + if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind + { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); - if matched_inputs[idx.into()].is_some() { - spans.push_span_label( - param.span, - format!( - "{} {} to match the {} type of this parameter", - display_list_with_comma_and(&other_param_matched_names), + let matched_ty = self + .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .sort_string(self.tcx); + + if matched_inputs[idx.into()].is_some() { + spans.push_span_label( + param.span, format!( - "need{}", - pluralize!(if other_param_matched_names.len() == 1 { - 0 - } else { - 1 - }) + "{} {} to match the {} type of this parameter", + display_list_with_comma_and(&other_param_matched_names), + format!( + "need{}", + pluralize!(if other_param_matched_names.len() == 1 { + 0 + } else { + 1 + }) + ), + matched_ty, ), - matched_ty, - ), - ); + ); + } else { + spans.push_span_label( + param.span, + format!( + "this parameter needs to match the {} type of {}", + matched_ty, + display_list_with_comma_and(&other_param_matched_names), + ), + ); + } + generics_with_unmatched_params.push(generic_param); } else { + spans.push_span_label(param.span, ""); + } + } + + for generic_param in self + .tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.generics()) + .into_iter() + .flat_map(|x| x.params) + .filter(|x| { + generics_with_unmatched_params + .iter() + .any(|y| x.name.ident() == y.name.ident()) + }) + { + let param_idents_matching: Vec = params_with_generics + .iter() + .filter(|(generic, _)| { + if let Some(generic) = generic { + generic.name.ident() == generic_param.name.ident() + } else { + false + } + }) + .map(|(_, param)| { + if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); + + if !param_idents_matching.is_empty() { spans.push_span_label( - param.span, + generic_param.span, format!( - "this parameter needs to match the {} type of {}", - matched_ty, - display_list_with_comma_and(&other_param_matched_names), + "{} all reference this parameter {}", + display_list_with_comma_and(¶m_idents_matching), + generic_param.name.ident().name, ), ); } - generics_with_unmatched_params.push(generic_param); - } else { - spans.push_span_label(param.span, ""); - } - } - - for generic_param in self - .tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.generics()) - .into_iter() - .flat_map(|x| x.params) - .filter(|x| { - generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident()) - }) - { - let param_idents_matching: Vec = params_with_generics - .iter() - .filter(|(generic, _)| { - if let Some(generic) = generic { - generic.name.ident() == generic_param.name.ident() - } else { - false - } - }) - .map(|(_, param)| { - if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { - format!("`{ident}`") - } else { - "{unknown}".to_string() - } - }) - .collect(); - - if !param_idents_matching.is_empty() { - spans.push_span_label( - generic_param.span, - format!( - "{} all reference this parameter {}", - display_list_with_comma_and(¶m_idents_matching), - generic_param.name.ident().name, - ), - ); } } - err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind @@ -2504,74 +2553,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - let params_with_generics = self.get_hir_params_with_generics(def_id, is_method); - - for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() { - if matched_inputs[idx.into()].is_none() { - continue; - } + if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) { + debug_assert_eq!(params_with_generics.len(), matched_inputs.len()); + for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() { + if matched_inputs[idx.into()].is_none() { + continue; + } - let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else { - continue; - }; + let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else { + continue; + }; - let Some(generic_param) = generic_param else { - continue; - }; + let Some(generic_param) = generic_param else { + continue; + }; - let mut idxs_matched: Vec = vec![]; - for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter( - |(other_idx, (other_generic_param, _))| { - if *other_idx == idx { - return false; - } - let Some(other_generic_param) = other_generic_param else { - return false; - }; - if matched_inputs[(*other_idx).into()].is_some() { - return false; - } - other_generic_param.name.ident() == generic_param.name.ident() - }, - ) { - idxs_matched.push(other_idx.into()); - } + let mut idxs_matched: Vec = vec![]; + for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter( + |(other_idx, (other_generic_param, _))| { + if *other_idx == idx { + return false; + } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[(*other_idx).into()].is_some() { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() + }, + ) { + idxs_matched.push(other_idx); + } - if idxs_matched.is_empty() { - continue; - } + if idxs_matched.is_empty() { + continue; + } - let expected_display_type = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) - .sort_string(self.tcx); - let label = if idxs_matched.len() == params_with_generics.len() - 1 { - format!( - "expected all arguments to be this {} type because they need to match the type of this parameter", - expected_display_type - ) - } else { - format!( - "expected some other arguments to be {} {} type to match the type of this parameter", - a_or_an(&expected_display_type), - expected_display_type, - ) - }; + let expected_display_type = self + .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .sort_string(self.tcx); + let label = if idxs_matched.len() == params_with_generics.len() - 1 { + format!( + "expected all arguments to be this {} type because they need to match the type of this parameter", + expected_display_type + ) + } else { + format!( + "expected some other arguments to be {} {} type to match the type of this parameter", + a_or_an(&expected_display_type), + expected_display_type, + ) + }; - err.span_label(*matched_arg_span, label); + err.span_label(*matched_arg_span, label); + } } } + /// Returns the parameters of a function, with their generic parameters if those are the full + /// type of that parameter. Returns `None` if the function body is unavailable (eg is an instrinsic). fn get_hir_params_with_generics( &self, def_id: DefId, is_method: bool, - ) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> { - let fn_node = self.tcx.hir().get_if_local(def_id); + ) -> Option>, &hir::Param<'_>)>> { + let fn_node = self.tcx.hir().get_if_local(def_id)?; + let fn_decl = fn_node.fn_decl()?; - let generic_params: Vec>> = fn_node - .and_then(|node| node.fn_decl()) + let generic_params: Vec>> = fn_decl + .inputs .into_iter() - .flat_map(|decl| decl.inputs) .skip(if is_method { 1 } else { 0 }) .map(|param| { if let hir::TyKind::Path(QPath::Resolved( @@ -2580,7 +2632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )) = param.kind { fn_node - .and_then(|node| node.generics()) + .generics() .into_iter() .flat_map(|generics| generics.params) .find(|param| ¶m.def_id.to_def_id() == res_def_id) @@ -2590,14 +2642,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect(); - let params: Vec<&hir::Param<'_>> = fn_node - .and_then(|node| node.body_id()) + let mut params: Vec<&hir::Param<'_>> = self + .tcx + .hir() + .body(fn_node.body_id()?) + .params .into_iter() - .flat_map(|id| self.tcx.hir().body(id).params) .skip(if is_method { 1 } else { 0 }) .collect(); - generic_params.into_iter().zip(params).collect() + // The surrounding code expects variadic functions to not have a parameter representing + // the "..." parameter. This is already true of the FnDecl but not of the body params, so + // we drop it if it exists. + + if fn_decl.c_variadic { + params.pop(); + } + + debug_assert_eq!(params.len(), generic_params.len()); + Some(generic_params.into_iter().zip(params).collect()) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index a43d7aa31a522..e60bd1a312a1b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -17,9 +17,9 @@ use rustc_infer::infer; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; -use rustc_span::{self, sym, Span, DUMMY_SP}; -use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations; +use rustc_span::{self, DUMMY_SP, Span, sym}; use rustc_trait_selection::error_reporting::TypeErrCtxt; +use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; use crate::coercion::DynamicCoerceMany; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 4454703645e79..5f89f7dedc2cc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -19,15 +19,15 @@ use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, suggest_constraining_type_params, Article, Binder, IsSuggestable, Ty, TyCtxt, - TypeVisitableExt, Upcast, + self, Article, Binder, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Upcast, + suggest_constraining_type_params, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{Ident, sym}; use rustc_span::{Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -79,9 +79,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `break` type mismatches provide better context for tail `loop` expressions. return false; } - if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { + if let Some((fn_id, fn_decl)) = self.get_fn_decl(blk_id) { pointing_at_return_type = - self.suggest_missing_return_type(err, fn_decl, expected, found, can_suggest, fn_id); + self.suggest_missing_return_type(err, fn_decl, expected, found, fn_id); self.suggest_missing_break_or_return_expr( err, expr, fn_decl, expected, found, blk_id, fn_id, ); @@ -813,7 +813,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_decl: &hir::FnDecl<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, - can_suggest: bool, fn_id: LocalDefId, ) -> bool { // Can't suggest `->` on a block-like coroutine @@ -826,28 +825,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let found = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found)); // Only suggest changing the return type for methods that - // haven't set a return type at all (and aren't `fn main()` or an impl). + // haven't set a return type at all (and aren't `fn main()`, impl or closure). match &fn_decl.output { - &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => { - // `fn main()` must return `()`, do not suggest changing return type - err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span }); - return true; - } + // For closure with default returns, don't suggest adding return type + &hir::FnRetTy::DefaultReturn(_) if self.tcx.is_closure_like(fn_id.to_def_id()) => {} &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { - if let Some(found) = found.make_suggestable(self.tcx, false, None) { + if !self.can_add_return_type(fn_id) { + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span }); + } else if let Some(found) = found.make_suggestable(self.tcx, false, None) { err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string(), }); - return true; } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) { err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg }); - return true; } else { // FIXME: if `found` could be `impl Iterator` we should suggest that. err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span }); - return true; } + + return true; } hir::FnRetTy::Return(hir_ty) => { if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind @@ -905,6 +902,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + /// Checks whether we can add a return type to a function. + /// Assumes given function doesn't have a explicit return type. + fn can_add_return_type(&self, fn_id: LocalDefId) -> bool { + match self.tcx.hir_node_by_def_id(fn_id) { + Node::Item(&hir::Item { ident, .. }) => { + // This is less than ideal, it will not suggest a return type span on any + // method called `main`, regardless of whether it is actually the entry point, + // but it will still present it as the reason for the expected type. + ident.name != sym::main + } + Node::ImplItem(item) => { + // If it doesn't impl a trait, we can add a return type + let Node::Item(&hir::Item { + kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }), + .. + }) = self.tcx.parent_hir_node(item.hir_id()) + else { + unreachable!(); + }; + + of_trait.is_none() + } + _ => true, + } + } + fn try_note_caller_chooses_ty_for_ty_param( &self, diag: &mut Diag<'_>, @@ -1479,7 +1502,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create an dummy type `&[_]` so that both &[] and `&Vec` can coerce to it. let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind() && let ty::Infer(_) = elem_ty.kind() - && size.try_eval_target_usize(self.tcx, self.param_env) == Some(0) + && self + .try_structurally_resolve_const(provided_expr.span, *size) + .try_to_target_usize(self.tcx) + == Some(0) { let slice = Ty::new_slice(self.tcx, *elem_ty); Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice) @@ -1978,17 +2004,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.kind, hir::ExprKind::Call( hir::Expr { - kind: hir::ExprKind::Path(hir::QPath::Resolved( - None, - hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. }, - )), + kind: hir::ExprKind::Path(hir::QPath::Resolved(None, hir::Path { + res: Res::Def(hir::def::DefKind::Ctor(_, _), _), + .. + },)), .. }, .., - ) | hir::ExprKind::Path(hir::QPath::Resolved( - None, - hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. }, - )), + ) | hir::ExprKind::Path(hir::QPath::Resolved(None, hir::Path { + res: Res::Def(hir::def::DefKind::Ctor(_, _), _), + .. + },)), ); let (article, kind, variant, sugg_operator) = @@ -2028,7 +2054,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = expr.span.find_oldest_ancestor_in_same_ctxt(); err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders); - return true; + true } pub(crate) fn suggest_coercing_result_via_try_operator( diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 4ea22884cf376..83c9a4878d2f8 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -3,8 +3,8 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, PatKind}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::{Ty, UserType}; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use tracing::debug; use crate::FnCtxt; @@ -158,14 +158,12 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { ), ); } - } else { - if !self.fcx.tcx.features().unsized_locals { - self.fcx.require_type_is_sized( - var_ty, - p.span, - ObligationCauseCode::VariableType(p.hir_id), - ); - } + } else if !self.fcx.tcx.features().unsized_locals { + self.fcx.require_type_is_sized( + var_ty, + p.span, + ObligationCauseCode::VariableType(p.hir_id), + ); } debug!( diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index f39d83a2a6f79..a4121adf628af 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -95,13 +95,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{v} bits") } else { // `u128` should definitely be able to hold the size of different architectures - // larger sizes should be reported as error `are too big for the current architecture` + // larger sizes should be reported as error `are too big for the target architecture` // otherwise we have a bug somewhere bug!("{:?} overflow for u128", size) } } Ok(SizeSkeleton::Generic(size)) => { - if let Some(size) = size.try_eval_target_usize(tcx, self.param_env) { + if let Some(size) = + self.try_structurally_resolve_const(span, size).try_to_target_usize(tcx) + { format!("{size} bytes") } else { format!("generic size {size}") diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index caf09c1177fd3..f8352d9d44a97 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -43,7 +43,7 @@ pub use coercion::can_coerce; use fn_ctxt::FnCtxt; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed}; +use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -55,8 +55,8 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use tracing::{debug, instrument}; use typeck_root_ctxt::TypeckRootCtxt; @@ -423,6 +423,36 @@ fn report_unexpected_variant_res( err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect); err } + Res::Def(DefKind::Variant, _) if expr.is_none() => { + err.span_label(span, format!("not a {expected}")); + + let fields = &tcx.expect_variant_res(res).fields.raw; + let span = qpath.span().shrink_to_hi().to(span.shrink_to_hi()); + let (msg, sugg) = if fields.is_empty() { + ("use the struct variant pattern syntax".to_string(), " {}".to_string()) + } else { + let msg = format!( + "the struct variant's field{s} {are} being ignored", + s = pluralize!(fields.len()), + are = pluralize!("is", fields.len()) + ); + let fields = fields + .iter() + .map(|field| format!("{}: _", field.name.to_ident_string())) + .collect::>() + .join(", "); + let sugg = format!(" {{ {} }}", fields); + (msg, sugg) + }; + + err.span_suggestion_verbose( + qpath.span().shrink_to_hi().to(span.shrink_to_hi()), + msg, + sugg, + Applicability::HasPlaceholders, + ); + err + } _ => err.with_span_label(span, format!("not a {expected}")), } .emit() diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index faeabdc082109..e3b0fa78eb705 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -1,8 +1,8 @@ use std::ops::Deref; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; +use rustc_hir::def_id::DefId; use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; @@ -20,12 +20,12 @@ use rustc_middle::ty::{ UserType, }; use rustc_middle::{bug, span_bug}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits; use tracing::debug; -use super::{probe, MethodCallee}; -use crate::{callee, FnCtxt}; +use super::{MethodCallee, probe}; +use crate::{FnCtxt, callee}; struct ConfirmContext<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -249,7 +249,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } /// Returns a set of generic parameters for the method *receiver* where all type and region - /// parameters are instantiated with fresh variables. This generic paramters does not include any + /// parameters are instantiated with fresh variables. This generic parameters does not include any /// parameters declared on the method itself. /// /// Note that this generic parameters may include late-bound regions from the impl level. If so, @@ -375,7 +375,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { IsMethodCall::Yes, ); - // Create generic paramters for early-bound lifetime parameters, + // Create generic parameters for early-bound lifetime parameters, // combining parameters from the type and those from the method. assert_eq!(generics.parent_count, parent_args.len()); @@ -546,7 +546,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args); // Instantiate the bounds on the method with the - // type/early-bound-regions instatiations performed. There can + // type/early-bound-regions instantiations performed. There can // be no late-bound regions appearing here. let def_id = pick.item.def_id; let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args); diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 7019b718b16e8..586b753f45493 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -18,14 +18,14 @@ use rustc_middle::ty::{ self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TypeVisitableExt, }; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, NormalizeExt}; use tracing::{debug, instrument}; -use self::probe::{IsSuggestion, ProbeScope}; pub(crate) use self::MethodError::*; +use self::probe::{IsSuggestion, ProbeScope}; use crate::FnCtxt; pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 0790c6f9a5992..a8b5b6165db06 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -8,14 +8,14 @@ use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty}; use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS}; -use rustc_span::symbol::kw::{Empty, Underscore}; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_span::symbol::kw::{Empty, Underscore}; +use rustc_span::symbol::{Ident, sym}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; -use crate::method::probe::{self, Pick}; use crate::FnCtxt; +use crate::method::probe::{self, Pick}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn lint_edition_dependent_dot_call( @@ -63,8 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Instead, the problem is that the array-into_iter hack will no longer // apply in Rust 2021. (ARRAY_INTO_ITER, "2021") - } else if self_ty.is_box() - && self_ty.boxed_ty().is_slice() + } else if self_ty.boxed_ty().is_some_and(Ty::is_slice) && !span.at_least_rust_2024() { // In this case, it wasn't really a prelude addition that was the problem. diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 0cf5403b3c085..1a8afcf003d20 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -6,15 +6,15 @@ use std::ops::Deref; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::HirId; +use rustc_hir::def::DefKind; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::middle::stability; use rustc_middle::query::Providers; -use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; +use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::{ self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast, @@ -25,22 +25,22 @@ use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::edit_distance::{ edit_distance_with_substrings, find_best_match_for_name_with_substrings, }; -use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::symbol::{Ident, sym}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::query::CanonicalTyGoal; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::{ CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult, }; -use rustc_trait_selection::traits::query::CanonicalTyGoal; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt}; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; use self::CandidateKind::*; pub(crate) use self::PickKind::*; -use super::{suggest, CandidateSource, MethodError, NoMatchData}; +use super::{CandidateSource, MethodError, NoMatchData, suggest}; use crate::FnCtxt; /// Boolean flag used to indicate if this search is for a suggestion @@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If our autoderef loop had reached the recursion limit, // report an overflow error, but continue going on with // the truncated autoderef list. - if steps.reached_recursion_limit { + if steps.reached_recursion_limit && !is_suggestion.0 { self.probe(|_| { let ty = &steps .steps @@ -403,7 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mode, })); } else if bad_ty.reached_raw_pointer - && !self.tcx.features().arbitrary_self_types + && !self.tcx.features().arbitrary_self_types_pointers && !self.tcx.sess.at_least_rust_2018() { // this case used to be allowed by the compiler, @@ -621,6 +621,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.unsatisfied_predicates.borrow_mut().clear(); } + /// When we're looking up a method by path (UFCS), we relate the receiver + /// types invariantly. When we are looking up a method by the `.` operator, + /// we relate them covariantly. + fn variance(&self) -> ty::Variance { + match self.mode { + Mode::MethodCall => ty::Covariant, + Mode::Path => ty::Invariant, + } + } + /////////////////////////////////////////////////////////////////////////// // CANDIDATE ASSEMBLY @@ -715,16 +725,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) { - let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else { + let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer) else { bug!("unexpected incoherent type: {:?}", self_ty) }; - for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter().flatten() { + for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter() { self.assemble_inherent_impl_probe(impl_def_id); } } fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { - let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id).into_iter().flatten(); + let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id).into_iter(); for &impl_def_id in impl_def_ids { self.assemble_inherent_impl_probe(impl_def_id); } @@ -1443,7 +1453,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, impl_ty, impl_args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + match ocx.relate(cause, self.param_env, self.variance(), self_ty, xform_self_ty) + { Ok(()) => {} Err(err) => { debug!("--> cannot relate self-types {:?}", err); @@ -1485,8 +1496,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Some trait methods are excluded for boxed slices before 2024. // (`boxed_slice.into_iter()` wants a slice iterator for compatibility.) - if self_ty.is_box() - && self_ty.boxed_ty().is_slice() + if self_ty.boxed_ty().is_some_and(Ty::is_slice) && !method_name.span.at_least_rust_2024() { let trait_def = self.tcx.trait_def(poly_trait_ref.def_id()); @@ -1515,7 +1525,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { { return ProbeResult::NoMatch; } - _ => match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + _ => match ocx.relate( + cause, + self.param_env, + self.variance(), + self_ty, + xform_self_ty, + ) { Ok(()) => {} Err(err) => { debug!("--> cannot relate self-types {:?}", err); @@ -1561,7 +1577,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + match ocx.relate(cause, self.param_env, self.variance(), self_ty, xform_self_ty) + { Ok(()) => {} Err(err) => { debug!("--> cannot relate self-types {:?}", err); @@ -1604,7 +1621,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty); - match ocx.sup(cause, self.param_env, return_ty, xform_ret_ty) { + match ocx.relate(cause, self.param_env, self.variance(), xform_ret_ty, return_ty) { Ok(()) => {} Err(_) => { result = ProbeResult::BadReturnType; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9ea57e4aa6168..e03be4f43f73d 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, Diag, MultiSpan, StashKey}; +use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -21,21 +21,21 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath}; use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_middle::bug; -use rustc_middle::ty::fast_reject::{simplify_type, DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; use rustc_middle::ty::print::{ - with_crate_prefix, with_forced_trimmed_paths, PrintTraitRefExt as _, + PrintTraitRefExt as _, with_crate_prefix, with_forced_trimmed_paths, }; use rustc_middle::ty::{self, GenericArgKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::DefIdSet; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{ - edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span, Symbol, DUMMY_SP, + DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span, Symbol, edit_distance, }; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ - supertraits, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, + FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, supertraits, }; use tracing::{debug, info, instrument}; @@ -62,14 +62,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // It might seem that we can use `predicate_must_hold_modulo_regions`, // but since a Dummy binder is used to fill in the FnOnce trait's arguments, // type resolution always gives a "maybe" here. - if self.autoderef(span, ty).any(|(ty, _)| { + if self.autoderef(span, ty).silence_errors().any(|(ty, _)| { info!("check deref {:?} error", ty); matches!(ty.kind(), ty::Error(_) | ty::Infer(_)) }) { return false; } - self.autoderef(span, ty).any(|(ty, _)| { + self.autoderef(span, ty).silence_errors().any(|(ty, _)| { info!("check deref {:?} impl FnOnce", ty); self.probe(|_| { let trait_ref = @@ -90,7 +90,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { - self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) + self.autoderef(span, ty) + .silence_errors() + .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) } fn impl_into_iterator_should_be_iterator( @@ -672,13 +674,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut ty_str_reported = ty_str.clone(); if let ty::Adt(_, generics) = rcvr_ty.kind() { if generics.len() > 0 { - let mut autoderef = self.autoderef(span, rcvr_ty); + let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors(); let candidate_found = autoderef.any(|(ty, _)| { if let ty::Adt(adt_def, _) = ty.kind() { self.tcx .inherent_impls(adt_def.did()) .into_iter() - .flatten() .any(|def_id| self.associated_value(*def_id, item_name).is_some()) } else { false @@ -1252,11 +1253,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && suggested_bounds.contains(parent) { // We don't suggest `PartialEq` when we already suggest `Eq`. - } else if !suggested_bounds.contains(pred) { - if collect_type_param_suggestions(self_ty, *pred, &p) { - suggested = true; - suggested_bounds.insert(pred); - } + } else if !suggested_bounds.contains(pred) + && collect_type_param_suggestions(self_ty, *pred, &p) + { + suggested = true; + suggested_bounds.insert(pred); } ( match parent_pred { @@ -1267,14 +1268,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !suggested && !suggested_bounds.contains(pred) && !suggested_bounds.contains(parent_pred) - { - if collect_type_param_suggestions( + && collect_type_param_suggestions( self_ty, *parent_pred, &p, - ) { - suggested_bounds.insert(pred); - } + ) + { + suggested_bounds.insert(pred); } format!("`{p}`\nwhich is required by `{parent_p}`") } @@ -1317,7 +1317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let actual_prefix = rcvr_ty.prefix_string(self.tcx); info!("unimplemented_traits.len() == {}", unimplemented_traits.len()); let mut long_ty_file = None; - let (primary_message, label) = if unimplemented_traits.len() == 1 + let (primary_message, label, notes) = if unimplemented_traits.len() == 1 && unimplemented_traits_only { unimplemented_traits @@ -1327,16 +1327,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if trait_ref.self_ty().references_error() || rcvr_ty.references_error() { // Avoid crashing. - return (None, None); + return (None, None, Vec::new()); } - let OnUnimplementedNote { message, label, .. } = self + let OnUnimplementedNote { message, label, notes, .. } = self .err_ctxt() .on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file); - (message, label) + (message, label, notes) }) .unwrap() } else { - (None, None) + (None, None, Vec::new()) }; let primary_message = primary_message.unwrap_or_else(|| { format!( @@ -1363,6 +1363,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the following trait bounds were not satisfied:\n{bound_list}" )); } + for note in notes { + err.note(note); + } + suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates); unsatisfied_bounds = true; @@ -1433,7 +1437,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .inherent_impls(adt.did()) .into_iter() - .flatten() .copied() .filter(|def_id| { if let Some(assoc) = self.associated_value(*def_id, item_name) { @@ -1716,20 +1719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() { - let msg = "remove this method call"; - let mut fallback_span = true; - if let SelfSource::MethodCall(expr) = source { - let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)); - if let Some(span) = call_expr.span.trim_start(expr.span) { - err.span_suggestion(span, msg, "", Applicability::MachineApplicable); - fallback_span = false; - } - } - if fallback_span { - err.span_label(span, msg); - } - } else if let Some(similar_candidate) = similar_candidate { + if let Some(similar_candidate) = similar_candidate { // Don't emit a suggestion if we found an actual method // that had unsatisfied trait bounds if unsatisfied_predicates.is_empty() @@ -1908,7 +1898,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_args: Option>>, ) -> Option { if let ty::Adt(adt, adt_args) = rcvr_ty.kind() { - for inherent_impl_did in self.tcx.inherent_impls(adt.did()).into_iter().flatten() { + for inherent_impl_did in self.tcx.inherent_impls(adt.did()).into_iter() { for inherent_method in self.tcx.associated_items(inherent_impl_did).in_definition_order() { @@ -2122,9 +2112,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Adt(adt_def, _) = rcvr_ty.kind() else { return; }; - // FIXME(oli-obk): try out bubbling this error up one level and cancelling the other error in that case. - let Ok(impls) = self.tcx.inherent_impls(adt_def.did()) else { return }; - let mut items = impls + let mut items = self + .tcx + .inherent_impls(adt_def.did()) .iter() .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers and only if @@ -2234,9 +2224,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity(); let target_ty = self .autoderef(sugg_span, rcvr_ty) + .silence_errors() .find(|(rcvr_ty, _)| { - DeepRejectCtxt::new(self.tcx, TreatParams::ForLookup) - .types_may_unify(*rcvr_ty, impl_ty) + DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify(*rcvr_ty, impl_ty) }) .map_or(impl_ty, |(ty, _)| ty) .peel_refs(); @@ -2350,17 +2340,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut Diag<'_>, ) -> bool { let tcx = self.tcx; - let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { - ty::Adt(def, args) if !def.is_enum() => { - let variant = &def.non_enum_variant(); - tcx.find_field_index(item_name, variant).map(|index| { - let field = &variant.fields[index]; - let field_ty = field.ty(tcx, args); - (field, field_ty) - }) - } - _ => None, - }); + let field_receiver = + self.autoderef(span, rcvr_ty).silence_errors().find_map(|(ty, _)| match ty.kind() { + ty::Adt(def, args) if !def.is_enum() => { + let variant = &def.non_enum_variant(); + tcx.find_field_index(item_name, variant).map(|index| { + let field = &variant.fields[index]; + let field_ty = field.ty(tcx, args); + (field, field_ty) + }) + } + _ => None, + }); if let Some((field, field_ty)) = field_receiver { let scope = tcx.parent_module_from_def_id(self.body_id); let is_accessible = field.vis.is_accessible_from(scope, tcx); @@ -2498,11 +2489,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .any(|info| self.associated_value(info.def_id, item_name).is_some()); let found_assoc = |ty: Ty<'tcx>| { - simplify_type(tcx, ty, TreatParams::AsCandidateKey) + simplify_type(tcx, ty, TreatParams::InstantiateWithInfer) .and_then(|simp| { tcx.incoherent_impls(simp) .into_iter() - .flatten() .find_map(|&id| self.associated_value(id, item_name)) }) .is_some() @@ -2673,9 +2663,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { if let SelfSource::MethodCall(expr) = source { let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); - for (fields, args) in - self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id) - { + for (fields, args) in self.get_field_candidates_considering_privacy_for_diag( + span, + actual, + mod_id, + expr.hir_id, + ) { let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)); let lang_items = self.tcx.lang_items(); @@ -2691,7 +2684,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut candidate_fields: Vec<_> = fields .into_iter() .filter_map(|candidate_field| { - self.check_for_nested_field_satisfying( + self.check_for_nested_field_satisfying_condition_for_diag( span, &|_, field_ty| { self.lookup_probe_for_diagnostic( @@ -3193,7 +3186,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let SelfSource::QPath(ty) = self_source else { return; }; - for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).skip(1) { + for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).silence_errors().skip(1) { if let Ok(pick) = self.probe_for_name( Mode::Path, item_name, @@ -3963,7 +3956,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // cases where a positive bound implies a negative impl. (candidates, Vec::new()) } else if let Some(simp_rcvr_ty) = - simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup) + simplify_type(self.tcx, rcvr_ty, TreatParams::AsRigid) { let mut potential_candidates = Vec::new(); let mut explicitly_negative = Vec::new(); @@ -3981,7 +3974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .any(|header| { let imp = header.trait_ref.instantiate_identity(); let imp_simp = - simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup); + simplify_type(self.tcx, imp.self_ty(), TreatParams::AsRigid); imp_simp.is_some_and(|s| s == simp_rcvr_ty) }) { @@ -4219,7 +4212,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return is_local(rcvr_ty); } - self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty)) + self.autoderef(span, rcvr_ty).silence_errors().any(|(ty, _)| is_local(ty)) } } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index c74270fc0e6a4..1574e9e98d4d8 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -2,7 +2,7 @@ use rustc_data_structures::packed::Pu128; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, Applicability, Diag}; +use rustc_errors::{Applicability, Diag, struct_span_code_err}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, @@ -11,17 +11,17 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::source_map::Spanned; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_span::source_map::Spanned; +use rustc_span::symbol::{Ident, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt}; use rustc_type_ir::TyKind::*; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; -use super::method::MethodCallee; use super::FnCtxt; +use super::method::MethodCallee; use crate::Expectation; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -896,17 +896,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let opname = Ident::with_dummy_span(opname); let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip(); let input_types = opt_rhs_ty.as_slice(); - let cause = self.cause( - span, - ObligationCauseCode::BinOp { - lhs_hir_id: lhs_expr.hir_id, - rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id), - rhs_span: opt_rhs_expr.map(|expr| expr.span), - rhs_is_lit: opt_rhs_expr - .is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_ty: expected.only_has_type(self), - }, - ); + let cause = self.cause(span, ObligationCauseCode::BinOp { + lhs_hir_id: lhs_expr.hir_id, + rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id), + rhs_span: opt_rhs_expr.map(|expr| expr.span), + rhs_is_lit: opt_rhs_expr.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Lit(_))), + output_ty: expected.only_has_type(self), + }); let method = self.lookup_method_in_trait( cause.clone(), diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 25f9340eeb717..49c5a7d8a652d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -5,13 +5,12 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, + Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, LangItem, Mutability, Pat, PatKind}; use rustc_infer::infer; -use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; @@ -19,8 +18,8 @@ use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::symbol::{Ident, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; @@ -29,7 +28,7 @@ use ty::VariantDef; use super::report_unexpected_variant_res; use crate::gather_locals::DeclOrigin; -use crate::{errors, FnCtxt, LoweredTy}; +use crate::{FnCtxt, LoweredTy, errors}; const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\ This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \ @@ -83,7 +82,7 @@ struct TopInfo<'tcx> { } #[derive(Copy, Clone)] -struct PatInfo<'tcx, 'a> { +struct PatInfo<'a, 'tcx> { binding_mode: ByRef, max_ref_mutbl: MutblCap, top_info: &'a TopInfo<'tcx>, @@ -222,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. #[instrument(level = "debug", skip(self, pat_info))] - fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) { + fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) { let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; let path_res = match &pat.kind { @@ -668,7 +667,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ident: Ident, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info; @@ -981,7 +980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { @@ -1184,7 +1183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let on_error = |e| { @@ -1441,7 +1440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -1479,7 +1478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx; @@ -2070,7 +2069,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = self @@ -2096,7 +2095,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; // Register a `DerefPure` bound, which is required by all `deref!()` pats. @@ -2137,7 +2136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &'tcx Pat<'tcx>, pat_mutbl: Mutability, mut expected: Ty<'tcx>, - mut pat_info: PatInfo<'tcx, '_>, + mut pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let features = tcx.features(); @@ -2345,7 +2344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice: Option<&'tcx Pat<'tcx>>, after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let expected = self.try_structurally_resolve_type(span, expected); @@ -2413,17 +2412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { len: ty::Const<'tcx>, min_len: u64, ) -> (Option>, Ty<'tcx>) { - let len = match len.eval(self.tcx, self.param_env, span) { - Ok((_, val)) => val - .try_to_scalar() - .and_then(|scalar| scalar.try_to_scalar_int().ok()) - .map(|int| int.to_target_usize(self.tcx)), - Err(ErrorHandled::Reported(..)) => { - let guar = self.error_scrutinee_unfixed_length(span); - return (Some(Ty::new_error(self.tcx, guar)), arr_ty); - } - Err(ErrorHandled::TooGeneric(..)) => None, - }; + let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx); let guar = if let Some(len) = len { // Now we know the length... @@ -2517,7 +2506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, expected_ty: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> ErrorGuaranteed { let PatInfo { top_info: ti, current_depth, .. } = pat_info; @@ -2533,6 +2522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.help("the semantics of slice patterns changed recently; see issue #62254"); } else if self .autoderef(span, expected_ty) + .silence_errors() .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) && let Some(span) = ti.span && let Some(_) = ti.origin_expr diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index e7f47ee56c9b2..8604f5f6920e7 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -7,8 +7,8 @@ use rustc_middle::ty::adjustment::{ PointerCoercion, }; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, sym}; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; @@ -30,13 +30,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; let method = self.register_infer_ok_obligations(ok); if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { - self.apply_adjustments( - oprnd_expr, - vec![Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), - target: method.sig.inputs()[0], - }], - ); + self.apply_adjustments(oprnd_expr, vec![Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), + target: method.sig.inputs()[0], + }]); } else { span_bug!(expr.span, "input to deref is not a ref?"); } diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs index d65aaef4e8b3f..98d7f777d6b8a 100644 --- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs +++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs @@ -1,5 +1,5 @@ -use hir::def_id::DefId; use hir::Node; +use hir::def_id::DefId; use rustc_hir as hir; use rustc_middle::bug; use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree}; diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 52fa30a352f84..18e40cfa42874 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -9,8 +9,8 @@ use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::span_bug; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::def_id::LocalDefIdMap; use rustc_span::Span; +use rustc_span::def_id::LocalDefIdMap; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ self, FulfillmentError, PredicateObligation, TraitEngine, TraitEngineExt as _, diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 986453397ffcc..c5843b883a17b 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -36,10 +36,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::{ExtendUnord, UnordSet}; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir as hir; +use rustc_hir::HirId; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::HirId; -use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind}; use rustc_middle::mir::FakeReadCause; use rustc_middle::traits::ObligationCauseCode; @@ -49,7 +48,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; -use rustc_span::{sym, BytePos, Pos, Span, Symbol}; +use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use rustc_target::abi::FIRST_VARIANT; use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; @@ -228,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // coroutine bodies can't borrow from their parent closure. To fix this, // we force the inner coroutine to also be `move`. This only matters for // coroutine-closures that are `move` since otherwise they themselves will - // be borrowing from the outer environment, so there's no self-borrows occuring. + // be borrowing from the outer environment, so there's no self-borrows occurring. if let UpvarArgs::Coroutine(..) = args && let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) = self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind") @@ -288,14 +287,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bug!(); }; let place = self.place_for_root_variable(closure_def_id, local_id); - delegate.capture_information.push(( - place, - ty::CaptureInfo { - capture_kind_expr_id: Some(init.hir_id), - path_expr_id: Some(init.hir_id), - capture_kind: UpvarCapture::ByValue, - }, - )); + delegate.capture_information.push((place, ty::CaptureInfo { + capture_kind_expr_id: Some(init.hir_id), + path_expr_id: Some(init.hir_id), + capture_kind: UpvarCapture::ByValue, + })); } } @@ -382,11 +378,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let UpvarArgs::CoroutineClosure(args) = args && !args.references_error() { - let closure_env_region: ty::Region<'_> = ty::Region::new_bound( - self.tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::BrEnv }, - ); + let closure_env_region: ty::Region<'_> = + ty::Region::new_bound(self.tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::ZERO, + kind: ty::BoundRegionKind::BrEnv, + }); let num_args = args .as_coroutine_closure() @@ -425,7 +421,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, upvar_ty, capture, - if needs_ref { Some(closure_env_region) } else { child_capture.region }, + if needs_ref { + closure_env_region + } else { + self.tcx.lifetimes.re_erased + }, ); }, ), @@ -587,7 +587,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability); - apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region) + apply_capture_kind_on_capture_ty( + self.tcx, + upvar_ty, + capture, + self.tcx.lifetimes.re_erased, + ) }) .collect() } @@ -775,13 +780,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(min_cap_list) = root_var_min_capture_list.get_mut(&var_hir_id) else { let mutability = self.determine_capture_mutability(&typeck_results, &place); - let min_cap_list = vec![ty::CapturedPlace { - var_ident, - place, - info: capture_info, - mutability, - region: None, - }]; + let min_cap_list = + vec![ty::CapturedPlace { var_ident, place, info: capture_info, mutability }]; root_var_min_capture_list.insert(var_hir_id, min_cap_list); continue; }; @@ -874,34 +874,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only need to insert when we don't have an ancestor in the existing min capture list if !ancestor_found { let mutability = self.determine_capture_mutability(&typeck_results, &place); - let captured_place = ty::CapturedPlace { - var_ident, - place, - info: updated_capture_info, - mutability, - region: None, - }; + let captured_place = + ty::CapturedPlace { var_ident, place, info: updated_capture_info, mutability }; min_cap_list.push(captured_place); } } - // For each capture that is determined to be captured by ref, add region info. - for (_, captures) in &mut root_var_min_capture_list { - for capture in captures { - match capture.info.capture_kind { - ty::UpvarCapture::ByRef(_) => { - let PlaceBase::Upvar(upvar_id) = capture.place.base else { - bug!("expected upvar") - }; - let origin = UpvarRegion(upvar_id, closure_span); - let upvar_region = self.next_region_var(origin); - capture.region = Some(upvar_region); - } - _ => (), - } - } - } - debug!( "For closure={:?}, min_captures before sorting={:?}", closure_def_id, root_var_min_capture_list @@ -1195,7 +1173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, ty, max_capture_info.capture_kind, - Some(self.tcx.lifetimes.re_erased), + self.tcx.lifetimes.re_erased, ) } }; @@ -1217,7 +1195,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, capture.place.ty(), capture.info.capture_kind, - Some(self.tcx.lifetimes.re_erased), + self.tcx.lifetimes.re_erased, ); // Checks if a capture implements any of the auto traits @@ -1935,13 +1913,11 @@ fn apply_capture_kind_on_capture_ty<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, capture_kind: UpvarCapture, - region: Option>, + region: ty::Region<'tcx>, ) -> Ty<'tcx> { match capture_kind { ty::UpvarCapture::ByValue => ty, - ty::UpvarCapture::ByRef(kind) => { - Ty::new_ref(tcx, region.unwrap(), ty, kind.to_mutbl_lossy()) - } + ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()), } } @@ -2025,14 +2001,11 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); - self.capture_information.push(( - place_with_id.place.clone(), - ty::CaptureInfo { - capture_kind_expr_id: Some(diag_expr_id), - path_expr_id: Some(diag_expr_id), - capture_kind: ty::UpvarCapture::ByValue, - }, - )); + self.capture_information.push((place_with_id.place.clone(), ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByValue, + })); } #[instrument(skip(self), level = "debug")] @@ -2059,14 +2032,11 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); } - self.capture_information.push(( - place, - ty::CaptureInfo { - capture_kind_expr_id: Some(diag_expr_id), - path_expr_id: Some(diag_expr_id), - capture_kind, - }, - )); + self.capture_information.push((place, ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind, + })); } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index c2555d2bb47dc..3254dddaee9a2 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -7,16 +7,16 @@ use std::mem; use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; +use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperFoldable}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::solve; use tracing::{debug, instrument}; @@ -803,7 +803,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { // We must deeply normalize in the new solver, since later lints // expect that types that show up in the typeck are fully // normalized. - let value = if self.should_normalize { + let mut value = if self.should_normalize { let body_id = tcx.hir().body_owner_def_id(self.body.id()); let cause = ObligationCause::misc(self.span.to_span(tcx), body_id); let at = self.fcx.at(&cause, self.fcx.param_env); @@ -818,12 +818,27 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { value }; + // Bail if there are any non-region infer. if value.has_non_region_infer() { let guar = self.report_error(value); - new_err(tcx, guar) - } else { - tcx.fold_regions(value, |_, _| tcx.lifetimes.re_erased) + value = new_err(tcx, guar); } + + // Erase the regions from the ty, since it's not really meaningful what + // these region values are; there's not a trivial correspondence between + // regions in the HIR and MIR, so when we turn the body into MIR, there's + // no reason to keep regions around. They will be repopulated during MIR + // borrowck, and specifically region constraints will be populated during + // MIR typeck which is run on the new body. + value = tcx.fold_regions(value, |_, _| tcx.lifetimes.re_erased); + + // Normalize consts in writeback, because GCE doesn't normalize eagerly. + if tcx.features().generic_const_exprs { + value = + value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env }); + } + + value } } @@ -858,3 +873,17 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { predicate } } + +struct EagerlyNormalizeConsts<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +} +impl<'tcx> TypeFolder> for EagerlyNormalizeConsts<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + self.tcx.try_normalize_erasing_regions(self.param_env, ct).unwrap_or(ct) + } +} diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 46f30526d2a83..a006786aa75b9 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -35,20 +35,20 @@ use std::env; use std::fs::{self, File}; -use std::io::{BufWriter, Write}; +use std::io::Write; use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_data_structures::graph::implementation::{Direction, INCOMING, NodeIndex, OUTGOING}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::dep_graph::{ - dep_kinds, DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, + DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, dep_kinds, }; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use tracing::debug; use {rustc_ast as ast, rustc_graphviz as dot, rustc_hir as hir}; @@ -245,7 +245,7 @@ fn dump_graph(query: &DepGraphQuery) { { // dump a .txt file with just the edges: let txt_path = format!("{path}.txt"); - let mut file = BufWriter::new(File::create(&txt_path).unwrap()); + let mut file = File::create_buffered(&txt_path).unwrap(); for (source, target) in &edges { write!(file, "{source:?} -> {target:?}\n").unwrap(); } diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index c79d108183c53..e8735cba9bd23 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -5,6 +5,7 @@ #![deny(missing_docs)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(file_buffered)] #![feature(rustdoc_internals)] #![warn(unreachable_pub)] // tidy-alphabetical-end @@ -14,9 +15,9 @@ mod errors; mod persist; pub use persist::{ - copy_cgu_workproduct_to_incr_comp_cache_dir, finalize_session_directory, in_incr_comp_dir, - in_incr_comp_dir_sess, load_query_result_cache, save_dep_graph, save_work_product_index, - setup_dep_graph, LoadResult, + LoadResult, copy_cgu_workproduct_to_incr_comp_cache_dir, finalize_session_directory, + in_incr_comp_dir, in_incr_comp_dir_sess, load_query_result_cache, save_dep_graph, + save_work_product_index, setup_dep_graph, }; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 88cb82f0f37a8..9dc5cbaafce19 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -23,12 +23,12 @@ use rustc_ast::{self as ast, Attribute, NestedMetaItem}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{intravisit, ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind}; -use rustc_middle::dep_graph::{label_strs, DepNode, DepNodeExt}; +use rustc_hir::{ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind, intravisit}; +use rustc_middle::dep_graph::{DepNode, DepNodeExt, label_strs}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use thin_vec::ThinVec; use tracing::debug; @@ -106,10 +106,11 @@ const LABELS_FN_IN_TRAIT: &[&[&str]] = const LABELS_HIR_ONLY: &[&[&str]] = &[BASE_HIR]; /// Impl `DepNode`s. -const LABELS_TRAIT: &[&[&str]] = &[ - BASE_HIR, - &[label_strs::associated_item_def_ids, label_strs::predicates_of, label_strs::generics_of], -]; +const LABELS_TRAIT: &[&[&str]] = &[BASE_HIR, &[ + label_strs::associated_item_def_ids, + label_strs::predicates_of, + label_strs::generics_of, +]]; /// Impl `DepNode`s. const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL]; @@ -417,12 +418,10 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol { if let Some(value) = item.value_str() { value + } else if let Some(ident) = item.ident() { + tcx.dcx().emit_fatal(errors::AssociatedValueExpectedFor { span: item.span(), ident }); } else { - if let Some(ident) = item.ident() { - tcx.dcx().emit_fatal(errors::AssociatedValueExpectedFor { span: item.span(), ident }); - } else { - tcx.dcx().emit_fatal(errors::AssociatedValueExpected { span: item.span() }); - } + tcx.dcx().emit_fatal(errors::AssociatedValueExpected { span: item.span() }); } } diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index f834c48cbf8fc..4c664ea6ba0f4 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -15,8 +15,8 @@ use std::path::{Path, PathBuf}; use std::{env, fs}; use rustc_data_structures::memmap::Mmap; -use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encoder; +use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::Session; use tracing::debug; diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index feb25a9a89d0d..8769c4173c886 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -108,14 +108,14 @@ use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use rand::{thread_rng, RngCore}; -use rustc_data_structures::base_n::{BaseNString, ToBaseN, CASE_INSENSITIVE}; +use rand::{RngCore, thread_rng}; +use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_data_structures::{base_n, flock}; use rustc_errors::ErrorGuaranteed; -use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy}; +use rustc_fs_util::{LinkOrCopy, link_or_copy, try_canonicalize}; use rustc_middle::bug; use rustc_session::config::CrateType; use rustc_session::output::{collect_crate_types, find_crate_name}; diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 18088a10dd00f..c74804cc7983d 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -7,10 +7,10 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::unord::UnordMap; use rustc_middle::dep_graph::{DepGraph, DepsType, SerializedDepGraph, WorkProductMap}; use rustc_middle::query::on_disk_cache::OnDiskCache; -use rustc_serialize::opaque::MemDecoder; use rustc_serialize::Decodable; -use rustc_session::config::IncrementalStateAssertion; +use rustc_serialize::opaque::MemDecoder; use rustc_session::Session; +use rustc_session::config::IncrementalStateAssertion; use rustc_span::ErrorGuaranteed; use tracing::{debug, warn}; diff --git a/compiler/rustc_incremental/src/persist/mod.rs b/compiler/rustc_incremental/src/persist/mod.rs index a529b1dcec082..186db0a60a38f 100644 --- a/compiler/rustc_incremental/src/persist/mod.rs +++ b/compiler/rustc_incremental/src/persist/mod.rs @@ -11,6 +11,6 @@ mod save; mod work_product; pub use fs::{finalize_session_directory, in_incr_comp_dir, in_incr_comp_dir_sess}; -pub use load::{load_query_result_cache, setup_dep_graph, LoadResult}; +pub use load::{LoadResult, load_query_result_cache, setup_dep_graph}; pub use save::{save_dep_graph, save_work_product_index}; pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir; diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 58a03cb8b30cd..53726df459797 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -7,8 +7,8 @@ use rustc_middle::dep_graph::{ DepGraph, SerializedDepGraph, WorkProduct, WorkProductId, WorkProductMap, }; use rustc_middle::ty::TyCtxt; -use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encodable as RustcEncodable; +use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::Session; use tracing::debug; diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index 92ea3f278dc43..f7d18f84e3452 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -20,4 +20,5 @@ nightly = [ "dep:rustc_macros", "rustc_index_macros/nightly", ] +rustc_randomized_layouts = [] # tidy-alphabetical-end diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 506afbae40c6e..c2b9cae680bf1 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -3,11 +3,11 @@ use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds use std::rc::Rc; use std::{fmt, iter, mem, slice}; +use Chunk::*; use arrayvec::ArrayVec; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_Generic, Encodable_Generic}; -use smallvec::{smallvec, SmallVec}; -use Chunk::*; +use smallvec::{SmallVec, smallvec}; use crate::{Idx, IndexVec}; diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index 066aa46e35080..21e681d63f69b 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -182,10 +182,11 @@ fn chunked_bitset() { //----------------------------------------------------------------------- let mut b1 = ChunkedBitSet::::new_empty(1); - assert_eq!( - b1, - ChunkedBitSet { domain_size: 1, chunks: Box::new([Zeros(1)]), marker: PhantomData } - ); + assert_eq!(b1, ChunkedBitSet { + domain_size: 1, + chunks: Box::new([Zeros(1)]), + marker: PhantomData + }); b1.assert_valid(); assert!(!b1.contains(0)); @@ -204,10 +205,11 @@ fn chunked_bitset() { //----------------------------------------------------------------------- let mut b100 = ChunkedBitSet::::new_filled(100); - assert_eq!( - b100, - ChunkedBitSet { domain_size: 100, chunks: Box::new([Ones(100)]), marker: PhantomData } - ); + assert_eq!(b100, ChunkedBitSet { + domain_size: 100, + chunks: Box::new([Ones(100)]), + marker: PhantomData + }); b100.assert_valid(); for i in 0..100 { @@ -222,20 +224,17 @@ fn chunked_bitset() { ); assert_eq!(b100.count(), 97); assert!(!b100.contains(20) && b100.contains(30) && !b100.contains(99) && b100.contains(50)); - assert_eq!( - b100.chunks(), - vec![Mixed( - 100, - 97, - #[rustfmt::skip] + assert_eq!(b100.chunks(), vec![Mixed( + 100, + 97, + #[rustfmt::skip] Rc::new([ 0b11111111_11111111_11111110_11111111_11111111_11101111_11111111_11111111, 0b00000000_00000000_00000000_00000111_11111111_11111111_11111111_11111111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]) - )], - ); + )],); b100.assert_valid(); let mut num_removed = 0; for i in 0..100 { @@ -250,14 +249,11 @@ fn chunked_bitset() { //----------------------------------------------------------------------- let mut b2548 = ChunkedBitSet::::new_empty(2548); - assert_eq!( - b2548, - ChunkedBitSet { - domain_size: 2548, - chunks: Box::new([Zeros(2048), Zeros(500)]), - marker: PhantomData, - } - ); + assert_eq!(b2548, ChunkedBitSet { + domain_size: 2548, + chunks: Box::new([Zeros(2048), Zeros(500)]), + marker: PhantomData, + }); b2548.assert_valid(); b2548.insert(14); @@ -274,14 +270,11 @@ fn chunked_bitset() { //----------------------------------------------------------------------- let mut b4096 = ChunkedBitSet::::new_empty(4096); - assert_eq!( - b4096, - ChunkedBitSet { - domain_size: 4096, - chunks: Box::new([Zeros(2048), Zeros(2048)]), - marker: PhantomData, - } - ); + assert_eq!(b4096, ChunkedBitSet { + domain_size: 4096, + chunks: Box::new([Zeros(2048), Zeros(2048)]), + marker: PhantomData, + }); b4096.assert_valid(); for i in 0..4096 { @@ -311,14 +304,11 @@ fn chunked_bitset() { //----------------------------------------------------------------------- let mut b10000 = ChunkedBitSet::::new_empty(10000); - assert_eq!( - b10000, - ChunkedBitSet { - domain_size: 10000, - chunks: Box::new([Zeros(2048), Zeros(2048), Zeros(2048), Zeros(2048), Zeros(1808),]), - marker: PhantomData, - } - ); + assert_eq!(b10000, ChunkedBitSet { + domain_size: 10000, + chunks: Box::new([Zeros(2048), Zeros(2048), Zeros(2048), Zeros(2048), Zeros(1808),]), + marker: PhantomData, + }); b10000.assert_valid(); assert!(b10000.insert(3000) && b10000.insert(5000)); diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index be028feca605f..34f541a8cc639 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -17,8 +17,8 @@ mod tests; /// first value of the following element. #[derive(Debug, Clone)] pub struct IntervalSet { - // Start, end - map: SmallVec<[(u32, u32); 4]>, + // Start, end (both inclusive) + map: SmallVec<[(u32, u32); 2]>, domain: usize, _data: PhantomData, } diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index f773b5b46adae..52f354b8ecaff 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -33,8 +33,19 @@ pub use vec::IndexVec; /// /// #[macro_export] +#[cfg(not(feature = "rustc_randomized_layouts"))] macro_rules! static_assert_size { ($ty:ty, $size:expr) => { const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()]; }; } + +#[macro_export] +#[cfg(feature = "rustc_randomized_layouts")] +macro_rules! static_assert_size { + ($ty:ty, $size:expr) => { + // no effect other than using the statements. + // struct sizes are not deterministic under randomized layouts + const _: (usize, usize) = ($size, ::std::mem::size_of::<$ty>()); + }; +} diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs index 3205ca3f40be2..956d32c9a6943 100644 --- a/compiler/rustc_index/src/slice.rs +++ b/compiler/rustc_index/src/slice.rs @@ -20,7 +20,7 @@ pub struct IndexSlice { impl IndexSlice { #[inline] - pub const fn empty() -> &'static Self { + pub const fn empty<'a>() -> &'a Self { Self::from_raw(&[]) } diff --git a/compiler/rustc_index/src/vec/tests.rs b/compiler/rustc_index/src/vec/tests.rs index 381d79c24fcba..9cee2f2f5b23b 100644 --- a/compiler/rustc_index/src/vec/tests.rs +++ b/compiler/rustc_index/src/vec/tests.rs @@ -29,19 +29,21 @@ fn index_size_is_optimized() { #[test] fn range_iterator_iterates_forwards() { let range = MyIdx::from_u32(1)..MyIdx::from_u32(4); - assert_eq!( - range.collect::>(), - [MyIdx::from_u32(1), MyIdx::from_u32(2), MyIdx::from_u32(3)] - ); + assert_eq!(range.collect::>(), [ + MyIdx::from_u32(1), + MyIdx::from_u32(2), + MyIdx::from_u32(3) + ]); } #[test] fn range_iterator_iterates_backwards() { let range = MyIdx::from_u32(1)..MyIdx::from_u32(4); - assert_eq!( - range.rev().collect::>(), - [MyIdx::from_u32(3), MyIdx::from_u32(2), MyIdx::from_u32(1)] - ); + assert_eq!(range.rev().collect::>(), [ + MyIdx::from_u32(3), + MyIdx::from_u32(2), + MyIdx::from_u32(1) + ]); } #[test] diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 9d77afa5d2f03..35ea42338250d 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -15,10 +15,10 @@ use rustc_middle::ty::{ use smallvec::SmallVec; use tracing::debug; +use crate::infer::InferCtxt; use crate::infer::canonical::{ Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues, }; -use crate::infer::InferCtxt; impl<'tcx> InferCtxt<'tcx> { /// Canonicalizes a query value `V`. When we canonicalize a query, @@ -51,7 +51,7 @@ impl<'tcx> InferCtxt<'tcx> { query_state, |tcx, param_env, query_state| { // FIXME(#118965): We don't canonicalize the static lifetimes that appear in the - // `param_env` beacause they are treated differently by trait selection. + // `param_env` because they are treated differently by trait selection. Canonicalizer::canonicalize( param_env, None, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 95d7bb7eb3830..7791bd736281c 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument}; -use crate::infer::canonical::instantiate::{instantiate_value, CanonicalExt}; +use crate::infer::canonical::instantiate::{CanonicalExt, instantiate_value}; use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 95888beb6b198..c06836edcfb55 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,12 +1,12 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode}; use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; -use rustc_type_ir::relate::Relate; use rustc_type_ir::InferCtxtLike; +use rustc_type_ir::relate::Relate; use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin}; diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index aab64883bc50f..6af49accc8411 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -4,7 +4,7 @@ use std::fmt; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{ - Direction, Graph, NodeIndex, INCOMING, OUTGOING, + Direction, Graph, INCOMING, NodeIndex, OUTGOING, }; use rustc_data_structures::intern::Interned; use rustc_data_structures::unord::UnordSet; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 234dc5133f8db..5fa1bf51634a3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,6 +1,9 @@ use std::cell::{Cell, RefCell}; use std::fmt; +pub use BoundRegionConversionTime::*; +pub use RegionVariableOrigin::*; +pub use SubregionOrigin::*; pub use at::DefineOpaqueTypes; use free_regions::RegionRelations; pub use freshen::TypeFreshener; @@ -10,8 +13,8 @@ use opaque_types::OpaqueTypeStorage; use region_constraints::{ GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound, }; -pub use relate::combine::{CombineFields, PredicateEmittingRelation}; pub use relate::StructurallyRelateAliases; +pub use relate::combine::{CombineFields, PredicateEmittingRelation}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; @@ -26,29 +29,26 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ ConstVariableOrigin, ConstVariableValue, ConstVidKey, EffectVarValue, EffectVidKey, }; -use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; +use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::traits::select; use rustc_middle::traits::solve::{Goal, NoSolution}; +pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{ BoundVarReplacerDelegate, TypeFoldable, TypeFolder, TypeSuperFoldable, }; use rustc_middle::ty::visit::TypeVisitableExt; -pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{ self, ConstVid, EffectVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, }; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; -pub use BoundRegionConversionTime::*; -pub use RegionVariableOrigin::*; -pub use SubregionOrigin::*; use crate::infer::relate::RelateResult; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; @@ -458,8 +458,8 @@ pub enum RegionVariableOrigin { PatternRegion(Span), /// Regions created by `&` operator. - /// - AddrOfRegion(Span), + BorrowRegion(Span), + /// Regions created as part of an autoref of a method receiver. Autoref(Span), @@ -1481,7 +1481,7 @@ impl<'tcx> InferCtxt<'tcx> { // This hoists the borrow/release out of the loop body. let inner = self.inner.try_borrow(); - return move |infer_var: TyOrConstInferVar| match (infer_var, &inner) { + move |infer_var: TyOrConstInferVar| match (infer_var, &inner) { (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => { use self::type_variable::TypeVariableValue; @@ -1491,7 +1491,7 @@ impl<'tcx> InferCtxt<'tcx> { ) } _ => false, - }; + } } /// `ty_or_const_infer_var_changed` is equivalent to one of these two: @@ -1741,7 +1741,7 @@ impl RegionVariableOrigin { match *self { MiscVariable(a) | PatternRegion(a) - | AddrOfRegion(a) + | BorrowRegion(a) | Autoref(a) | Coercion(a) | RegionParameterDefinition(a, ..) @@ -1776,16 +1776,13 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( self.idx += 1; idx }; - Ty::new_placeholder( - self.tcx, - ty::PlaceholderType { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundTy { - var: ty::BoundVar::from_u32(idx), - kind: ty::BoundTyKind::Anon, - }, + Ty::new_placeholder(self.tcx, ty::PlaceholderType { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundTy { + var: ty::BoundVar::from_u32(idx), + kind: ty::BoundTyKind::Anon, }, - ) + }) } else { t.super_fold_with(self) } @@ -1793,17 +1790,14 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { if let ty::ConstKind::Infer(_) = c.kind() { - ty::Const::new_placeholder( - self.tcx, - ty::PlaceholderConst { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundVar::from_u32({ - let idx = self.idx; - self.idx += 1; - idx - }), - }, - ) + ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundVar::from_u32({ + let idx = self.idx; + self.idx += 1; + idx + }), + }) } else { c.super_fold_with(self) } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 88db7237647cd..55c51bc856f8e 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -2,8 +2,8 @@ use hir::def_id::{DefId, LocalDefId}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; -use rustc_middle::traits::solve::Goal; use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{ @@ -213,7 +213,7 @@ impl<'tcx> InferCtxt<'tcx> { /// ``` /// /// As indicating in the comments above, each of those references - /// is (in the compiler) basically generic paramters (`args`) + /// is (in the compiler) basically generic parameters (`args`) /// applied to the type of a suitable `def_id` (which identifies /// `Foo1` or `Foo2`). /// diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 77c711e57bb62..a071b84a1a00f 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -5,8 +5,8 @@ use rustc_middle::ty::{self, Region}; use tracing::{debug, instrument}; use super::explicit_outlives_bounds; -use crate::infer::free_regions::FreeRegionMap; use crate::infer::GenericKind; +use crate::infer::free_regions::FreeRegionMap; use crate::traits::query::OutlivesBound; /// The `OutlivesEnvironment` collects information about what outlives diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 0c397350067c3..634cda86bc338 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -68,7 +68,7 @@ use rustc_middle::ty::{ TypeFoldable as _, TypeVisitableExt, }; use rustc_span::DUMMY_SP; -use rustc_type_ir::outlives::{push_outlives_components, Component}; +use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::smallvec; use tracing::{debug, instrument}; @@ -101,19 +101,15 @@ impl<'tcx> InferCtxt<'tcx> { ) { debug!(?sup_type, ?sub_region, ?cause); let origin = SubregionOrigin::from_obligation_cause(cause, || { - infer::RelateParamBound( - cause.span, - sup_type, - match cause.code().peel_derives() { - ObligationCauseCode::WhereClause(_, span) - | ObligationCauseCode::WhereClauseInExpr(_, span, ..) - if !span.is_dummy() => - { - Some(*span) - } - _ => None, - }, - ) + infer::RelateParamBound(cause.span, sup_type, match cause.code().peel_derives() { + ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) + if !span.is_dummy() => + { + Some(*span) + } + _ => None, + }) }); self.register_region_obligation(RegionObligation { sup_type, sub_region, origin }); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 711f20444defc..74a80a1b9aa7c 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,7 +1,7 @@ use std::assert_matches::assert_matches; use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; -use rustc_type_ir::outlives::{compute_alias_components_recursive, Component}; +use rustc_type_ir::outlives::{Component, compute_alias_components_recursive}; use smallvec::smallvec; use tracing::{debug, instrument, trace}; diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 70b59322f5bee..e75d7b7db1453 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -30,7 +30,7 @@ use super::glb::Glb; use super::lub::Lub; use super::type_relating::TypeRelating; use super::{RelateResult, StructurallyRelateAliases}; -use crate::infer::{relate, DefineOpaqueTypes, InferCtxt, TypeTrace}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate}; use crate::traits::{Obligation, PredicateObligation}; #[derive(Clone)] @@ -153,7 +153,7 @@ impl<'tcx> InferCtxt<'tcx> { // During coherence, opaque types should be treated as *possibly* // equal to any other type (except for possibly itself). This is an - // extremely heavy hammer, but can be relaxed in a fowards-compatible + // extremely heavy hammer, but can be relaxed in a forwards-compatible // way later. (&ty::Alias(ty::Opaque, _), _) | (_, &ty::Alias(ty::Opaque, _)) if self.intercrate => { relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index f257141ea6581..a6d10aa5968c7 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -17,7 +17,7 @@ use super::{ PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, }; use crate::infer::type_variable::TypeVariableValue; -use crate::infer::{relate, InferCtxt, RegionVariableOrigin}; +use crate::infer::{InferCtxt, RegionVariableOrigin, relate}; impl<'tcx> InferCtxt<'tcx> { /// The idea is that we should ensure that the type variable `target_vid` @@ -120,7 +120,7 @@ impl<'tcx> InferCtxt<'tcx> { } else { // NOTE: The `instantiation_variance` is not the same variance as // used by the relation. When instantiating `b`, `target_is_expected` - // is flipped and the `instantion_variance` is also flipped. To + // is flipped and the `instantiation_variance` is also flipped. To // constrain the `generalized_ty` while using the original relation, // we therefore only have to flip the arguments. // @@ -259,11 +259,11 @@ impl<'tcx> InferCtxt<'tcx> { structurally_relate_aliases, root_vid, for_universe, - ambient_variance, root_term: source_term.into(), + ambient_variance, in_alias: false, - has_unconstrained_ty_var: false, cache: Default::default(), + has_unconstrained_ty_var: false, }; let value_may_be_infer = generalizer.relate(source_term, source_term)?; @@ -304,14 +304,12 @@ struct Generalizer<'me, 'tcx> { /// we reject the relation. for_universe: ty::UniverseIndex, - /// After we generalize this type, we are going to relate it to - /// some other type. What will be the variance at this point? - ambient_variance: ty::Variance, - /// The root term (const or type) we're generalizing. Used for cycle errors. root_term: Term<'tcx>, - cache: SsoHashMap, Ty<'tcx>>, + /// After we generalize this type, we are going to relate it to + /// some other type. What will be the variance at this point? + ambient_variance: ty::Variance, /// This is set once we're generalizing the arguments of an alias. /// @@ -320,6 +318,8 @@ struct Generalizer<'me, 'tcx> { /// hold by either normalizing the outer or the inner associated type. in_alias: bool, + cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>, + /// See the field `has_unconstrained_ty_var` in `Generalization`. has_unconstrained_ty_var: bool, } @@ -451,7 +451,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be == - if let Some(&result) = self.cache.get(&t) { + if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) { return Ok(result); } @@ -557,7 +557,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { _ => relate::structurally_relate_tys(self, t, t), }?; - self.cache.insert(t, g); + self.cache.insert((t, self.ambient_variance, self.in_alias), g); Ok(g) } diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index 7b12003643eb1..ed108f42969db 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -6,9 +6,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; use tracing::{debug, instrument}; +use super::StructurallyRelateAliases; use super::combine::{CombineFields, PredicateEmittingRelation}; use super::lattice::{self, LatticeDir}; -use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::ObligationCause; diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index ab6a19265f3fc..7908733e7348e 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -6,8 +6,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use tracing::{debug, instrument}; use super::RelateResult; -use crate::infer::snapshot::CombinedSnapshot; use crate::infer::InferCtxt; +use crate::infer::snapshot::CombinedSnapshot; impl<'tcx> InferCtxt<'tcx> { /// Replaces all bound variables (lifetimes, types, and constants) bound by @@ -34,22 +34,22 @@ impl<'tcx> InferCtxt<'tcx> { let delegate = FnMutDelegate { regions: &mut |br: ty::BoundRegion| { - ty::Region::new_placeholder( - self.tcx, - ty::PlaceholderRegion { universe: next_universe, bound: br }, - ) + ty::Region::new_placeholder(self.tcx, ty::PlaceholderRegion { + universe: next_universe, + bound: br, + }) }, types: &mut |bound_ty: ty::BoundTy| { - Ty::new_placeholder( - self.tcx, - ty::PlaceholderType { universe: next_universe, bound: bound_ty }, - ) + Ty::new_placeholder(self.tcx, ty::PlaceholderType { + universe: next_universe, + bound: bound_ty, + }) }, consts: &mut |bound_var: ty::BoundVar| { - ty::Const::new_placeholder( - self.tcx, - ty::PlaceholderConst { universe: next_universe, bound: bound_var }, - ) + ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst { + universe: next_universe, + bound: bound_var, + }) }, }; diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index bf4d68b942863..35c7ab5000d70 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -6,9 +6,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; use tracing::{debug, instrument}; +use super::StructurallyRelateAliases; use super::combine::{CombineFields, PredicateEmittingRelation}; use super::lattice::{self, LatticeDir}; -use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::ObligationCause; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index be16fca45216a..a402a8009ff8d 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -1,14 +1,14 @@ use rustc_middle::traits::solve::Goal; use rustc_middle::ty::relate::{ - relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation, + Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances, }; use rustc_middle::ty::{self, Ty, TyCtxt, TyVar}; use rustc_span::Span; use tracing::{debug, instrument}; use super::combine::CombineFields; -use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; use crate::infer::BoundRegionConversionTime::HigherRankedType; +use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; /// Enforce that `a` is equal to or a subtype of `b`. diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs index 20db6583a2ba1..964fb1f681955 100644 --- a/compiler/rustc_infer/src/infer/snapshot/mod.rs +++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs @@ -2,8 +2,8 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::ty; use tracing::{debug, instrument}; -use super::region_constraints::RegionSnapshot; use super::InferCtxt; +use super::region_constraints::RegionSnapshot; mod fudge; pub(crate) mod undo_log; diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 9aa02f89d2a76..79ea0915c9c05 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -6,7 +6,7 @@ use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey}; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey}; use tracing::debug; -use crate::infer::{region_constraints, type_variable, InferCtxtInner}; +use crate::infer::{InferCtxtInner, region_constraints, type_variable}; use crate::traits; pub struct Snapshot<'tcx> { diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index fd38040406d47..a076cdad672ab 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -45,15 +45,12 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { cause: ObligationCause<'tcx>, ) { let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]); - self.register_predicate_obligation( - infcx, - Obligation { - cause, - recursion_depth: 0, - param_env, - predicate: trait_ref.upcast(infcx.tcx), - }, - ); + self.register_predicate_obligation(infcx, Obligation { + cause, + recursion_depth: 0, + param_env, + predicate: trait_ref.upcast(infcx.tcx), + }); } fn register_predicate_obligation( diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 3a05b576a9744..34b0fe3e96788 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -18,14 +18,14 @@ pub use rustc_middle::traits::*; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::Span; +pub use self::ImplSource::*; +pub use self::SelectionError::*; pub use self::engine::{FromSolverError, ScrubbedTraitError, TraitEngine}; pub(crate) use self::project::UndoLog; pub use self::project::{ MismatchedProjectionTypes, Normalized, NormalizedTerm, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheStorage, }; -pub use self::ImplSource::*; -pub use self::SelectionError::*; use crate::infer::InferCtxt; /// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index f6b05340952a9..fa813d0f90ca0 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -200,10 +200,10 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { if result.must_apply_considering_regions() { ty.obligations = vec![]; } - map.insert( - key, - ProjectionCacheEntry::NormalizedTerm { ty, complete: Some(result) }, - ); + map.insert(key, ProjectionCacheEntry::NormalizedTerm { + ty, + complete: Some(result), + }); } ref value => { // Type inference could "strand behind" old cache entries. Leave diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 3e4f9b4816660..a977bd15d3bb9 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::{self, ToPolyTraitRef, TyCtxt}; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; pub use rustc_type_ir::elaborate::*; use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 04e2b7d45dc93..c2241773c8ccb 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use std::result; use std::sync::Arc; -use rustc_ast::{token, LitKind, MetaItemKind}; +use rustc_ast::{LitKind, MetaItemKind, token}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::StableHasher; @@ -21,10 +21,10 @@ use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; use rustc_session::filesearch::{self, sysroot_candidates}; use rustc_session::parse::ParseSess; -use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session}; +use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint}; +use rustc_span::FileName; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs}; use rustc_span::symbol::sym; -use rustc_span::FileName; use tracing::trace; use crate::util; @@ -311,7 +311,9 @@ pub struct Config { pub output_file: Option, pub ice_file: Option, pub file_loader: Option>, - pub locale_resources: &'static [&'static str], + /// The list of fluent resources, used for lints declared with + /// [`Diagnostic`](rustc_errors::Diagnostic) and [`LintDiagnostic`](rustc_errors::LintDiagnostic). + pub locale_resources: Vec<&'static str>, pub lint_caps: FxHashMap, diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 3b6c2acaf3083..b81a740270163 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,5 +1,6 @@ // tidy-alphabetical-start #![feature(decl_macro)] +#![feature(file_buffered)] #![feature(let_chains)] #![feature(try_blocks)] #![warn(unreachable_pub)] @@ -14,7 +15,7 @@ mod queries; pub mod util; pub use callbacks::setup_callbacks; -pub use interface::{run_compiler, Config}; +pub use interface::{Config, run_compiler}; pub use passes::DEFAULT_QUERY_PROVIDERS; pub use queries::{Linker, Queries}; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 779b98d073dab..bba517915a2df 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -13,10 +13,10 @@ use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; -use rustc_hir::def_id::{StableCrateId, StableCrateIdMap, LOCAL_CRATE}; +use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; -use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore}; +use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store}; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; @@ -32,8 +32,8 @@ use rustc_session::cstore::Untracked; use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name}; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::FileName; +use rustc_span::symbol::{Symbol, sym}; use rustc_target::spec::PanicStrategy; use rustc_trait_selection::traits; use tracing::{info, instrument}; @@ -435,7 +435,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P escape_dep_filename(&file.prefer_local().to_string()) }; - // The entries will be used to declare dependencies beween files in a + // The entries will be used to declare dependencies between files in a // Makefile-like output, so the iteration order does not matter. #[allow(rustc::potential_query_instability)] let extra_tracked_files = @@ -519,7 +519,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P write_deps_to_file(&mut file)?; } OutFileName::Real(ref path) => { - let mut file = BufWriter::new(fs::File::create(path)?); + let mut file = fs::File::create_buffered(path)?; write_deps_to_file(&mut file)?; } } @@ -788,7 +788,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { rustc_hir_analysis::check_crate(tcx); sess.time("MIR_coroutine_by_move_body", || { tcx.hir().par_body_owners(|def_id| { - if tcx.needs_coroutine_by_move_body_def_id(def_id) { + if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) { tcx.ensure_with_value().coroutine_by_move_body_def_id(def_id); } }); @@ -980,19 +980,15 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { std::ops::ControlFlow::Continue::(()) }); - sess.code_stats.record_vtable_size( - tr, - &name, - VTableSizeInfo { - trait_name: name.clone(), - entries: entries_ignoring_upcasting + entries_for_upcasting, - entries_ignoring_upcasting, - entries_for_upcasting, - upcasting_cost_percent: entries_for_upcasting as f64 - / entries_ignoring_upcasting as f64 - * 100., - }, - ) + sess.code_stats.record_vtable_size(tr, &name, VTableSizeInfo { + trait_name: name.clone(), + entries: entries_ignoring_upcasting + entries_for_upcasting, + entries_ignoring_upcasting, + entries_for_upcasting, + upcasting_cost_percent: entries_for_upcasting as f64 + / entries_ignoring_upcasting as f64 + * 100., + }) } } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 44e07b36b616b..3a1833452d4b6 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -3,8 +3,8 @@ use std::cell::{RefCell, RefMut}; use std::sync::Arc; use rustc_ast as ast; -use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; +use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{OnceLock, WorkerLocal}; @@ -13,8 +13,8 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::{GlobalCtxt, TyCtxt}; use rustc_serialize::opaque::FileEncodeResult; -use rustc_session::config::{self, OutputFilenames, OutputType}; use rustc_session::Session; +use rustc_session::config::{self, OutputFilenames, OutputType}; use crate::errors::FailedWritingFile; use crate::interface::{Compiler, Result}; diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 42fed98df0101..57aa3deae806b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -6,22 +6,22 @@ use std::sync::Arc; use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::emitter::HumanReadableErrorType; -use rustc_errors::{registry, ColorConfig}; +use rustc_errors::{ColorConfig, registry}; use rustc_session::config::{ - build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, - CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, DebugInfo, DumpMonoStatsFormat, - ErrorOutputType, ExternEntry, ExternLocation, Externs, FmtDebug, FunctionReturn, - InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, - LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, OomStrategy, - Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, + BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, + DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, + FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, + LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, + OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, - SymbolManglingVersion, WasiExecModel, + SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options, + rustc_optgroups, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; -use rustc_session::{build_session, filesearch, getopts, CompilerIO, EarlyDiagCtxt, Session}; -use rustc_span::edition::{Edition, DEFAULT_EDITION}; +use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, build_session, filesearch, getopts}; +use rustc_span::edition::{DEFAULT_EDITION, Edition}; use rustc_span::source_map::{RealFileLoader, SourceMapInputs}; use rustc_span::symbol::sym; use rustc_span::{FileName, SourceFileHashAlgorithm}; @@ -847,6 +847,7 @@ fn test_unstable_options_tracking_hash() { tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc"))); + tracked!(small_data_threshold, Some(16)); tracked!(split_lto_unit, Some(true)); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); tracked!(stack_protector, StackProtector::All); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 761d288a7c2eb..71e8accf5a328 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,21 +1,21 @@ use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; +use std::sync::atomic::{AtomicBool, Ordering}; use std::{env, iter, thread}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; #[cfg(parallel_compiler)] use rustc_data_structures::sync; -use rustc_metadata::{load_symbol_from_dylib, DylibError}; +use rustc_metadata::{DylibError, load_symbol_from_dylib}; use rustc_middle::ty::CurrentGcx; use rustc_parse::validate_attr; -use rustc_session::config::{host_triple, Cfg, OutFileName, OutputFilenames, OutputTypes}; +use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, host_triple}; use rustc_session::filesearch::sysroot_candidates; use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer}; -use rustc_session::output::{categorize_crate_type, CRATE_TYPES}; -use rustc_session::{filesearch, EarlyDiagCtxt, Session}; +use rustc_session::output::{CRATE_TYPES, categorize_crate_type}; +use rustc_session::{EarlyDiagCtxt, Session, filesearch}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMapInputs; @@ -143,7 +143,7 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, use rustc_data_structures::{defer, jobserver}; use rustc_middle::ty::tls; use rustc_query_impl::QueryCtxt; - use rustc_query_system::query::{break_query_cycles, QueryContext}; + use rustc_query_system::query::{QueryContext, break_query_cycles}; let thread_stack_size = init_stack_size(thread_builder_diag); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 31fdd2d7cec70..60aab668cbaa6 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -91,6 +91,15 @@ pub enum TokenKind { /// tokens. UnknownPrefix, + /// An unknown prefix in a lifetime, like `'foo#`. + /// + /// Note that like above, only the `'` and prefix are included in the token + /// and not the separator. + UnknownPrefixLifetime, + + /// `'r#lt`, which in edition < 2021 is split into several tokens: `'r # lt`. + RawLifetime, + /// Similar to the above, but *always* an error on every edition. This is used /// for emoji identifier recovery, as those are not meant to be ever accepted. InvalidPrefix, @@ -677,9 +686,17 @@ impl Cursor<'_> { return Literal { kind, suffix_start }; } + if self.first() == 'r' && self.second() == '#' && is_id_start(self.third()) { + // Eat "r" and `#`, and identifier start characters. + self.bump(); + self.bump(); + self.bump(); + self.eat_while(is_id_continue); + return RawLifetime; + } + // Either a lifetime or a character literal with // length greater than 1. - let starts_with_number = self.first().is_ascii_digit(); // Skip the literal contents. @@ -688,15 +705,17 @@ impl Cursor<'_> { self.bump(); self.eat_while(is_id_continue); - // Check if after skipping literal contents we've met a closing - // single quote (which means that user attempted to create a - // string with single quotes). - if self.first() == '\'' { - self.bump(); - let kind = Char { terminated: true }; - Literal { kind, suffix_start: self.pos_within_token() } - } else { - Lifetime { starts_with_number } + match self.first() { + // Check if after skipping literal contents we've met a closing + // single quote (which means that user attempted to create a + // string with single quotes). + '\'' => { + self.bump(); + let kind = Char { terminated: true }; + Literal { kind, suffix_start: self.pos_within_token() } + } + '#' if !starts_with_number => UnknownPrefixLifetime, + _ => Lifetime { starts_with_number }, } } diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 493ec2b0f6045..556bbf1f5182e 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -1,4 +1,4 @@ -use expect_test::{expect, Expect}; +use expect_test::{Expect, expect}; use super::*; @@ -141,9 +141,7 @@ fn check_lexing(src: &str, expect: Expect) { #[test] fn smoke_test() { - check_lexing( - "/* my source file */ fn main() { println!(\"zebra\"); }\n", - expect![[r#" + check_lexing("/* my source file */ fn main() { println!(\"zebra\"); }\n", expect![[r#" Token { kind: BlockComment { doc_style: None, terminated: true }, len: 20 } Token { kind: Whitespace, len: 1 } Token { kind: Ident, len: 2 } @@ -163,8 +161,7 @@ fn smoke_test() { Token { kind: Whitespace, len: 1 } Token { kind: CloseBrace, len: 1 } Token { kind: Whitespace, len: 1 } - "#]], - ) + "#]]) } #[test] @@ -207,47 +204,35 @@ fn comment_flavors() { #[test] fn nested_block_comments() { - check_lexing( - "/* /* */ */'a'", - expect![[r#" + check_lexing("/* /* */ */'a'", expect![[r#" Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } - "#]], - ) + "#]]) } #[test] fn characters() { - check_lexing( - "'a' ' ' '\\n'", - expect![[r#" + check_lexing("'a' ' ' '\\n'", expect![[r#" Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } Token { kind: Whitespace, len: 1 } Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } Token { kind: Whitespace, len: 1 } Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 4 }, len: 4 } - "#]], - ); + "#]]); } #[test] fn lifetime() { - check_lexing( - "'abc", - expect![[r#" + check_lexing("'abc", expect![[r#" Token { kind: Lifetime { starts_with_number: false }, len: 4 } - "#]], - ); + "#]]); } #[test] fn raw_string() { - check_lexing( - "r###\"\"#a\\b\x00c\"\"###", - expect![[r#" + check_lexing("r###\"\"#a\\b\x00c\"\"###", expect![[r#" Token { kind: Literal { kind: RawStr { n_hashes: Some(3) }, suffix_start: 17 }, len: 17 } - "#]], - ) + "#]]) } #[test] diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs index 5b99495f47581..6fa7a150516b8 100644 --- a/compiler/rustc_lexer/src/unescape/tests.rs +++ b/compiler/rustc_lexer/src/unescape/tests.rs @@ -108,15 +108,12 @@ fn test_unescape_str_warn() { check("\\\n", &[]); check("\\\n ", &[]); - check( - "\\\n \u{a0} x", - &[ - (0..5, Err(EscapeError::UnskippedWhitespaceWarning)), - (3..5, Ok('\u{a0}')), - (5..6, Ok(' ')), - (6..7, Ok('x')), - ], - ); + check("\\\n \u{a0} x", &[ + (0..5, Err(EscapeError::UnskippedWhitespaceWarning)), + (3..5, Ok('\u{a0}')), + (5..6, Ok(' ')), + (6..7, Ok('x')), + ]); check("\\\n \n x", &[(0..7, Err(EscapeError::MultipleSkippedLinesWarning)), (7..8, Ok('x'))]); } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 31b7eb5ee7df3..375cfccbe9f71 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -255,6 +255,7 @@ lint_duplicate_matcher_binding = duplicate matcher binding lint_elided_named_lifetime = elided lifetime has a name .label_elided = this elided lifetime gets resolved as `{$name}` .label_named = lifetime `{$name}` declared here + .suggestion = consider specifying it explicitly lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type @@ -333,6 +334,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len -> *[other] {" "}{$identifier_type} } Unicode general security profile +lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024 + .label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + .help = the value is now dropped here in Edition 2024 + .suggestion = a `match` with a single arm can preserve the drop order up to Edition 2021 + lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level lint_ill_formed_attribute_input = {$num_suggestions -> @@ -584,10 +590,7 @@ lint_non_local_definitions_cargo_update = the {$macro_kind} `{$macro_name}` may lint_non_local_definitions_deprecation = this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks should be written at the same level as their item - .remove_help = remove `{$may_remove_part}` to make the `impl` local - .without_trait = methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` - .with_trait = an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - .bounds = `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + .non_local = an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` .doctest = make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}` .exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint .const_anon = use a const-anon item to suppress this lint @@ -609,12 +612,6 @@ lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, `# remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}` .non_local = a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute -lint_non_local_definitions_may_move = may need to be moved as well - -lint_non_local_definitions_of_trait_not_local = `{$of_trait_str}` is not local - -lint_non_local_definitions_self_ty_not_local = `{$self_ty_str}` is not local - lint_non_snake_case = {$sort} `{$name}` should have a snake case name .rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier .cannot_convert_note = `{$sc}` cannot be used as a raw identifier @@ -699,11 +696,18 @@ lint_ptr_null_checks_ref = references are not nullable, so checking them for nul lint_query_instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale +lint_query_untracked = `{$method}` accesses information that is not tracked by the query system + .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale + lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}` lint_range_use_inclusive_range = use an inclusive range instead +lint_raw_prefix = prefix `'r` is reserved + .label = reserved prefix + .suggestion = insert whitespace here to avoid this being parsed as a prefix in Rust 2021 + lint_reason_must_be_string_literal = reason must be a string literal lint_reason_must_come_last = reason in lint attribute must come last @@ -756,6 +760,13 @@ lint_single_use_lifetime = lifetime parameter `{$ident}` only used once lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` +lint_static_mut_refs_lint = creating a {$shared_label}reference to mutable static is discouraged + .label = {$shared_label}reference to mutable static + .suggestion = use `&raw const` instead to create a raw pointer + .suggestion_mut = use `&raw mut` instead to create a raw pointer + .shared_note = shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + .mut_note = mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives + lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion .label = `{$self_ty}` implements `Deref` which conflicts with supertrait `{$supertrait_principal}` .label2 = target type is a supertrait of `{$self_ty}` @@ -783,6 +794,9 @@ lint_tykind = usage of `ty::TyKind` lint_tykind_kind = usage of `ty::TyKind::` .suggestion = try using `ty::` directly +lint_type_ir_inherent_usage = do not use `rustc_type_ir::inherent` unless you're inside of the trait solver + .note = the method or struct you're looking for is likely defined somewhere else downstream in the compiler + lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing .label = argument has type `{$arg_ty}` .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value @@ -874,6 +888,8 @@ lint_unnameable_test_items = cannot test inner items lint_unnecessary_qualification = unnecessary qualification .suggestion = remove the unnecessary path segments +lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::` + lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe .label = usage of unsafe attribute lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` diff --git a/compiler/rustc_lint/src/async_closures.rs b/compiler/rustc_lint/src/async_closures.rs index 33cc5738262f6..2a821b7110316 100644 --- a/compiler/rustc_lint/src/async_closures.rs +++ b/compiler/rustc_lint/src/async_closures.rs @@ -12,6 +12,7 @@ declare_lint! { /// ### Example /// /// ```rust + /// #![feature(async_closure)] /// #![warn(closure_returning_async_block)] /// let c = |x: &str| async {}; /// ``` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d8482567bbe5b..8bd9c899a6286 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -28,10 +28,10 @@ use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_errors::{Applicability, LintDiagnostic}; -use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; +use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::FnKind as HirFnKind; use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin}; use rustc_middle::bug; @@ -39,13 +39,13 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; +use rustc_session::lint::FutureIncompatibilityReason; // hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; -use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{BytePos, InnerSpan, Span}; use rustc_target::abi::Abi; use rustc_target::asm::InlineAsmArch; @@ -68,10 +68,10 @@ use crate::lints::{ BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel, }; -use crate::nonstandard_style::{method_context, MethodLateContext}; +use crate::nonstandard_style::{MethodLateContext, method_context}; use crate::{ - fluent_generated as fluent, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, - LintContext, + EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, + fluent_generated as fluent, }; declare_lint! { @@ -120,11 +120,10 @@ impl EarlyLintPass for WhileTrue { "{}loop", label.map_or_else(String::new, |label| format!("{}: ", label.ident,)) ); - cx.emit_span_lint( - WHILE_TRUE, - condition_span, - BuiltinWhileTrue { suggestion: condition_span, replace }, - ); + cx.emit_span_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue { + suggestion: condition_span, + replace, + }); } } } @@ -426,29 +425,20 @@ impl MissingDoc { article: &'static str, desc: &'static str, ) { - // If we're building a test harness, then warning about - // documentation is probably not really relevant right now. - if cx.sess().opts.test { - return; - } - // Only check publicly-visible items, using the result from the privacy pass. // 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.effective_visibilities.is_exported(def_id) { - return; - } + if def_id != CRATE_DEF_ID && !cx.effective_visibilities.is_exported(def_id) { + return; } let attrs = cx.tcx.hir().attrs(cx.tcx.local_def_id_to_hir_id(def_id)); let has_doc = attrs.iter().any(has_doc); if !has_doc { - cx.emit_span_lint( - MISSING_DOCS, - cx.tcx.def_span(def_id), - BuiltinMissingDoc { article, desc }, - ); + cx.emit_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), BuiltinMissingDoc { + article, + desc, + }); } } } @@ -729,11 +719,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { .next() .is_some(); if !has_impl { - cx.emit_span_lint( - MISSING_DEBUG_IMPLEMENTATIONS, - item.span, - BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug }, - ); + cx.emit_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, BuiltinMissingDebugImpl { + tcx: cx.tcx, + def_id: debug, + }); } } } @@ -855,24 +844,21 @@ impl EarlyLintPass for DeprecatedAttr { BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span } } }; - cx.emit_span_lint( - DEPRECATED, - attr.span, - BuiltinDeprecatedAttrLink { name, reason, link, suggestion }, - ); + cx.emit_span_lint(DEPRECATED, attr.span, BuiltinDeprecatedAttrLink { + name, + reason, + link, + suggestion, + }); } return; } } if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) { - cx.emit_span_lint( - DEPRECATED, - attr.span, - BuiltinDeprecatedAttrUsed { - name: pprust::path_to_string(&attr.get_normal_item().path), - suggestion: attr.span, - }, - ); + cx.emit_span_lint(DEPRECATED, attr.span, BuiltinDeprecatedAttrUsed { + name: pprust::path_to_string(&attr.get_normal_item().path), + suggestion: attr.span, + }); } } } @@ -907,11 +893,11 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & BuiltinUnusedDocCommentSub::BlockHelp } }; - cx.emit_span_lint( - UNUSED_DOC_COMMENTS, - span, - BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub }, - ); + cx.emit_span_lint(UNUSED_DOC_COMMENTS, span, BuiltinUnusedDocComment { + kind: node_kind, + label: node_span, + sub, + }); } } } @@ -1041,11 +1027,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - cx.emit_span_lint( - NO_MANGLE_GENERIC_ITEMS, - span, - BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span }, - ); + cx.emit_span_lint(NO_MANGLE_GENERIC_ITEMS, span, BuiltinNoMangleGeneric { + suggestion: no_mangle_attr.span, + }); break; } } @@ -1072,11 +1056,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to - cx.emit_span_lint( - NO_MANGLE_CONST_ITEMS, - it.span, - BuiltinConstNoMangle { suggestion }, - ); + cx.emit_span_lint(NO_MANGLE_CONST_ITEMS, it.span, BuiltinConstNoMangle { + suggestion, + }); } } hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { @@ -1324,15 +1306,11 @@ impl UnreachablePub { applicability = Applicability::MaybeIncorrect; } let def_span = cx.tcx.def_span(def_id); - cx.emit_span_lint( - UNREACHABLE_PUB, - def_span, - BuiltinUnreachablePub { - what, - suggestion: (vis_span, applicability), - help: exportable, - }, - ); + cx.emit_span_lint(UNREACHABLE_PUB, def_span, BuiltinUnreachablePub { + what, + suggestion: (vis_span, applicability), + help: exportable, + }); } } } @@ -1476,32 +1454,24 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let enable_feat_help = cx.tcx.sess.is_nightly_build(); if let [.., label_sp] = *where_spans { - cx.emit_span_lint( - TYPE_ALIAS_BOUNDS, - where_spans, - BuiltinTypeAliasBounds { - in_where_clause: true, - label: label_sp, - enable_feat_help, - suggestions: vec![(generics.where_clause_span, String::new())], - preds: generics.predicates, - ty: ty.take(), - }, - ); + cx.emit_span_lint(TYPE_ALIAS_BOUNDS, where_spans, BuiltinTypeAliasBounds { + in_where_clause: true, + label: label_sp, + enable_feat_help, + suggestions: vec![(generics.where_clause_span, String::new())], + preds: generics.predicates, + ty: ty.take(), + }); } if let [.., label_sp] = *inline_spans { - cx.emit_span_lint( - TYPE_ALIAS_BOUNDS, - inline_spans, - BuiltinTypeAliasBounds { - in_where_clause: false, - label: label_sp, - enable_feat_help, - suggestions: inline_sugg, - preds: generics.predicates, - ty, - }, - ); + cx.emit_span_lint(TYPE_ALIAS_BOUNDS, inline_spans, BuiltinTypeAliasBounds { + in_where_clause: false, + label: label_sp, + enable_feat_help, + suggestions: inline_sugg, + preds: generics.predicates, + ty, + }); } } } @@ -1587,11 +1557,10 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { | ClauseKind::ConstEvaluatable(..) => continue, }; if predicate.is_global() { - cx.emit_span_lint( - TRIVIAL_BOUNDS, - span, - BuiltinTrivialBounds { predicate_kind_name, predicate }, - ); + cx.emit_span_lint(TRIVIAL_BOUNDS, span, BuiltinTrivialBounds { + predicate_kind_name, + predicate, + }); } } } @@ -1851,9 +1820,16 @@ impl KeywordIdents { TokenTree::Token(token, _) => { if let Some((ident, token::IdentIsRaw::No)) = token.ident() { if !prev_dollar { - self.check_ident_token(cx, UnderMacro(true), ident); + self.check_ident_token(cx, UnderMacro(true), ident, ""); } - } else if *token == TokenKind::Dollar { + } else if let Some((ident, token::IdentIsRaw::No)) = token.lifetime() { + self.check_ident_token( + cx, + UnderMacro(true), + ident.without_first_quote(), + "'", + ); + } else if token.kind == TokenKind::Dollar { prev_dollar = true; continue; } @@ -1869,6 +1845,7 @@ impl KeywordIdents { cx: &EarlyContext<'_>, UnderMacro(under_macro): UnderMacro, ident: Ident, + prefix: &'static str, ) { let (lint, edition) = match ident.name { kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018), @@ -1899,11 +1876,12 @@ impl KeywordIdents { return; } - cx.emit_span_lint( - lint, - ident.span, - BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span }, - ); + cx.emit_span_lint(lint, ident.span, BuiltinKeywordIdents { + kw: ident, + next: edition, + suggestion: ident.span, + prefix, + }); } } @@ -1915,7 +1893,11 @@ impl EarlyLintPass for KeywordIdents { self.check_tokens(cx, &mac.args.tokens); } fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { - self.check_ident_token(cx, UnderMacro(false), ident); + if ident.name.as_str().starts_with('\'') { + self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'"); + } else { + self.check_ident_token(cx, UnderMacro(false), ident, ""); + } } } @@ -2318,11 +2300,11 @@ impl EarlyLintPass for IncompleteInternalFeatures { let help = HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp); - cx.emit_span_lint( - INCOMPLETE_FEATURES, - span, - BuiltinIncompleteFeatures { name, note, help }, - ); + cx.emit_span_lint(INCOMPLETE_FEATURES, span, BuiltinIncompleteFeatures { + name, + note, + help, + }); } else { cx.emit_span_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name }); } @@ -2643,17 +2625,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit, }; let sub = BuiltinUnpermittedTypeInitSub { err }; - cx.emit_span_lint( - INVALID_VALUE, - expr.span, - BuiltinUnpermittedTypeInit { - msg, - ty: conjured_ty, - label: expr.span, - sub, - tcx: cx.tcx, - }, - ); + cx.emit_span_lint(INVALID_VALUE, expr.span, BuiltinUnpermittedTypeInit { + msg, + ty: conjured_ty, + label: expr.span, + sub, + tcx: cx.tcx, + }); } } } @@ -2731,11 +2709,9 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind { if is_null_ptr(cx, expr_deref) { - cx.emit_span_lint( - DEREF_NULLPTR, - expr.span, - BuiltinDerefNullptr { label: expr.span }, - ); + cx.emit_span_lint(DEREF_NULLPTR, expr.span, BuiltinDerefNullptr { + label: expr.span, + }); } } } @@ -2952,18 +2928,14 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels { let span = span.unwrap_or(*template_span); match label_kind { AsmLabelKind::Named => { - cx.emit_span_lint( - NAMED_ASM_LABELS, - span, - InvalidAsmLabel::Named { missing_precise_span }, - ); + cx.emit_span_lint(NAMED_ASM_LABELS, span, InvalidAsmLabel::Named { + missing_precise_span, + }); } AsmLabelKind::FormatArg => { - cx.emit_span_lint( - NAMED_ASM_LABELS, - span, - InvalidAsmLabel::FormatArg { missing_precise_span }, - ); + cx.emit_span_lint(NAMED_ASM_LABELS, span, InvalidAsmLabel::FormatArg { + missing_precise_span, + }); } // the binary asm issue only occurs when using intel syntax on x86 targets AsmLabelKind::Binary @@ -2973,11 +2945,10 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels { Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) | None ) => { - cx.emit_span_lint( - BINARY_ASM_LABELS, + cx.emit_span_lint(BINARY_ASM_LABELS, span, InvalidAsmLabel::Binary { + missing_precise_span, span, - InvalidAsmLabel::Binary { missing_precise_span, span }, - ) + }) } // No lint on anything other than x86 AsmLabelKind::Binary => (), diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c9e2eee16b3b9..39f90a8e9ed14 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -29,15 +29,15 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::bug; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError, PrintTraitRefExt as _, Printer}; +use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths}; use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt}; use rustc_session::lint::{ BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId, }; use rustc_session::{LintStoreMarker, Session}; -use rustc_span::edit_distance::find_best_match_for_names; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use rustc_span::edit_distance::find_best_match_for_names; +use rustc_span::symbol::{Ident, Symbol, sym}; use rustc_target::abi; use tracing::debug; @@ -251,14 +251,11 @@ impl LintStore { } pub fn register_group_alias(&mut self, lint_name: &'static str, alias: &'static str) { - self.lint_groups.insert( - alias, - LintGroup { - lint_ids: vec![], - is_externally_loaded: false, - depr: Some(LintAlias { name: lint_name, silent: true }), - }, - ); + self.lint_groups.insert(alias, LintGroup { + lint_ids: vec![], + is_externally_loaded: false, + depr: Some(LintAlias { name: lint_name, silent: true }), + }); } pub fn register_group( @@ -273,14 +270,11 @@ impl LintStore { .insert(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None }) .is_none(); if let Some(deprecated) = deprecated_name { - self.lint_groups.insert( - deprecated, - LintGroup { - lint_ids: vec![], - is_externally_loaded, - depr: Some(LintAlias { name, silent: false }), - }, - ); + self.lint_groups.insert(deprecated, LintGroup { + lint_ids: vec![], + is_externally_loaded, + depr: Some(LintAlias { name, silent: false }), + }); } if !new { diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index fd43afa174383..168e3a8e92c5f 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -5,16 +5,16 @@ use std::borrow::Cow; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_errors::{ - elided_lifetime_in_path_suggestion, Applicability, Diag, DiagArgValue, LintDiagnostic, + Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion, }; use rustc_middle::middle::stability; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::Session; -use rustc_span::symbol::kw; +use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution}; use rustc_span::BytePos; +use rustc_span::symbol::kw; use tracing::debug; -use crate::lints; +use crate::lints::{self, ElidedNamedLifetime}; mod check_cfg; @@ -172,6 +172,10 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & } .decorate_lint(diag); } + BuiltinLintDiag::RawPrefix(label_span) => { + lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() } + .decorate_lint(diag); + } BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => { lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag); } @@ -442,15 +446,14 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => { lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag) } - BuiltinLintDiag::ElidedIsStatic { elided } => { - lints::ElidedNamedLifetime { elided, name: kw::StaticLifetime, named_declaration: None } - .decorate_lint(diag) - } - BuiltinLintDiag::ElidedIsParam { elided, param: (param_name, param_span) } => { - lints::ElidedNamedLifetime { - elided, - name: param_name, - named_declaration: Some(param_span), + BuiltinLintDiag::ElidedNamedLifetimes { elided: (span, kind), resolution } => { + match resolution { + ElidedLifetimeResolution::Static => { + ElidedNamedLifetime { span, kind, name: kw::StaticLifetime, declaration: None } + } + ElidedLifetimeResolution::Param(name, declaration) => { + ElidedNamedLifetime { span, kind, name, declaration: Some(declaration) } + } } .decorate_lint(diag) } diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs index fb3f40aa27108..16994846545df 100644 --- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs @@ -1,8 +1,9 @@ use rustc_middle::bug; -use rustc_session::config::ExpectedValues; use rustc_session::Session; +use rustc_session::config::ExpectedValues; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::symbol::Ident; +use rustc_span::{Span, Symbol, sym}; use crate::lints; @@ -30,7 +31,7 @@ enum EscapeQuotes { No, } -fn to_check_cfg_arg(name: Symbol, value: Option, quotes: EscapeQuotes) -> String { +fn to_check_cfg_arg(name: Ident, value: Option, quotes: EscapeQuotes) -> String { if let Some(value) = value { let value = str::escape_debug(value.as_str()).to_string(); let values = match quotes { @@ -110,6 +111,7 @@ pub(super) fn unexpected_cfg_name( } }; + let best_match = Ident::new(best_match, name_span); if let Some((value, value_span)) = value { if best_match_values.contains(&Some(value)) { lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue { @@ -163,6 +165,8 @@ pub(super) fn unexpected_cfg_name( }; let expected_names = if !possibilities.is_empty() { let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities); + let possibilities: Vec<_> = + possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect(); Some(lints::unexpected_cfg_name::ExpectedNames { possibilities: possibilities.into(), and_more, @@ -176,7 +180,9 @@ pub(super) fn unexpected_cfg_name( } }; - let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes); + let inst = |escape_quotes| { + to_check_cfg_arg(Ident::new(name, name_span), value.map(|(v, _s)| v), escape_quotes) + }; let invocation_help = if is_from_cargo { let sub = if !is_feature_cfg { Some(cargo_help_sub(sess, &inst)) } else { None }; @@ -267,13 +273,15 @@ pub(super) fn unexpected_cfg_value( // encouraged to do so. let can_suggest_adding_value = !sess.psess.check_config.well_known_names.contains(&name) // Except when working on rustc or the standard library itself, in which case we want to - // suggest adding these cfgs to the "normal" place because of bootstraping reasons. As a + // suggest adding these cfgs to the "normal" place because of bootstrapping reasons. As a // basic heuristic, we use the "cheat" unstable feature enable method and the // non-ui-testing enabled option. || (matches!(sess.psess.unstable_features, rustc_feature::UnstableFeatures::Cheat) && !sess.opts.unstable_opts.ui_testing); - let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes); + let inst = |escape_quotes| { + to_check_cfg_arg(Ident::new(name, name_span), value.map(|(v, _s)| v), escape_quotes) + }; let invocation_help = if is_from_cargo { let help = if name == sym::feature { diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index f174470b7a731..657642e093ccd 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -86,19 +86,14 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { .find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) .map(|label| SupertraitAsDerefTargetLabel { label }); let span = tcx.def_span(item.owner_id.def_id); - cx.emit_span_lint( - DEREF_INTO_DYN_SUPERTRAIT, - span, - SupertraitAsDerefTarget { - self_ty, - supertrait_principal: supertrait_principal.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - }), - target_principal, - label: span, - label2, - }, - ); + cx.emit_span_lint(DEREF_INTO_DYN_SUPERTRAIT, span, SupertraitAsDerefTarget { + self_ty, + supertrait_principal: supertrait_principal + .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)), + target_principal, + label: span, + label2, + }); } } } diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index a9de258e005c9..364c6fd488a8e 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -163,44 +163,32 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { }; match fn_name { sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { - cx.emit_span_lint( - DROPPING_REFERENCES, - expr.span, - DropRefDiag { arg_ty, label: arg.span, sugg: let_underscore_ignore_sugg() }, - ); + cx.emit_span_lint(DROPPING_REFERENCES, expr.span, DropRefDiag { + arg_ty, + label: arg.span, + sugg: let_underscore_ignore_sugg(), + }); } sym::mem_forget if arg_ty.is_ref() => { - cx.emit_span_lint( - FORGETTING_REFERENCES, - expr.span, - ForgetRefDiag { - arg_ty, - label: arg.span, - sugg: let_underscore_ignore_sugg(), - }, - ); + cx.emit_span_lint(FORGETTING_REFERENCES, expr.span, ForgetRefDiag { + arg_ty, + label: arg.span, + sugg: let_underscore_ignore_sugg(), + }); } sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { - cx.emit_span_lint( - DROPPING_COPY_TYPES, - expr.span, - DropCopyDiag { - arg_ty, - label: arg.span, - sugg: let_underscore_ignore_sugg(), - }, - ); + cx.emit_span_lint(DROPPING_COPY_TYPES, expr.span, DropCopyDiag { + arg_ty, + label: arg.span, + sugg: let_underscore_ignore_sugg(), + }); } sym::mem_forget if is_copy => { - cx.emit_span_lint( - FORGETTING_COPY_TYPES, - expr.span, - ForgetCopyDiag { - arg_ty, - label: arg.span, - sugg: let_underscore_ignore_sugg(), - }, - ); + cx.emit_span_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { + arg_ty, + label: arg.span, + sugg: let_underscore_ignore_sugg(), + }); } sym::mem_drop if let ty::Adt(adt, _) = arg_ty.kind() diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 0ee9dda1fefa2..2285877c9ef26 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -15,15 +15,15 @@ //! for all lint attributes. use rustc_ast::ptr::P; -use rustc_ast::visit::{self as ast_visit, walk_list, Visitor}; +use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; use rustc_ast::{self as ast, HasAttrs}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_feature::Features; use rustc_middle::ty::RegisteredTools; -use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::Session; -use rustc_span::symbol::Ident; +use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_span::Span; +use rustc_span::symbol::Ident; use tracing::debug; use crate::context::{EarlyContext, LintStore}; diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index 4e3eca496eadb..8e22a9bdc45a7 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -1,9 +1,9 @@ use rustc_hir as hir; -use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::Ty; +use rustc_middle::ty::visit::TypeVisitableExt; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use crate::context::LintContext; use crate::lints::{EnumIntrinsicsMemDiscriminate, EnumIntrinsicsMemVariant}; @@ -55,11 +55,10 @@ fn enforce_mem_discriminant( ) { let ty_param = cx.typeck_results().node_args(func_expr.hir_id).type_at(0); if is_non_enum(ty_param) { - cx.emit_span_lint( - ENUM_INTRINSICS_NON_ENUMS, - expr_span, - EnumIntrinsicsMemDiscriminate { ty_param, note: args_span }, - ); + cx.emit_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, EnumIntrinsicsMemDiscriminate { + ty_param, + note: args_span, + }); } } diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index d8afba3d5053c..289e2c9b72243 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,10 +1,10 @@ -use rustc_data_structures::fx::FxIndexMap; -use rustc_hir::{HirId, CRATE_OWNER_ID}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::CRATE_OWNER_ID; use rustc_middle::lint::LintExpectation; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::lint::LintExpectationId; use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS; -use rustc_session::lint::{Level, LintExpectationId}; use rustc_span::Symbol; use crate::lints::{Expectation, ExpectationNote}; @@ -17,43 +17,12 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp let krate = tcx.hir_crate_items(()); let mut expectations = Vec::new(); - let mut unstable_to_stable_ids = FxIndexMap::default(); - let mut record_stable = |attr_id, hir_id, attr_index| { - let expect_id = LintExpectationId::Stable { hir_id, attr_index, lint_index: None }; - unstable_to_stable_ids.entry(attr_id).or_insert(expect_id); - }; - let mut push_expectations = |owner| { + for owner in std::iter::once(CRATE_OWNER_ID).chain(krate.owners()) { let lints = tcx.shallow_lint_levels_on(owner); - if lints.expectations.is_empty() { - return; - } - expectations.extend_from_slice(&lints.expectations); - - let attrs = tcx.hir_attrs(owner); - for &(local_id, attrs) in attrs.map.iter() { - // Some attributes appear multiple times in HIR, to ensure they are correctly taken - // into account where they matter. This means we cannot just associate the AttrId to - // the first HirId where we see it, but need to check it actually appears in a lint - // level. - // FIXME(cjgillot): Can this cause an attribute to appear in multiple expectation ids? - if !lints.specs.contains_key(&local_id) { - continue; - } - for (attr_index, attr) in attrs.iter().enumerate() { - let Some(Level::Expect(_)) = Level::from_attr(attr) else { continue }; - record_stable(attr.id, HirId { owner, local_id }, attr_index.try_into().unwrap()); - } - } - }; - - push_expectations(CRATE_OWNER_ID); - for owner in krate.owners() { - push_expectations(owner); } - tcx.dcx().update_unstable_expectation_id(unstable_to_stable_ids); expectations } @@ -61,24 +30,43 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { let lint_expectations = tcx.lint_expectations(()); let fulfilled_expectations = tcx.dcx().steal_fulfilled_expectation_ids(); - for (id, expectation) in lint_expectations { - // This check will always be true, since `lint_expectations` only - // holds stable ids - if let LintExpectationId::Stable { hir_id, .. } = id { - if !fulfilled_expectations.contains(id) - && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) - { - let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); - let note = expectation.is_unfulfilled_lint_expectations; - tcx.emit_node_span_lint( - UNFULFILLED_LINT_EXPECTATIONS, - *hir_id, - expectation.emission_span, - Expectation { rationale, note }, - ); + // Turn a `LintExpectationId` into a `(AttrId, lint_index)` pair. + let canonicalize_id = |expect_id: &LintExpectationId| { + match *expect_id { + LintExpectationId::Unstable { attr_id, lint_index: Some(lint_index) } => { + (attr_id, lint_index) + } + LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { + // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok. + let attr_id = tcx.hir().attrs(hir_id)[attr_index as usize].id; + (attr_id, lint_index) } - } else { + _ => panic!("fulfilled expectations must have a lint index"), + } + }; + + let fulfilled_expectations: FxHashSet<_> = + fulfilled_expectations.iter().map(canonicalize_id).collect(); + + for (expect_id, expectation) in lint_expectations { + // This check will always be true, since `lint_expectations` only holds stable ids + let LintExpectationId::Stable { hir_id, .. } = expect_id else { unreachable!("at this stage all `LintExpectationId`s are stable"); + }; + + let expect_id = canonicalize_id(expect_id); + + if !fulfilled_expectations.contains(&expect_id) + && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) + { + let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); + let note = expectation.is_unfulfilled_lint_expectations; + tcx.emit_node_span_lint( + UNFULFILLED_LINT_EXPECTATIONS, + *hir_id, + expectation.emission_span, + Expectation { rationale, note }, + ); } } } diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index 2793d48dc512b..fcb7a6108c0e2 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; use rustc_middle::ty; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_trait_selection::traits::ObligationCtxt; use crate::lints::{ @@ -96,11 +96,14 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { end_span: pat.span.between(arg.span), }; - cx.emit_span_lint( - FOR_LOOPS_OVER_FALLIBLES, - arg.span, - ForLoopsOverFalliblesDiag { article, ref_prefix, ty, sub, question_mark, suggestion }, - ); + cx.emit_span_lint(FOR_LOOPS_OVER_FALLIBLES, arg.span, ForLoopsOverFalliblesDiag { + article, + ref_prefix, + ty, + sub, + question_mark, + suggestion, + }); } } @@ -133,7 +136,7 @@ fn extract_iterator_next_call<'tcx>( { Some(recv) } else { - return None; + None } } diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index a60fc0ffbbb3b..1ead377607f1b 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -3,15 +3,14 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::query::Providers; -use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_session::declare_lint; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::abi::FIRST_VARIANT; use tracing::{debug, instrument}; use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub}; -use crate::{types, LintVec}; +use crate::{LintVec, types}; pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { clashing_extern_declarations, ..*providers }; @@ -212,7 +211,17 @@ fn structurally_same_type<'tcx>( ckind: types::CItemKind, ) -> bool { let mut seen_types = UnordSet::default(); - structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind) + let result = structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind); + if cfg!(debug_assertions) && result { + // Sanity-check: must have same ABI, size and alignment. + // `extern` blocks cannot be generic, so we'll always get a layout here. + let a_layout = tcx.layout_of(param_env.and(a)).unwrap(); + let b_layout = tcx.layout_of(param_env.and(b)).unwrap(); + assert_eq!(a_layout.abi, b_layout.abi); + assert_eq!(a_layout.size, b_layout.size); + assert_eq!(a_layout.align, b_layout.align); + } + result } fn structurally_same_type_impl<'tcx>( @@ -266,30 +275,21 @@ fn structurally_same_type_impl<'tcx>( // Do a full, depth-first comparison between the two. use rustc_type_ir::TyKind::*; - let compare_layouts = |a, b| -> Result> { - debug!("compare_layouts({:?}, {:?})", a, b); - let a_layout = &tcx.layout_of(param_env.and(a))?.layout.abi(); - let b_layout = &tcx.layout_of(param_env.and(b))?.layout.abi(); - debug!( - "comparing layouts: {:?} == {:?} = {}", - a_layout, - b_layout, - a_layout == b_layout - ); - Ok(a_layout == b_layout) - }; - let is_primitive_or_pointer = |ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind(), RawPtr(..) | Ref(..)); ensure_sufficient_stack(|| { match (a.kind(), b.kind()) { - (Adt(a_def, _), Adt(b_def, _)) => { - // We can immediately rule out these types as structurally same if - // their layouts differ. - match compare_layouts(a, b) { - Ok(false) => return false, - _ => (), // otherwise, continue onto the full, fields comparison + (&Adt(a_def, _), &Adt(b_def, _)) => { + // Only `repr(C)` types can be compared structurally. + if !(a_def.repr().c() && b_def.repr().c()) { + return false; + } + // If the types differ in their packed-ness, align, or simd-ness they conflict. + let repr_characteristica = + |def: AdtDef<'tcx>| (def.repr().pack, def.repr().align, def.repr().simd()); + if repr_characteristica(a_def) != repr_characteristica(b_def) { + return false; } // Grab a flattened representation of all fields. @@ -311,9 +311,9 @@ fn structurally_same_type_impl<'tcx>( }, ) } - (Array(a_ty, a_const), Array(b_ty, b_const)) => { - // For arrays, we also check the constness of the type. - a_const.kind() == b_const.kind() + (Array(a_ty, a_len), Array(b_ty, b_len)) => { + // For arrays, we also check the length. + a_len == b_len && structurally_same_type_impl( seen_types, tcx, param_env, *a_ty, *b_ty, ckind, ) @@ -357,10 +357,9 @@ fn structurally_same_type_impl<'tcx>( ckind, ) } - (Tuple(a_args), Tuple(b_args)) => { - a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| { - structurally_same_type_impl(seen_types, tcx, param_env, a_ty, b_ty, ckind) - }) + (Tuple(..), Tuple(..)) => { + // Tuples are not `repr(C)` so these cannot be compared structurally. + false } // For these, it's not quite as easy to define structural-sameness quite so easily. // For the purposes of this lint, take the conservative approach and mark them as @@ -380,24 +379,21 @@ fn structurally_same_type_impl<'tcx>( // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. (Adt(..), _) if is_primitive_or_pointer(b) => { - if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, a, ckind) { - ty == b + if let Some(a_inner) = types::repr_nullable_ptr(tcx, param_env, a, ckind) { + a_inner == b } else { - compare_layouts(a, b).unwrap_or(false) + false } } (_, Adt(..)) if is_primitive_or_pointer(a) => { - if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, b, ckind) { - ty == a + if let Some(b_inner) = types::repr_nullable_ptr(tcx, param_env, b, ckind) { + b_inner == a } else { - compare_layouts(a, b).unwrap_or(false) + false } } - // Otherwise, just compare the layouts. This may fail to lint for some - // incompatible types, but at the very least, will stop reads into - // uninitialised memory. - _ => compare_layouts(a, b).unwrap_or(false), + _ => false, } }) } diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index ebd8bd5605d78..025fd45204064 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -1,4 +1,4 @@ -use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS}; +use ast::util::unicode::{TEXT_FLOW_CONTROL_CHARS, contains_text_flow_control_chars}; use rustc_ast as ast; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{BytePos, Span, Symbol}; @@ -73,11 +73,13 @@ impl HiddenUnicodeCodepoints { HiddenUnicodeCodepointsDiagSub::NoEscape { spans } }; - cx.emit_span_lint( - TEXT_DIRECTION_CODEPOINT_IN_LITERAL, - span, - HiddenUnicodeCodepointsDiag { label, count, span_label: span, labels, sub }, - ); + cx.emit_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, HiddenUnicodeCodepointsDiag { + label, + count, + span_label: span, + labels, + sub, + }); } } impl EarlyLintPass for HiddenUnicodeCodepoints { diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs new file mode 100644 index 0000000000000..229d0c3642174 --- /dev/null +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -0,0 +1,425 @@ +use std::iter::repeat; +use std::ops::ControlFlow; + +use hir::intravisit::Visitor; +use rustc_ast::Recovered; +use rustc_errors::{ + Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, +}; +use rustc_hir::{self as hir, HirIdSet}; +use rustc_macros::LintDiagnostic; +use rustc_middle::ty::TyCtxt; +use rustc_session::lint::{FutureIncompatibilityReason, Level}; +use rustc_session::{declare_lint, impl_lint_pass}; +use rustc_span::Span; +use rustc_span::edition::Edition; + +use crate::{LateContext, LateLintPass}; + +declare_lint! { + /// The `if_let_rescope` lint detects cases where a temporary value with + /// significant drop is generated on the right hand side of `if let` + /// and suggests a rewrite into `match` when possible. + /// + /// ### Example + /// + /// ```rust,edition2021 + /// #![cfg_attr(not(bootstrap), feature(if_let_rescope))] // Simplify this in bootstrap bump. + /// #![warn(if_let_rescope)] + /// #![allow(unused_variables)] + /// + /// struct Droppy; + /// impl Drop for Droppy { + /// fn drop(&mut self) { + /// // Custom destructor, including this `drop` implementation, is considered + /// // significant. + /// // Rust does not check whether this destructor emits side-effects that can + /// // lead to observable change in program semantics, when the drop order changes. + /// // Rust biases to be on the safe side, so that you can apply discretion whether + /// // this change indeed breaches any contract or specification that your code needs + /// // to honour. + /// println!("dropped"); + /// } + /// } + /// impl Droppy { + /// fn get(&self) -> Option { + /// None + /// } + /// } + /// + /// fn main() { + /// if let Some(value) = Droppy.get() { + /// // do something + /// } else { + /// // do something else + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With Edition 2024, temporaries generated while evaluating `if let`s + /// will be dropped before the `else` block. + /// This lint captures a possible change in runtime behaviour due to + /// a change in sequence of calls to significant `Drop::drop` destructors. + /// + /// A significant [`Drop::drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html) + /// destructor here refers to an explicit, arbitrary implementation of the `Drop` trait on the type + /// with exceptions including `Vec`, `Box`, `Rc`, `BTreeMap` and `HashMap` + /// that are marked by the compiler otherwise so long that the generic types have + /// no significant destructor recursively. + /// In other words, a type has a significant drop destructor when it has a `Drop` implementation + /// or its destructor invokes a significant destructor on a type. + /// Since we cannot completely reason about the change by just inspecting the existence of + /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default. + /// + /// Whenever possible, a rewrite into an equivalent `match` expression that + /// observe the same order of calls to such destructors is proposed by this lint. + /// Authors may take their own discretion whether the rewrite suggestion shall be + /// accepted, or rejected to continue the use of the `if let` expression. + pub IF_LET_RESCOPE, + Allow, + "`if let` assigns a shorter lifetime to temporary values being pattern-matched against in Edition 2024 and \ + rewriting in `match` is an option to preserve the semantics up to Edition 2021", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "issue #124085 ", + }; +} + +/// Lint for potential change in program semantics of `if let`s +#[derive(Default)] +pub(crate) struct IfLetRescope { + skip: HirIdSet, +} + +fn expr_parent_is_else(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { + let Some((_, hir::Node::Expr(expr))) = tcx.hir().parent_iter(hir_id).next() else { + return false; + }; + let hir::ExprKind::If(_cond, _conseq, Some(alt)) = expr.kind else { return false }; + alt.hir_id == hir_id +} + +fn expr_parent_is_stmt(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { + let Some((_, hir::Node::Stmt(stmt))) = tcx.hir().parent_iter(hir_id).next() else { + return false; + }; + let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = stmt.kind else { return false }; + expr.hir_id == hir_id +} + +fn match_head_needs_bracket(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> bool { + expr_parent_is_else(tcx, expr.hir_id) && matches!(expr.kind, hir::ExprKind::If(..)) +} + +impl IfLetRescope { + fn probe_if_cascade<'tcx>(&mut self, cx: &LateContext<'tcx>, mut expr: &'tcx hir::Expr<'tcx>) { + if self.skip.contains(&expr.hir_id) { + return; + } + let tcx = cx.tcx; + let source_map = tcx.sess.source_map(); + let expr_end = expr.span.shrink_to_hi(); + let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr); + let mut significant_droppers = vec![]; + let mut lifetime_ends = vec![]; + let mut closing_brackets = 0; + let mut alt_heads = vec![]; + let mut match_heads = vec![]; + let mut consequent_heads = vec![]; + let mut first_if_to_lint = None; + let mut first_if_to_rewrite = false; + let mut empty_alt = false; + while let hir::ExprKind::If(cond, conseq, alt) = expr.kind { + self.skip.insert(expr.hir_id); + // We are interested in `let` fragment of the condition. + // Otherwise, we probe into the `else` fragment. + if let hir::ExprKind::Let(&hir::LetExpr { + span, + pat, + init, + ty: ty_ascription, + recovered: Recovered::No, + }) = cond.kind + { + let if_let_pat = expr.span.shrink_to_lo().between(init.span); + // The consequent fragment is always a block. + let before_conseq = conseq.span.shrink_to_lo(); + let lifetime_end = source_map.end_point(conseq.span); + + if let ControlFlow::Break(significant_dropper) = + (FindSignificantDropper { cx }).visit_expr(init) + { + first_if_to_lint = first_if_to_lint.or_else(|| Some((span, expr.hir_id))); + significant_droppers.push(significant_dropper); + lifetime_ends.push(lifetime_end); + if ty_ascription.is_some() + || !expr.span.can_be_used_for_suggestions() + || !pat.span.can_be_used_for_suggestions() + { + // Our `match` rewrites does not support type ascription, + // so we just bail. + // Alternatively when the span comes from proc macro expansion, + // we will also bail. + // FIXME(#101728): change this when type ascription syntax is stabilized again + } else if let Ok(pat) = source_map.span_to_snippet(pat.span) { + let emit_suggestion = |alt_span| { + first_if_to_rewrite = true; + if add_bracket_to_match_head { + closing_brackets += 2; + match_heads.push(SingleArmMatchBegin::WithOpenBracket(if_let_pat)); + } else { + // Sometimes, wrapping `match` into a block is undesirable, + // because the scrutinee temporary lifetime is shortened and + // the proposed fix will not work. + closing_brackets += 1; + match_heads + .push(SingleArmMatchBegin::WithoutOpenBracket(if_let_pat)); + } + consequent_heads.push(ConsequentRewrite { span: before_conseq, pat }); + if let Some(alt_span) = alt_span { + alt_heads.push(AltHead(alt_span)); + } + }; + if let Some(alt) = alt { + let alt_head = conseq.span.between(alt.span); + if alt_head.can_be_used_for_suggestions() { + // We lint only when the `else` span is user code, too. + emit_suggestion(Some(alt_head)); + } + } else { + // This is the end of the `if .. else ..` cascade. + // We can stop here. + emit_suggestion(None); + empty_alt = true; + break; + } + } + } + } + // At this point, any `if let` fragment in the cascade is definitely preceeded by `else`, + // so a opening bracket is mandatory before each `match`. + add_bracket_to_match_head = true; + if let Some(alt) = alt { + expr = alt; + } else { + break; + } + } + if let Some((span, hir_id)) = first_if_to_lint { + tcx.emit_node_span_lint(IF_LET_RESCOPE, hir_id, span, IfLetRescopeLint { + significant_droppers, + lifetime_ends, + rewrite: first_if_to_rewrite.then_some(IfLetRescopeRewrite { + match_heads, + consequent_heads, + closing_brackets: ClosingBrackets { + span: expr_end, + count: closing_brackets, + empty_alt, + }, + alt_heads, + }), + }); + } + } +} + +impl_lint_pass!( + IfLetRescope => [IF_LET_RESCOPE] +); + +impl<'tcx> LateLintPass<'tcx> for IfLetRescope { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope { + return; + } + if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { + return; + } + if expr_parent_is_stmt(cx.tcx, expr.hir_id) + && matches!(expr.kind, hir::ExprKind::If(_cond, _conseq, None)) + { + // `if let` statement without an `else` branch has no observable change + // so we can skip linting it + return; + } + self.probe_if_cascade(cx, expr); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_if_let_rescope)] +struct IfLetRescopeLint { + #[label] + significant_droppers: Vec, + #[help] + lifetime_ends: Vec, + #[subdiagnostic] + rewrite: Option, +} + +// #[derive(Subdiagnostic)] +struct IfLetRescopeRewrite { + match_heads: Vec, + consequent_heads: Vec, + closing_brackets: ClosingBrackets, + alt_heads: Vec, +} + +impl Subdiagnostic for IfLetRescopeRewrite { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + let mut suggestions = vec![]; + for match_head in self.match_heads { + match match_head { + SingleArmMatchBegin::WithOpenBracket(span) => { + suggestions.push((span, "{ match ".into())) + } + SingleArmMatchBegin::WithoutOpenBracket(span) => { + suggestions.push((span, "match ".into())) + } + } + } + for ConsequentRewrite { span, pat } in self.consequent_heads { + suggestions.push((span, format!("{{ {pat} => "))); + } + for AltHead(span) in self.alt_heads { + suggestions.push((span, " _ => ".into())); + } + let closing_brackets = self.closing_brackets; + suggestions.push(( + closing_brackets.span, + closing_brackets + .empty_alt + .then_some(" _ => {}".chars()) + .into_iter() + .flatten() + .chain(repeat('}').take(closing_brackets.count)) + .collect(), + )); + let msg = f(diag, crate::fluent_generated::lint_suggestion.into()); + diag.multipart_suggestion_with_style( + msg, + suggestions, + Applicability::MachineApplicable, + SuggestionStyle::ShowCode, + ); + } +} + +struct AltHead(Span); + +struct ConsequentRewrite { + span: Span, + pat: String, +} + +struct ClosingBrackets { + span: Span, + count: usize, + empty_alt: bool, +} +enum SingleArmMatchBegin { + WithOpenBracket(Span), + WithoutOpenBracket(Span), +} + +struct FindSignificantDropper<'tcx, 'a> { + cx: &'a LateContext<'tcx>, +} + +impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> { + type Result = ControlFlow; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result { + if self + .cx + .typeck_results() + .expr_ty(expr) + .has_significant_drop(self.cx.tcx, self.cx.param_env) + { + return ControlFlow::Break(expr.span); + } + match expr.kind { + hir::ExprKind::ConstBlock(_) + | hir::ExprKind::Lit(_) + | hir::ExprKind::Path(_) + | hir::ExprKind::Assign(_, _, _) + | hir::ExprKind::AssignOp(_, _, _) + | hir::ExprKind::Break(_, _) + | hir::ExprKind::Continue(_) + | hir::ExprKind::Ret(_) + | hir::ExprKind::Become(_) + | hir::ExprKind::InlineAsm(_) + | hir::ExprKind::OffsetOf(_, _) + | hir::ExprKind::Repeat(_, _) + | hir::ExprKind::Err(_) + | hir::ExprKind::Struct(_, _, _) + | hir::ExprKind::Closure(_) + | hir::ExprKind::Block(_, _) + | hir::ExprKind::DropTemps(_) + | hir::ExprKind::Loop(_, _, _, _) => ControlFlow::Continue(()), + + hir::ExprKind::Tup(exprs) | hir::ExprKind::Array(exprs) => { + for expr in exprs { + self.visit_expr(expr)?; + } + ControlFlow::Continue(()) + } + hir::ExprKind::Call(callee, args) => { + self.visit_expr(callee)?; + for expr in args { + self.visit_expr(expr)?; + } + ControlFlow::Continue(()) + } + hir::ExprKind::MethodCall(_, receiver, args, _) => { + self.visit_expr(receiver)?; + for expr in args { + self.visit_expr(expr)?; + } + ControlFlow::Continue(()) + } + hir::ExprKind::Index(left, right, _) | hir::ExprKind::Binary(_, left, right) => { + self.visit_expr(left)?; + self.visit_expr(right) + } + hir::ExprKind::Unary(_, expr) + | hir::ExprKind::Cast(expr, _) + | hir::ExprKind::Type(expr, _) + | hir::ExprKind::Yield(expr, _) + | hir::ExprKind::AddrOf(_, _, expr) + | hir::ExprKind::Match(expr, _, _) + | hir::ExprKind::Field(expr, _) + | hir::ExprKind::Let(&hir::LetExpr { + init: expr, + span: _, + pat: _, + ty: _, + recovered: Recovered::No, + }) => self.visit_expr(expr), + hir::ExprKind::Let(_) => ControlFlow::Continue(()), + + hir::ExprKind::If(cond, _, _) => { + if let hir::ExprKind::Let(hir::LetExpr { + init, + span: _, + pat: _, + ty: _, + recovered: Recovered::No, + }) = cond.kind + { + self.visit_expr(init)?; + } + ControlFlow::Continue(()) + } + } + } +} diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 8824e1dfe50d8..a073d16f634d8 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -1,21 +1,31 @@ -use rustc_data_structures::fx::FxIndexSet; +use std::assert_matches::debug_assert_matches; +use std::cell::LazyCell; + +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{Applicability, LintDiagnostic}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_macros::LintDiagnostic; -use rustc_middle::bug; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; +use rustc_middle::ty::relate::{ + Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, +}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; +use rustc_middle::{bug, span_bug}; use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; +use rustc_trait_selection::traits::ObligationCtxt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt; -use crate::{fluent_generated as fluent, LateContext, LateLintPass}; +use crate::{LateContext, LateLintPass, fluent_generated as fluent}; declare_lint! { /// The `impl_trait_overcaptures` lint warns against cases where lifetime @@ -119,20 +129,41 @@ impl<'tcx> LateLintPass<'tcx> for ImplTraitOvercaptures { } } +#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] +enum ParamKind { + // Early-bound var. + Early(Symbol, u32), + // Late-bound var on function, not within a binder. We can capture these. + Free(DefId, Symbol), + // Late-bound var in a binder. We can't capture these yet. + Late, +} + fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { let sig = tcx.fn_sig(parent_def_id).instantiate_identity(); - let mut in_scope_parameters = FxIndexSet::default(); + let mut in_scope_parameters = FxIndexMap::default(); // Populate the in_scope_parameters list first with all of the generics in scope let mut current_def_id = Some(parent_def_id.to_def_id()); while let Some(def_id) = current_def_id { let generics = tcx.generics_of(def_id); for param in &generics.own_params { - in_scope_parameters.insert(param.def_id); + in_scope_parameters.insert(param.def_id, ParamKind::Early(param.name, param.index)); } current_def_id = generics.parent; } + for bound_var in sig.bound_vars() { + let ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, name)) = bound_var + else { + span_bug!(tcx.def_span(parent_def_id), "unexpected non-lifetime binder on fn sig"); + }; + + in_scope_parameters.insert(def_id, ParamKind::Free(def_id, name)); + } + + let sig = tcx.liberate_late_bound_regions(parent_def_id.to_def_id(), sig); + // Then visit the signature to walk through all the binders (incl. the late-bound // vars on the function itself, which we need to count too). sig.visit_with(&mut VisitOpaqueTypes { @@ -140,21 +171,45 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { parent_def_id, in_scope_parameters, seen: Default::default(), + // Lazily compute these two, since they're likely a bit expensive. + variances: LazyCell::new(|| { + let mut functional_variances = FunctionalVariances { + tcx: tcx, + variances: FxHashMap::default(), + ambient_variance: ty::Covariant, + generics: tcx.generics_of(parent_def_id), + }; + functional_variances.relate(sig, sig).unwrap(); + functional_variances.variances + }), + outlives_env: LazyCell::new(|| { + let param_env = tcx.param_env(parent_def_id); + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default(); + let implied_bounds = + infcx.implied_bounds_tys_compat(param_env, parent_def_id, &assumed_wf_tys, false); + OutlivesEnvironment::with_bounds(param_env, implied_bounds) + }), }); } -struct VisitOpaqueTypes<'tcx> { +struct VisitOpaqueTypes<'tcx, VarFn, OutlivesFn> { tcx: TyCtxt<'tcx>, parent_def_id: LocalDefId, - in_scope_parameters: FxIndexSet, + in_scope_parameters: FxIndexMap, + variances: LazyCell, VarFn>, + outlives_env: LazyCell, OutlivesFn>, seen: FxIndexSet, } -impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { - fn visit_binder>>( - &mut self, - t: &ty::Binder<'tcx, T>, - ) -> Self::Result { +impl<'tcx, VarFn, OutlivesFn> TypeVisitor> + for VisitOpaqueTypes<'tcx, VarFn, OutlivesFn> +where + VarFn: FnOnce() -> FxHashMap, + OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>, +{ + fn visit_binder>>(&mut self, t: &ty::Binder<'tcx, T>) { // When we get into a binder, we need to add its own bound vars to the scope. let mut added = vec![]; for arg in t.bound_vars() { @@ -163,8 +218,8 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..)) | ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => { added.push(def_id); - let unique = self.in_scope_parameters.insert(def_id); - assert!(unique); + let unique = self.in_scope_parameters.insert(def_id, ParamKind::Late); + assert_eq!(unique, None); } _ => { self.tcx.dcx().span_delayed_bug( @@ -184,7 +239,7 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { } } - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + fn visit_ty(&mut self, t: Ty<'tcx>) { if !t.has_aliases() { return; } @@ -207,89 +262,128 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { && let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin && parent_def_id == self.parent_def_id { - // Compute the set of args that are captured by the opaque... - let mut captured = FxIndexSet::default(); - let variances = self.tcx.variances_of(opaque_def_id); - let mut current_def_id = Some(opaque_def_id.to_def_id()); - while let Some(def_id) = current_def_id { - let generics = self.tcx.generics_of(def_id); - for param in &generics.own_params { - // A param is captured if it's invariant. - if variances[param.index as usize] != ty::Invariant { - continue; - } - // We need to turn all `ty::Param`/`ConstKind::Param` and - // `ReEarlyParam`/`ReBound` into def ids. - captured.insert(extract_def_id_from_arg( - self.tcx, - generics, - opaque_ty.args[param.index as usize], - )); - } - current_def_id = generics.parent; - } - - // Compute the set of in scope params that are not captured. Get their spans, - // since that's all we really care about them for emitting the diagnostic. - let uncaptured_spans: Vec<_> = self - .in_scope_parameters - .iter() - .filter(|def_id| !captured.contains(*def_id)) - .map(|def_id| self.tcx.def_span(def_id)) - .collect(); - let opaque_span = self.tcx.def_span(opaque_def_id); let new_capture_rules = opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024; - - // If we have uncaptured args, and if the opaque doesn't already have - // `use<>` syntax on it, and we're < edition 2024, then warn the user. if !new_capture_rules && !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) - && !uncaptured_spans.is_empty() { - let suggestion = if let Ok(snippet) = - self.tcx.sess.source_map().span_to_snippet(opaque_span) - && snippet.starts_with("impl ") - { - let (lifetimes, others): (Vec<_>, Vec<_>) = captured - .into_iter() - .partition(|def_id| self.tcx.def_kind(*def_id) == DefKind::LifetimeParam); - // Take all lifetime params first, then all others (ty/ct). - let generics: Vec<_> = lifetimes - .into_iter() - .chain(others) - .map(|def_id| self.tcx.item_name(def_id).to_string()) - .collect(); - // Make sure that we're not trying to name any APITs - if generics.iter().all(|name| !name.starts_with("impl ")) { - Some(( - format!(" + use<{}>", generics.join(", ")), - opaque_span.shrink_to_hi(), - )) + // Compute the set of args that are captured by the opaque... + let mut captured = FxIndexSet::default(); + let mut captured_regions = FxIndexSet::default(); + let variances = self.tcx.variances_of(opaque_def_id); + let mut current_def_id = Some(opaque_def_id.to_def_id()); + while let Some(def_id) = current_def_id { + let generics = self.tcx.generics_of(def_id); + for param in &generics.own_params { + // A param is captured if it's invariant. + if variances[param.index as usize] != ty::Invariant { + continue; + } + + let arg = opaque_ty.args[param.index as usize]; + // We need to turn all `ty::Param`/`ConstKind::Param` and + // `ReEarlyParam`/`ReBound` into def ids. + captured.insert(extract_def_id_from_arg(self.tcx, generics, arg)); + + captured_regions.extend(arg.as_region()); + } + current_def_id = generics.parent; + } + + // Compute the set of in scope params that are not captured. + let mut uncaptured_args: FxIndexSet<_> = self + .in_scope_parameters + .iter() + .filter(|&(def_id, _)| !captured.contains(def_id)) + .collect(); + // Remove the set of lifetimes that are in-scope that outlive some other captured + // lifetime and are contravariant (i.e. covariant in argument position). + uncaptured_args.retain(|&(def_id, kind)| { + let Some(ty::Bivariant | ty::Contravariant) = self.variances.get(def_id) else { + // Keep all covariant/invariant args. Also if variance is `None`, + // then that means it's either not a lifetime, or it didn't show up + // anywhere in the signature. + return true; + }; + // We only computed variance of lifetimes... + debug_assert_matches!(self.tcx.def_kind(def_id), DefKind::LifetimeParam); + let uncaptured = match *kind { + ParamKind::Early(name, index) => { + ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion { + name, + index, + }) + } + ParamKind::Free(def_id, name) => ty::Region::new_late_param( + self.tcx, + self.parent_def_id.to_def_id(), + ty::BoundRegionKind::BrNamed(def_id, name), + ), + // Totally ignore late bound args from binders. + ParamKind::Late => return true, + }; + // Does this region outlive any captured region? + !captured_regions.iter().any(|r| { + self.outlives_env + .free_region_map() + .sub_free_regions(self.tcx, *r, uncaptured) + }) + }); + + // If we have uncaptured args, and if the opaque doesn't already have + // `use<>` syntax on it, and we're < edition 2024, then warn the user. + if !uncaptured_args.is_empty() { + let suggestion = if let Ok(snippet) = + self.tcx.sess.source_map().span_to_snippet(opaque_span) + && snippet.starts_with("impl ") + { + let (lifetimes, others): (Vec<_>, Vec<_>) = + captured.into_iter().partition(|def_id| { + self.tcx.def_kind(*def_id) == DefKind::LifetimeParam + }); + // Take all lifetime params first, then all others (ty/ct). + let generics: Vec<_> = lifetimes + .into_iter() + .chain(others) + .map(|def_id| self.tcx.item_name(def_id).to_string()) + .collect(); + // Make sure that we're not trying to name any APITs + if generics.iter().all(|name| !name.starts_with("impl ")) { + Some(( + format!(" + use<{}>", generics.join(", ")), + opaque_span.shrink_to_hi(), + )) + } else { + None + } } else { None - } - } else { - None - }; - - self.tcx.emit_node_span_lint( - IMPL_TRAIT_OVERCAPTURES, - self.tcx.local_def_id_to_hir_id(opaque_def_id), - opaque_span, - ImplTraitOvercapturesLint { - self_ty: t, - num_captured: uncaptured_spans.len(), - uncaptured_spans, - suggestion, - }, - ); + }; + + let uncaptured_spans: Vec<_> = uncaptured_args + .into_iter() + .map(|(def_id, _)| self.tcx.def_span(def_id)) + .collect(); + + self.tcx.emit_node_span_lint( + IMPL_TRAIT_OVERCAPTURES, + self.tcx.local_def_id_to_hir_id(opaque_def_id), + opaque_span, + ImplTraitOvercapturesLint { + self_ty: t, + num_captured: uncaptured_spans.len(), + uncaptured_spans, + suggestion, + }, + ); + } } + // Otherwise, if we are edition 2024, have `use<>` syntax, and // have no uncaptured args, then we should warn to the user that // it's redundant to capture all args explicitly. - else if new_capture_rules + if new_capture_rules && let Some((captured_args, capturing_span)) = opaque.bounds.iter().find_map(|bound| match *bound { hir::GenericBound::Use(a, s) => Some((a, s)), @@ -327,7 +421,7 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { if self .in_scope_parameters .iter() - .all(|def_id| explicitly_captured.contains(def_id)) + .all(|(def_id, _)| explicitly_captured.contains(def_id)) { self.tcx.emit_node_span_lint( IMPL_TRAIT_REDUNDANT_CAPTURES, @@ -396,7 +490,11 @@ fn extract_def_id_from_arg<'tcx>( ty::ReBound( _, ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, ..), .. }, - ) => def_id, + ) + | ty::ReLateParam(ty::LateParamRegion { + scope: _, + bound_region: ty::BoundRegionKind::BrNamed(def_id, ..), + }) => def_id, _ => unreachable!(), }, ty::GenericArgKind::Type(ty) => { @@ -413,3 +511,106 @@ fn extract_def_id_from_arg<'tcx>( } } } + +/// Computes the variances of regions that appear in the type, but considering +/// late-bound regions too, which don't have their variance computed usually. +/// +/// Like generalization, this is a unary operation implemented on top of the binary +/// relation infrastructure, mostly because it's much easier to have the relation +/// track the variance for you, rather than having to do it yourself. +struct FunctionalVariances<'tcx> { + tcx: TyCtxt<'tcx>, + variances: FxHashMap, + ambient_variance: ty::Variance, + generics: &'tcx ty::Generics, +} + +impl<'tcx> TypeRelation> for FunctionalVariances<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn relate_with_variance>>( + &mut self, + variance: rustc_type_ir::Variance, + _: ty::VarianceDiagInfo>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + let old_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + self.relate(a, b).unwrap(); + self.ambient_variance = old_variance; + Ok(a) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + structurally_relate_tys(self, a, b).unwrap(); + Ok(a) + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + _: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + let def_id = match *a { + ty::ReEarlyParam(ebr) => self.generics.region_param(ebr, self.tcx).def_id, + ty::ReBound( + _, + ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, ..), .. }, + ) + | ty::ReLateParam(ty::LateParamRegion { + scope: _, + bound_region: ty::BoundRegionKind::BrNamed(def_id, ..), + }) => def_id, + _ => { + return Ok(a); + } + }; + + if let Some(variance) = self.variances.get_mut(&def_id) { + *variance = unify(*variance, self.ambient_variance); + } else { + self.variances.insert(def_id, self.ambient_variance); + } + + Ok(a) + } + + fn consts( + &mut self, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + structurally_relate_consts(self, a, b).unwrap(); + Ok(a) + } + + fn binders( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate>, + { + self.relate(a.skip_binder(), b.skip_binder()).unwrap(); + Ok(a) + } +} + +/// What is the variance that satisfies the two variances? +fn unify(a: ty::Variance, b: ty::Variance) -> ty::Variance { + match (a, b) { + // Bivariance is lattice bottom. + (ty::Bivariant, other) | (other, ty::Bivariant) => other, + // Invariant is lattice top. + (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant, + // If type is required to be covariant and contravariant, then it's invariant. + (ty::Contravariant, ty::Covariant) | (ty::Covariant, ty::Contravariant) => ty::Invariant, + // Otherwise, co + co = co, contra + contra = contra. + (ty::Contravariant, ty::Contravariant) => ty::Contravariant, + (ty::Covariant, ty::Covariant) => ty::Covariant, + } +} diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 65571815019ea..94cc58e495681 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -10,15 +10,15 @@ use rustc_hir::{ }; use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; +use rustc_span::hygiene::{ExpnKind, MacroKind}; +use rustc_span::symbol::{Symbol, kw, sym}; use tracing::debug; use crate::lints::{ BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword, - NonGlobImportTypeIrInherent, QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, - TykindKind, UntranslatableDiag, + NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag, TyQualified, + TykindDiag, TykindKind, TypeIrInherentUsage, UntranslatableDiag, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -48,11 +48,10 @@ impl LateLintPass<'_> for DefaultHashTypes { Some(sym::HashSet) => "FxHashSet", _ => return, }; - cx.emit_span_lint( - DEFAULT_HASH_TYPES, - path.span, - DefaultHashTypesDiag { preferred, used: cx.tcx.item_name(def_id) }, - ); + cx.emit_span_lint(DEFAULT_HASH_TYPES, path.span, DefaultHashTypesDiag { + preferred, + used: cx.tcx.item_name(def_id), + }); } } @@ -88,7 +87,18 @@ declare_tool_lint! { report_in_external_macro: true } -declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]); +declare_tool_lint! { + /// The `untracked_query_information` lint detects use of methods which leak information not + /// tracked by the query system, such as whether a `Steal` value has already been stolen. In + /// order not to break incremental compilation, such methods must be used very carefully or not + /// at all. + pub rustc::UNTRACKED_QUERY_INFORMATION, + Allow, + "require explicit opt-in when accessing information not tracked by the query system", + report_in_external_macro: true +} + +declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]); impl LateLintPass<'_> for QueryStability { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { @@ -96,11 +106,14 @@ impl LateLintPass<'_> for QueryStability { if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, args) { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { - cx.emit_span_lint( - POTENTIAL_QUERY_INSTABILITY, - span, - QueryInstability { query: cx.tcx.item_name(def_id) }, - ); + cx.emit_span_lint(POTENTIAL_QUERY_INSTABILITY, span, QueryInstability { + query: cx.tcx.item_name(def_id), + }); + } + if cx.tcx.has_attr(def_id, sym::rustc_lint_untracked_query_information) { + cx.emit_span_lint(UNTRACKED_QUERY_INFORMATION, span, QueryUntracked { + method: cx.tcx.item_name(def_id), + }); } } } @@ -190,11 +203,9 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { match span { Some(span) => { - cx.emit_span_lint( - USAGE_OF_TY_TYKIND, - path.span, - TykindKind { suggestion: span }, - ); + cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { + suggestion: span, + }); } None => cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag), } @@ -202,11 +213,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, path) { - cx.emit_span_lint( - USAGE_OF_QUALIFIED_TY, - path.span, - TyQualified { ty, suggestion: path.span }, - ); + cx.emit_span_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified { + ty, + suggestion: path.span, + }); } } _ => {} @@ -277,13 +287,39 @@ declare_tool_lint! { report_in_external_macro: true } -declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT]); +declare_tool_lint! { + /// The `usage_of_type_ir_inherent` lint detects usage `rustc_type_ir::inherent`. + /// + /// This module should only be used within the trait solver. + pub rustc::USAGE_OF_TYPE_IR_INHERENT, + Allow, + "usage `rustc_type_ir::inherent` outside of trait system", + report_in_external_macro: true +} + +declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_INHERENT]); impl<'tcx> LateLintPass<'tcx> for TypeIr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return }; let is_mod_inherent = |def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id); + + // Path segments except for the final. + if let Some(seg) = + path.segments.iter().find(|seg| seg.res.opt_def_id().is_some_and(is_mod_inherent)) + { + cx.emit_span_lint(USAGE_OF_TYPE_IR_INHERENT, seg.ident.span, TypeIrInherentUsage); + } + // Final path resolutions, like `use rustc_type_ir::inherent` + else if path.res.iter().any(|res| res.opt_def_id().is_some_and(is_mod_inherent)) { + cx.emit_span_lint( + USAGE_OF_TYPE_IR_INHERENT, + path.segments.last().unwrap().ident.span, + TypeIrInherentUsage, + ); + } + let (lo, hi, snippet) = match path.segments { [.., penultimate, segment] if penultimate.res.opt_def_id().is_some_and(is_mod_inherent) => @@ -374,11 +410,9 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { if is_doc_keyword(keyword) { return; } - cx.emit_span_lint( - EXISTING_DOC_KEYWORD, - attr.span, - NonExistentDocKeyword { keyword }, - ); + cx.emit_span_lint(EXISTING_DOC_KEYWORD, attr.span, NonExistentDocKeyword { + keyword, + }); } } } @@ -581,11 +615,9 @@ impl LateLintPass<'_> for BadOptAccess { && let Some(lit) = item.lit() && let ast::LitKind::Str(val, _) = lit.kind { - cx.emit_span_lint( - BAD_OPT_ACCESS, - expr.span, - BadOptAccessDiag { msg: val.as_str() }, - ); + cx.emit_span_lint(BAD_OPT_ACCESS, expr.span, BadOptAccessDiag { + msg: val.as_str(), + }); } } } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index cb369d99a8450..de40139715076 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -18,14 +18,14 @@ use std::any::Any; use std::cell::Cell; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::{join, Lrc}; +use rustc_data_structures::sync::{Lrc, join}; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; -use rustc_hir::{intravisit as hir_visit, HirId}; +use rustc_hir::{HirId, intravisit as hir_visit}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::LintPass; use rustc_session::Session; +use rustc_session::lint::LintPass; use rustc_span::Span; use tracing::debug; diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 1368cc87e3e16..a12a97ee5730e 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -2,7 +2,7 @@ use rustc_errors::MultiSpan; use rustc_hir as hir; use rustc_middle::ty; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use crate::lints::{NonBindingLet, NonBindingLetSub}; use crate::{LateContext, LateLintPass, LintContext}; @@ -156,11 +156,10 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { }; if is_sync_lock { let span = MultiSpan::from_span(pat.span); - cx.emit_span_lint( - LET_UNDERSCORE_LOCK, - span, - NonBindingLet::SyncLock { sub, pat: pat.span }, - ); + cx.emit_span_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { + sub, + pat: pat.span, + }); // Only emit let_underscore_drop for top-level `_` patterns. } else if can_use_init.is_some() { cx.emit_span_lint(LET_UNDERSCORE_DROP, local.span, NonBindingLet::DropType { sub }); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 65289de980e13..007e86ae0d2b2 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -2,25 +2,25 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::{Features, GateIssue}; -use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; +use rustc_hir::intravisit::{self, Visitor}; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ - lint_level, reveal_actual_level, LevelAndSource, LintExpectation, LintLevelSource, - ShallowLintLevelMap, + LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, lint_level, + reveal_actual_level, }; use rustc_middle::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; +use rustc_session::Session; use rustc_session::lint::builtin::{ self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES, }; use rustc_session::lint::{Level, Lint, LintExpectationId, LintId}; -use rustc_session::Session; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Symbol, sym}; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; use {rustc_ast as ast, rustc_hir as hir}; @@ -255,11 +255,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { intravisit::walk_foreign_item(self, it); } - fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { - // We will call `add_id` when we walk - // the `StmtKind`. The outer statement itself doesn't - // define the lint levels. - intravisit::walk_stmt(self, e); + fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { + self.add_id(s.hir_id); + intravisit::walk_stmt(self, s); } fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c5a5c5b30afef..c74cb866f21fa 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -30,6 +30,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(extract_if)] @@ -55,6 +56,7 @@ mod expect; mod for_loops_over_fallibles; mod foreign_modules; pub mod hidden_unicode_codepoints; +mod if_let_rescope; mod impl_trait_overcaptures; mod internal; mod invalid_from_utf8; @@ -79,10 +81,12 @@ mod ptr_nulls; mod redundant_semicolon; mod reference_casting; mod shadowed_into_iter; +mod static_mut_refs; mod tail_expr_drop_order; mod traits; mod types; mod unit_bindings; +mod unqualified_local_imports; mod unused; use async_closures::AsyncClosureUsage; @@ -93,6 +97,7 @@ use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; +use if_let_rescope::IfLetRescope; use impl_trait_overcaptures::ImplTraitOvercaptures; use internal::*; use invalid_from_utf8::*; @@ -117,10 +122,12 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use shadowed_into_iter::ShadowedIntoIter; pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; +use static_mut_refs::*; use tail_expr_drop_order::TailExprDropOrder; use traits::*; use types::*; use unit_bindings::*; +use unqualified_local_imports::*; use unused::*; #[rustfmt::skip] @@ -128,7 +135,7 @@ pub use builtin::{MissingDoc, SoftLints}; pub use context::{ CheckLintNameResult, EarlyContext, FindLintError, LateContext, LintContext, LintStore, }; -pub use early::{check_ast_node, EarlyCheckNode}; +pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use passes::{EarlyLintPass, LateLintPass}; pub use rustc_session::lint::Level::{self, *}; @@ -242,6 +249,9 @@ late_lint_methods!( NonLocalDefinitions: NonLocalDefinitions::default(), ImplTraitOvercaptures: ImplTraitOvercaptures, TailExprDropOrder: TailExprDropOrder, + IfLetRescope: IfLetRescope::default(), + StaticMutRefs: StaticMutRefs, + UnqualifiedLocalImports: UnqualifiedLocalImports, ] ] ); @@ -575,6 +585,15 @@ fn register_builtins(store: &mut LintStore) { for more information", ); store.register_removed("writes_through_immutable_pointer", "converted into hard error"); + store.register_removed( + "const_eval_mutable_ptr_in_final_value", + "partially allowed now, otherwise turned into a hard error", + ); + store.register_removed( + "where_clauses_object_safety", + "converted into hard error, see PR #125380 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { @@ -602,23 +621,19 @@ fn register_internals(store: &mut LintStore) { // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and // these lints will trigger all of the time - change this once migration to diagnostic structs // and translation is completed - store.register_group( - false, - "rustc::internal", - None, - vec![ - LintId::of(DEFAULT_HASH_TYPES), - LintId::of(POTENTIAL_QUERY_INSTABILITY), - LintId::of(USAGE_OF_TY_TYKIND), - LintId::of(PASS_BY_VALUE), - LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), - LintId::of(USAGE_OF_QUALIFIED_TY), - LintId::of(NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT), - LintId::of(EXISTING_DOC_KEYWORD), - LintId::of(BAD_OPT_ACCESS), - LintId::of(SPAN_USE_EQ_CTXT), - ], - ); + store.register_group(false, "rustc::internal", None, vec![ + LintId::of(DEFAULT_HASH_TYPES), + LintId::of(POTENTIAL_QUERY_INSTABILITY), + LintId::of(UNTRACKED_QUERY_INFORMATION), + LintId::of(USAGE_OF_TY_TYKIND), + LintId::of(PASS_BY_VALUE), + LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), + LintId::of(USAGE_OF_QUALIFIED_TY), + LintId::of(NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT), + LintId::of(EXISTING_DOC_KEYWORD), + LintId::of(BAD_OPT_ACCESS), + LintId::of(SPAN_USE_EQ_CTXT), + ]); } #[cfg(test)] diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 2712e25668a48..0045cfcaa56ad 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -9,19 +9,19 @@ use rustc_errors::{ }; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir}; +use rustc_hir::{self as hir, MissingLifetimeKind}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; -use rustc_session::lint::AmbiguityErrorDiag; use rustc_session::Session; +use rustc_session::lint::AmbiguityErrorDiag; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds}; use crate::errors::{OverruledAttributeSub, RequestedLevel}; -use crate::{fluent_generated as fluent, LateContext}; +use crate::{LateContext, fluent_generated as fluent}; // array_into_iter.rs #[derive(LintDiagnostic)] @@ -267,16 +267,16 @@ pub(crate) struct MacroExprFragment2024 { pub suggestion: Span, } -pub(crate) struct BuiltinTypeAliasBounds<'a, 'hir> { +pub(crate) struct BuiltinTypeAliasBounds<'hir> { pub in_where_clause: bool, pub label: Span, pub enable_feat_help: bool, pub suggestions: Vec<(Span, String)>, pub preds: &'hir [hir::WherePredicate<'hir>], - pub ty: Option<&'a hir::Ty<'hir>>, + pub ty: Option<&'hir hir::Ty<'hir>>, } -impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_, '_> { +impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_> { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { diag.primary_message(if self.in_where_clause { fluent::lint_builtin_type_alias_bounds_where_clause @@ -363,8 +363,9 @@ pub(crate) enum BuiltinEllipsisInclusiveRangePatternsLint { pub(crate) struct BuiltinKeywordIdents { pub kw: Ident, pub next: Edition, - #[suggestion(code = "r#{kw}", applicability = "machine-applicable")] + #[suggestion(code = "{prefix}r#{kw}", applicability = "machine-applicable")] pub suggestion: Span, + pub prefix: &'static str, } #[derive(LintDiagnostic)] @@ -894,6 +895,13 @@ pub(crate) struct QueryInstability { pub query: Symbol, } +#[derive(LintDiagnostic)] +#[diag(lint_query_untracked)] +#[note] +pub(crate) struct QueryUntracked { + pub method: Symbol, +} + #[derive(LintDiagnostic)] #[diag(lint_span_use_eq_ctxt)] pub(crate) struct SpanUseEqCtxtDiag; @@ -918,6 +926,11 @@ pub(crate) struct TyQualified { pub suggestion: Span, } +#[derive(LintDiagnostic)] +#[diag(lint_type_ir_inherent_usage)] +#[note] +pub(crate) struct TypeIrInherentUsage; + #[derive(LintDiagnostic)] #[diag(lint_non_glob_import_type_ir_inherent)] pub(crate) struct NonGlobImportTypeIrInherent { @@ -1362,12 +1375,7 @@ pub(crate) enum NonLocalDefinitionsDiag { body_name: String, cargo_update: Option, const_anon: Option>, - move_to: Option<(Span, Vec)>, doctest: bool, - may_remove: Option<(Span, String)>, - has_trait: bool, - self_ty_str: String, - of_trait_str: Option, macro_to_change: Option<(String, &'static str)>, }, MacroRules { @@ -1388,22 +1396,13 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { body_name, cargo_update, const_anon, - move_to, doctest, - may_remove, - has_trait, - self_ty_str, - of_trait_str, macro_to_change, } => { diag.primary_message(fluent::lint_non_local_definitions_impl); diag.arg("depth", depth); diag.arg("body_kind_descr", body_kind_descr); diag.arg("body_name", body_name); - diag.arg("self_ty_str", self_ty_str); - if let Some(of_trait_str) = of_trait_str { - diag.arg("of_trait_str", of_trait_str); - } if let Some((macro_to_change, macro_kind)) = macro_to_change { diag.arg("macro_to_change", macro_to_change); @@ -1414,34 +1413,12 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { diag.subdiagnostic(cargo_update); } - if has_trait { - diag.note(fluent::lint_bounds); - diag.note(fluent::lint_with_trait); - } else { - diag.note(fluent::lint_without_trait); - } + diag.note(fluent::lint_non_local); - if let Some((move_help, may_move)) = move_to { - let mut ms = MultiSpan::from_span(move_help); - for sp in may_move { - ms.push_span_label(sp, fluent::lint_non_local_definitions_may_move); - } - diag.span_help(ms, fluent::lint_non_local_definitions_impl_move_help); - } if doctest { diag.help(fluent::lint_doctest); } - if let Some((span, part)) = may_remove { - diag.arg("may_remove_part", part); - diag.span_suggestion( - span, - fluent::lint_remove_help, - "", - Applicability::MaybeIncorrect, - ); - } - if let Some(const_anon) = const_anon { diag.note(fluent::lint_exception); if let Some(const_anon) = const_anon { @@ -2167,6 +2144,7 @@ pub(crate) struct UnexpectedCfgName { pub(crate) mod unexpected_cfg_name { use rustc_errors::DiagSymbolList; use rustc_macros::Subdiagnostic; + use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol}; #[derive(Subdiagnostic)] @@ -2247,7 +2225,7 @@ pub(crate) mod unexpected_cfg_name { #[derive(Subdiagnostic)] #[help_once(lint_unexpected_cfg_name_expected_names)] pub(crate) struct ExpectedNames { - pub possibilities: DiagSymbolList, + pub possibilities: DiagSymbolList, pub and_more: usize, } @@ -2611,14 +2589,56 @@ pub(crate) struct ElidedLifetimesInPaths { pub subdiag: ElidedLifetimeInPathSubdiag, } -#[derive(LintDiagnostic)] -#[diag(lint_elided_named_lifetime)] pub(crate) struct ElidedNamedLifetime { - #[label(lint_label_elided)] - pub elided: Span, + pub span: Span, + pub kind: MissingLifetimeKind, pub name: Symbol, - #[label(lint_label_named)] - pub named_declaration: Option, + pub declaration: Option, +} + +impl LintDiagnostic<'_, G> for ElidedNamedLifetime { + fn decorate_lint(self, diag: &mut rustc_errors::Diag<'_, G>) { + let Self { span, kind, name, declaration } = self; + diag.primary_message(fluent::lint_elided_named_lifetime); + diag.arg("name", name); + diag.span_label(span, fluent::lint_label_elided); + if let Some(declaration) = declaration { + diag.span_label(declaration, fluent::lint_label_named); + } + // FIXME(GrigorenkoPV): this `if` and `return` should be removed, + // but currently this lint's suggestions can conflict with those of `clippy::needless_lifetimes`: + // https://github.com/rust-lang/rust/pull/129840#issuecomment-2323349119 + // HACK: `'static` suggestions will never sonflict, emit only those for now. + if name != rustc_span::symbol::kw::StaticLifetime { + return; + } + match kind { + MissingLifetimeKind::Underscore => diag.span_suggestion_verbose( + span, + fluent::lint_suggestion, + format!("{name}"), + Applicability::MachineApplicable, + ), + MissingLifetimeKind::Ampersand => diag.span_suggestion_verbose( + span.shrink_to_hi(), + fluent::lint_suggestion, + format!("{name} "), + Applicability::MachineApplicable, + ), + MissingLifetimeKind::Comma => diag.span_suggestion_verbose( + span.shrink_to_hi(), + fluent::lint_suggestion, + format!("{name}, "), + Applicability::MachineApplicable, + ), + MissingLifetimeKind::Brackets => diag.span_suggestion_verbose( + span.shrink_to_hi(), + fluent::lint_suggestion, + format!("<{name}>"), + Applicability::MachineApplicable, + ), + }; + } } #[derive(LintDiagnostic)] @@ -2760,6 +2780,15 @@ pub(crate) struct ReservedPrefix { pub prefix: String, } +#[derive(LintDiagnostic)] +#[diag(lint_raw_prefix)] +pub(crate) struct RawPrefix { + #[label] + pub label: Span, + #[suggestion(code = " ", applicability = "machine-applicable")] + pub suggestion: Span, +} + #[derive(LintDiagnostic)] #[diag(lint_unused_builtin_attribute)] pub(crate) struct UnusedBuiltinAttribute { @@ -2996,3 +3025,39 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { pub(crate) struct OutOfScopeMacroCalls { pub path: String, } + +#[derive(LintDiagnostic)] +#[diag(lint_static_mut_refs_lint)] +pub(crate) struct RefOfMutStatic<'a> { + #[label] + pub span: Span, + #[subdiagnostic] + pub sugg: Option, + pub shared_label: &'a str, + #[note(lint_shared_note)] + pub shared_note: bool, + #[note(lint_mut_note)] + pub mut_note: bool, +} + +#[derive(Subdiagnostic)] +pub(crate) enum MutRefSugg { + #[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")] + Shared { + #[suggestion_part(code = "&raw const ")] + span: Span, + }, + #[multipart_suggestion( + lint_suggestion_mut, + style = "verbose", + applicability = "maybe-incorrect" + )] + Mut { + #[suggestion_part(code = "&raw mut ")] + span: Span, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unqualified_local_imports)] +pub(crate) struct UnqualifiedLocalImportsDiag {} diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs index e3b1967da09c7..23f4f7289067d 100644 --- a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs +++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs @@ -8,8 +8,8 @@ use rustc_span::edition::Edition; use rustc_span::sym; use tracing::debug; -use crate::lints::MacroExprFragment2024; use crate::EarlyLintPass; +use crate::lints::MacroExprFragment2024; declare_lint! { /// The `edition_2024_expr_fragment_specifier` lint detects the use of diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs index 3b27e45613690..776d51a672718 100644 --- a/compiler/rustc_lint/src/map_unit_fn.rs +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -60,39 +60,25 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn { let fn_ty = cx.tcx.fn_sig(id).skip_binder(); let ret_ty = fn_ty.output().skip_binder(); if is_unit_type(ret_ty) { - cx.emit_span_lint( - MAP_UNIT_FN, - span, - MappingToUnit { - function_label: cx - .tcx - .span_of_impl(*id) - .unwrap_or(default_span), - argument_label: args[0].span, - map_label: arg_ty.default_span(cx.tcx), - suggestion: path.ident.span, - replace: "for_each".to_string(), - }, - ) + cx.emit_span_lint(MAP_UNIT_FN, span, MappingToUnit { + function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span), + argument_label: args[0].span, + map_label: arg_ty.default_span(cx.tcx), + suggestion: path.ident.span, + replace: "for_each".to_string(), + }) } } else if let ty::Closure(id, subs) = arg_ty.kind() { let cl_ty = subs.as_closure().sig(); let ret_ty = cl_ty.output().skip_binder(); if is_unit_type(ret_ty) { - cx.emit_span_lint( - MAP_UNIT_FN, - span, - MappingToUnit { - function_label: cx - .tcx - .span_of_impl(*id) - .unwrap_or(default_span), - argument_label: args[0].span, - map_label: arg_ty.default_span(cx.tcx), - suggestion: path.ident.span, - replace: "for_each".to_string(), - }, - ) + cx.emit_span_lint(MAP_UNIT_FN, span, MappingToUnit { + function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span), + argument_label: args[0].span, + map_label: arg_ty.default_span(cx.tcx), + suggestion: path.ident.span, + replace: "for_each".to_string(), + }) } } } diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index dff72bb622f23..df22bf0972d71 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -1,8 +1,8 @@ use rustc_hir::{Expr, ExprKind}; use rustc_middle::ty; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use crate::lints::CStringPtr; use crate::{LateContext, LateLintPass, LintContext}; @@ -58,11 +58,10 @@ fn lint_cstring_as_ptr( if cx.tcx.is_diagnostic_item(sym::Result, def.did()) { if let ty::Adt(adt, _) = args.type_at(0).kind() { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { - cx.emit_span_lint( - TEMPORARY_CSTRING_AS_PTR, - as_ptr_span, - CStringPtr { as_ptr: as_ptr_span, unwrap: unwrap.span }, - ); + cx.emit_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, CStringPtr { + as_ptr: as_ptr_span, + unwrap: unwrap.span, + }); } } } diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 08d054b6a8bd3..9b495c19990c1 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -209,30 +209,22 @@ impl EarlyLintPass for NonAsciiIdents { if codepoints.is_empty() { continue; } - cx.emit_span_lint( - UNCOMMON_CODEPOINTS, - sp, - IdentifierUncommonCodepoints { - codepoints_len: codepoints.len(), - codepoints: codepoints.into_iter().map(|(c, _)| c).collect(), - identifier_type: id_ty_descr, - }, - ); + cx.emit_span_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints { + codepoints_len: codepoints.len(), + codepoints: codepoints.into_iter().map(|(c, _)| c).collect(), + identifier_type: id_ty_descr, + }); } let remaining = chars .extract_if(|(c, _)| !GeneralSecurityProfile::identifier_allowed(*c)) .collect::>(); if !remaining.is_empty() { - cx.emit_span_lint( - UNCOMMON_CODEPOINTS, - sp, - IdentifierUncommonCodepoints { - codepoints_len: remaining.len(), - codepoints: remaining.into_iter().map(|(c, _)| c).collect(), - identifier_type: "Restricted", - }, - ); + cx.emit_span_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints { + codepoints_len: remaining.len(), + codepoints: remaining.into_iter().map(|(c, _)| c).collect(), + identifier_type: "Restricted", + }); } } } @@ -261,16 +253,12 @@ impl EarlyLintPass for NonAsciiIdents { .entry(skeleton_sym) .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| { if !*existing_is_ascii || !is_ascii { - cx.emit_span_lint( - CONFUSABLE_IDENTS, - sp, - ConfusableIdentifierPair { - existing_sym: *existing_symbol, - sym: symbol, - label: *existing_span, - main_label: sp, - }, - ); + cx.emit_span_lint(CONFUSABLE_IDENTS, sp, ConfusableIdentifierPair { + existing_sym: *existing_symbol, + sym: symbol, + label: *existing_span, + main_label: sp, + }); } if *existing_is_ascii && !is_ascii { *existing_symbol = symbol; @@ -382,11 +370,10 @@ impl EarlyLintPass for NonAsciiIdents { let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); includes += &char_info; } - cx.emit_span_lint( - MIXED_SCRIPT_CONFUSABLES, - sp, - MixedScriptConfusables { set: script_set.to_string(), includes }, - ); + cx.emit_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, MixedScriptConfusables { + set: script_set.to_string(), + includes, + }); } } } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 10a517bfbcb76..51877e8a03495 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -9,11 +9,11 @@ use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; use rustc_span::symbol::kw; -use rustc_span::{hygiene, sym, InnerSpan, Span, Symbol}; +use rustc_span::{InnerSpan, Span, Symbol, hygiene, sym}; use rustc_trait_selection::infer::InferCtxtExt; use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused}; -use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext}; +use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; declare_lint! { /// The `non_fmt_panics` lint detects `panic!(..)` invocations where the first @@ -255,14 +255,10 @@ fn check_panic_str<'tcx>( .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end))) .collect(), }; - cx.emit_span_lint( - NON_FMT_PANICS, - arg_spans, - NonFmtPanicUnused { - count: n_arguments, - suggestion: is_arg_inside_call(arg.span, span).then_some(arg.span), - }, - ); + cx.emit_span_lint(NON_FMT_PANICS, arg_spans, NonFmtPanicUnused { + count: n_arguments, + suggestion: is_arg_inside_call(arg.span, span).then_some(arg.span), + }); } else { let brace_spans: Option> = snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| { diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 13a3c741fe39b..56f930ea7f62e 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -1,23 +1,15 @@ use rustc_errors::MultiSpan; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, QPath, TyKind}; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::{Obligation, ObligationCause}; -use rustc_middle::ty::{ - self, Binder, EarlyBinder, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, -}; +use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind}; +use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::kw; -use rustc_span::{sym, ExpnKind, MacroKind, Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::ambiguity::{ - compute_applicable_impls_for_diagnostics, CandidateSource, -}; -use rustc_trait_selection::infer::TyCtxtInferExt; +use rustc_span::{ExpnKind, MacroKind, Span, sym}; use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag}; -use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext}; +use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; declare_lint! { /// The `non_local_definitions` lint checks for `impl` blocks and `#[macro_export]` @@ -49,7 +41,7 @@ declare_lint! { /// All nested bodies (functions, enum discriminant, array length, consts) (expect for /// `const _: Ty = { ... }` in top-level module, which is still undecided) are checked. pub NON_LOCAL_DEFINITIONS, - Allow, + Warn, "checks for non-local definitions", report_in_external_macro } @@ -126,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { // > same expression-containing item. // // To achieve this we get try to get the paths of the _Trait_ and - // _Type_, and we look inside thoses paths to try a find in one + // _Type_, and we look inside those paths to try a find in one // of them a type whose parent is the same as the impl definition. // // If that's the case this means that this impl block declaration @@ -142,42 +134,28 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { None }; - // Part 1: Is the Self type local? - let self_ty_has_local_parent = - ty_has_local_parent(&impl_.self_ty.kind, cx, parent, parent_parent); - - if self_ty_has_local_parent { - return; + // 1. We collect all the `hir::Path` from the `Self` type and `Trait` ref + // of the `impl` definition + let mut collector = PathCollector { paths: Vec::new() }; + collector.visit_ty(&impl_.self_ty); + if let Some(of_trait) = &impl_.of_trait { + collector.visit_trait_ref(of_trait); } - // Part 2: Is the Trait local? - let of_trait_has_local_parent = impl_ - .of_trait - .map(|of_trait| path_has_local_parent(of_trait.path, cx, parent, parent_parent)) - .unwrap_or(false); - - if of_trait_has_local_parent { - return; - } - - // Part 3: Is the impl definition leaking outside it's defining scope? - // - // We always consider inherent impls to be leaking. - let impl_has_enough_non_local_candidates = cx - .tcx - .impl_trait_ref(def_id) - .map(|binder| { - impl_trait_ref_has_enough_non_local_candidates( - cx.tcx, - item.span, - def_id, - binder, - |did| did_has_local_parent(did, cx.tcx, parent, parent_parent), - ) - }) - .unwrap_or(false); + // 1.5. Remove any path that doesn't resolve to a `DefId` or if it resolve to a + // type-param (e.g. `T`). + collector.paths.retain( + |p| matches!(p.res, Res::Def(def_kind, _) if def_kind != DefKind::TyParam), + ); - if impl_has_enough_non_local_candidates { + // 2. We check if any of path reference a "local" parent and if that the case + // we bail out as asked by T-lang, even though this isn't correct from a + // type-system point of view, as inference exists and could still leak the impl. + if collector + .paths + .iter() + .any(|path| path_has_local_parent(path, cx, parent, parent_parent)) + { return; } @@ -199,76 +177,28 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. }) .then_some(span_for_const_anon_suggestion); - let may_remove = match &impl_.self_ty.kind { - TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) - if ty_has_local_parent(&mut_ty.ty.kind, cx, parent, parent_parent) => - { - let type_ = - if matches!(impl_.self_ty.kind, TyKind::Ptr(_)) { "*" } else { "&" }; - let part = format!("{}{}", type_, mut_ty.mutbl.prefix_str()); - Some((impl_.self_ty.span.shrink_to_lo().until(mut_ty.ty.span), part)) - } - _ => None, - }; - let impl_span = item.span.shrink_to_lo().to(impl_.self_ty.span); let mut ms = MultiSpan::from_span(impl_span); - let (self_ty_span, self_ty_str) = - self_ty_kind_for_diagnostic(&impl_.self_ty, cx.tcx); - - ms.push_span_label( - self_ty_span, - fluent::lint_non_local_definitions_self_ty_not_local, - ); - let of_trait_str = if let Some(of_trait) = &impl_.of_trait { + for path in &collector.paths { + // FIXME: While a translatable diagnostic message can have an argument + // we (currently) have no way to set different args per diag msg with + // `MultiSpan::push_span_label`. + #[allow(rustc::untranslatable_diagnostic)] ms.push_span_label( - path_span_without_args(&of_trait.path), - fluent::lint_non_local_definitions_of_trait_not_local, + path_span_without_args(path), + format!("`{}` is not local", path_name_to_string(path)), ); - Some(path_name_to_string(&of_trait.path)) - } else { - None - }; - - let (doctest, move_to) = if is_at_toplevel_doctest() { - (true, None) - } else { - let mut collector = PathCollector { paths: Vec::new() }; - collector.visit_ty(&impl_.self_ty); - if let Some(of_trait) = &impl_.of_trait { - collector.visit_trait_ref(of_trait); - } - collector.visit_generics(&impl_.generics); - - let mut may_move: Vec = collector - .paths - .into_iter() - .filter_map(|path| { - if let Some(did) = path.res.opt_def_id() - && did_has_local_parent(did, cx.tcx, parent, parent_parent) - { - Some(cx.tcx.def_span(did)) - } else { - None - } - }) - .collect(); - may_move.sort(); - may_move.dedup(); + } - let move_to = if may_move.is_empty() { - ms.push_span_label( - cx.tcx.def_span(parent), - fluent::lint_non_local_definitions_impl_move_help, - ); - None - } else { - Some((cx.tcx.def_span(parent), may_move)) - }; + let doctest = is_at_toplevel_doctest(); - (false, move_to) - }; + if !doctest { + ms.push_span_label( + cx.tcx.def_span(parent), + fluent::lint_non_local_definitions_impl_move_help, + ); + } let macro_to_change = if let ExpnKind::Macro(kind, name) = item.span.ctxt().outer_expn_data().kind { @@ -277,26 +207,17 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { None }; - cx.emit_span_lint( - NON_LOCAL_DEFINITIONS, - ms, - NonLocalDefinitionsDiag::Impl { - depth: self.body_depth, - body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent), - body_name: parent_opt_item_name - .map(|s| s.to_ident_string()) - .unwrap_or_else(|| "".to_string()), - cargo_update: cargo_update(), - const_anon, - self_ty_str, - of_trait_str, - move_to, - doctest, - may_remove, - has_trait: impl_.of_trait.is_some(), - macro_to_change, - }, - ) + cx.emit_span_lint(NON_LOCAL_DEFINITIONS, ms, NonLocalDefinitionsDiag::Impl { + depth: self.body_depth, + body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent), + body_name: parent_opt_item_name + .map(|s| s.to_ident_string()) + .unwrap_or_else(|| "".to_string()), + cargo_update: cargo_update(), + const_anon, + doctest, + macro_to_change, + }) } ItemKind::Macro(_macro, MacroKind::Bang) if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => @@ -320,90 +241,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { } } -// Detecting if the impl definition is leaking outside of its defining scope. -// -// Rule: for each impl, instantiate all local types with inference vars and -// then assemble candidates for that goal, if there are more than 1 (non-private -// impls), it does not leak. -// -// https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895 -fn impl_trait_ref_has_enough_non_local_candidates<'tcx>( - tcx: TyCtxt<'tcx>, - infer_span: Span, - trait_def_id: DefId, - binder: EarlyBinder<'tcx, TraitRef<'tcx>>, - mut did_has_local_parent: impl FnMut(DefId) -> bool, -) -> bool { - let infcx = tcx - .infer_ctxt() - // We use the new trait solver since the obligation we are trying to - // prove here may overflow and those are fatal in the old trait solver. - // Which is unacceptable for a lint. - // - // Thanksfully the part we use here are very similar to the - // new-trait-solver-as-coherence, which is in stabilization. - // - // https://github.com/rust-lang/rust/issues/123573 - .with_next_trait_solver(true) - .build(); - - let trait_ref = binder.instantiate(tcx, infcx.fresh_args_for_item(infer_span, trait_def_id)); - - let trait_ref = trait_ref.fold_with(&mut ReplaceLocalTypesWithInfer { - infcx: &infcx, - infer_span, - did_has_local_parent: &mut did_has_local_parent, - }); - - let poly_trait_obligation = Obligation::new( - tcx, - ObligationCause::dummy(), - ty::ParamEnv::empty(), - Binder::dummy(trait_ref), - ); - - let ambiguities = compute_applicable_impls_for_diagnostics(&infcx, &poly_trait_obligation); - - let mut it = ambiguities.iter().filter(|ambi| match ambi { - CandidateSource::DefId(did) => !did_has_local_parent(*did), - CandidateSource::ParamEnv(_) => unreachable!(), - }); - - let _ = it.next(); - it.next().is_some() -} - -/// Replace every local type by inference variable. -/// -/// ```text -/// as std::cmp::PartialEq>> -/// to -/// as std::cmp::PartialEq>> -/// ``` -struct ReplaceLocalTypesWithInfer<'a, 'tcx, F: FnMut(DefId) -> bool> { - infcx: &'a InferCtxt<'tcx>, - did_has_local_parent: F, - infer_span: Span, -} - -impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder> - for ReplaceLocalTypesWithInfer<'a, 'tcx, F> -{ - fn cx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if let Some(def) = t.ty_adt_def() - && (self.did_has_local_parent)(def.did()) - { - self.infcx.next_ty_var(self.infer_span) - } else { - t.super_fold_with(self) - } - } -} - /// Simple hir::Path collector struct PathCollector<'tcx> { paths: Vec>, @@ -416,42 +253,6 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> { } } -/// Given a `Ty` we check if the (outermost) type is local. -fn ty_has_local_parent( - ty_kind: &TyKind<'_>, - cx: &LateContext<'_>, - impl_parent: DefId, - impl_parent_parent: Option, -) -> bool { - match ty_kind { - TyKind::Path(QPath::Resolved(_, ty_path)) => { - path_has_local_parent(ty_path, cx, impl_parent, impl_parent_parent) - } - TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => path_has_local_parent( - principle_poly_trait_ref.0.trait_ref.path, - cx, - impl_parent, - impl_parent_parent, - ), - TyKind::TraitObject([], _, _) - | TyKind::InferDelegation(_, _) - | TyKind::Slice(_) - | TyKind::Array(_, _) - | TyKind::Ptr(_) - | TyKind::Ref(_, _) - | TyKind::BareFn(_) - | TyKind::Never - | TyKind::Tup(_) - | TyKind::Path(_) - | TyKind::Pat(..) - | TyKind::AnonAdt(_) - | TyKind::OpaqueDef(_, _, _) - | TyKind::Typeof(_) - | TyKind::Infer - | TyKind::Err(_) => false, - } -} - /// Given a path and a parent impl def id, this checks if the if parent resolution /// def id correspond to the def id of the parent impl definition. /// @@ -507,38 +308,3 @@ fn path_span_without_args(path: &Path<'_>) -> Span { fn path_name_to_string(path: &Path<'_>) -> String { path.segments.last().unwrap().ident.name.to_ident_string() } - -/// Compute the `Span` and visual representation for the `Self` we want to point at; -/// It follows part of the actual logic of non-local, and if possible return the least -/// amount possible for the span and representation. -fn self_ty_kind_for_diagnostic(ty: &rustc_hir::Ty<'_>, tcx: TyCtxt<'_>) -> (Span, String) { - match ty.kind { - TyKind::Path(QPath::Resolved(_, ty_path)) => ( - path_span_without_args(ty_path), - ty_path - .res - .opt_def_id() - .map(|did| tcx.opt_item_name(did)) - .flatten() - .as_ref() - .map(|s| Symbol::as_str(s)) - .unwrap_or("") - .to_string(), - ), - TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => { - let path = &principle_poly_trait_ref.0.trait_ref.path; - ( - path_span_without_args(path), - path.res - .opt_def_id() - .map(|did| tcx.opt_item_name(did)) - .flatten() - .as_ref() - .map(|s| Symbol::as_str(s)) - .unwrap_or("") - .to_string(), - ) - } - _ => (ty.span, rustc_hir_pretty::ty_to_string(&tcx, ty)), - } -} diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index d81052b5e2466..83a8ca4307e03 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -5,7 +5,7 @@ use rustc_middle::ty; use rustc_session::config::CrateType; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{Ident, sym}; use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; @@ -151,11 +151,11 @@ impl NonCamelCaseTypes { } else { NonCamelCaseTypeSub::Label { span: ident.span } }; - cx.emit_span_lint( - NON_CAMEL_CASE_TYPES, - ident.span, - NonCamelCaseType { sort, name, sub }, - ); + cx.emit_span_lint(NON_CAMEL_CASE_TYPES, ident.span, NonCamelCaseType { + sort, + name, + sub, + }); } } } @@ -332,6 +332,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { return; } + // Issue #45127: don't enforce `snake_case` for binary crates as binaries are not intended + // to be distributed and depended on like libraries. The lint is not suppressed for cdylib + // or staticlib because it's not clear what the desired lint behavior for those are. if cx.tcx.crate_types().iter().all(|&crate_type| crate_type == CrateType::Executable) { return; } @@ -486,11 +489,11 @@ impl NonUpperCaseGlobals { } else { NonUpperCaseGlobalSub::Label { span: ident.span } }; - cx.emit_span_lint( - NON_UPPER_CASE_GLOBALS, - ident.span, - NonUpperCaseGlobal { sort, name, sub }, - ); + cx.emit_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, NonUpperCaseGlobal { + sort, + name, + sub, + }); } } } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index d08a959f6547b..4890a93fa76a9 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -128,17 +128,13 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { ty::Adt(def, _) => Some(cx.tcx.def_span(def.did()).shrink_to_lo()), _ => None, }; - cx.emit_span_lint( - NOOP_METHOD_CALL, - span, - NoopMethodCallDiag { - method: call.ident.name, - orig_ty, - trait_, - label: span, - suggest_derive, - }, - ); + cx.emit_span_lint(NOOP_METHOD_CALL, span, NoopMethodCallDiag { + method: call.ident.name, + orig_ty, + trait_, + label: span, + suggest_derive, + }); } else { match name { // If `type_of(x) == T` and `x.borrow()` is used to get `&T`, diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index e0ba6a912f120..83652bbf54631 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -5,8 +5,8 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::{PrintTraitPredicateExt as _, TraitPredPrintModifiersAndPath}; use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; use rustc_trait_selection::traits::{self, ObligationCtxt}; use crate::{LateContext, LateLintPass, LintContext}; @@ -72,6 +72,18 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { return; }; + + // If this is an RPITIT from a trait method with no body, then skip. + // That's because although we may have an opaque type on the function, + // it won't have a hidden type, so proving predicates about it is + // not really meaningful. + if let hir::OpaqueTyOrigin::FnReturn(method_def_id) = opaque.origin + && let hir::Node::TraitItem(trait_item) = cx.tcx.hir_node_by_def_id(method_def_id) + && !trait_item.defaultness.has_value() + { + return; + } + 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, diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 23b200998a537..ec306f5f83472 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -31,11 +31,10 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { } } if let Some(t) = path_for_pass_by_value(cx, inner_ty) { - cx.emit_span_lint( - PASS_BY_VALUE, - ty.span, - PassByValueDiag { ty: t, suggestion: ty.span }, - ); + cx.emit_span_lint(PASS_BY_VALUE, ty.span, PassByValueDiag { + ty: t, + suggestion: ty.span, + }); } } _ => {} diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index bf16e3b7d150f..a1d436e0d3dbf 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -1,5 +1,5 @@ -use rustc_session::lint::builtin::HardwiredLints; use rustc_session::lint::LintPass; +use rustc_session::lint::builtin::HardwiredLints; use crate::context::{EarlyContext, LateContext}; @@ -14,6 +14,8 @@ macro_rules! late_lint_methods { fn check_mod(a: &'tcx rustc_hir::Mod<'tcx>, b: rustc_hir::HirId); fn check_foreign_item(a: &'tcx rustc_hir::ForeignItem<'tcx>); fn check_item(a: &'tcx rustc_hir::Item<'tcx>); + /// This is called *after* recursing into the item + /// (in contrast to `check_item`, which is checked before). fn check_item_post(a: &'tcx rustc_hir::Item<'tcx>); fn check_local(a: &'tcx rustc_hir::LetStmt<'tcx>); fn check_block(a: &'tcx rustc_hir::Block<'tcx>); @@ -135,6 +137,8 @@ macro_rules! early_lint_methods { fn check_crate(a: &rustc_ast::Crate); fn check_crate_post(a: &rustc_ast::Crate); fn check_item(a: &rustc_ast::Item); + /// This is called *after* recursing into the item + /// (in contrast to `check_item`, which is checked before). fn check_item_post(a: &rustc_ast::Item); fn check_local(a: &rustc_ast::Local); fn check_block(a: &rustc_ast::Block); diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index b43e4938b736c..036bfd06856f6 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -50,10 +50,9 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo return; } - cx.emit_span_lint( - REDUNDANT_SEMICOLONS, - span, - RedundantSemicolonsDiag { multiple, suggestion: span }, - ); + cx.emit_span_lint(REDUNDANT_SEMICOLONS, span, RedundantSemicolonsDiag { + multiple, + suggestion: span, + }); } } diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index bb9c7d85c2efc..a73904cd7769b 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -94,12 +94,9 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { fn is_ref_to_array(ty: Ty<'_>) -> bool { if let ty::Ref(_, pointee_ty, _) = *ty.kind() { pointee_ty.is_array() } else { false } } - fn is_boxed_slice(ty: Ty<'_>) -> bool { - ty.is_box() && ty.boxed_ty().is_slice() - } fn is_ref_to_boxed_slice(ty: Ty<'_>) -> bool { if let ty::Ref(_, pointee_ty, _) = *ty.kind() { - is_boxed_slice(pointee_ty) + pointee_ty.boxed_ty().is_some_and(Ty::is_slice) } else { false } @@ -119,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { .iter() .copied() .take_while(|ty| !is_ref_to_boxed_slice(*ty)) - .position(|ty| is_boxed_slice(ty)) + .position(|ty| ty.boxed_ty().is_some_and(Ty::is_slice)) { (BOXED_SLICE_INTO_ITER, "Box<[T]>", "2024", idx == 0) } else { @@ -149,10 +146,11 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { None }; - cx.emit_span_lint( - lint, - call.ident.span, - ShadowedIntoIterDiag { target, edition, suggestion: call.ident.span, sub }, - ); + cx.emit_span_lint(lint, call.ident.span, ShadowedIntoIterDiag { + target, + edition, + suggestion: call.ident.span, + sub, + }); } } diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs new file mode 100644 index 0000000000000..5d78b41944fef --- /dev/null +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -0,0 +1,156 @@ +use rustc_hir as hir; +use rustc_hir::{Expr, Stmt}; +use rustc_middle::ty::{Mutability, TyKind}; +use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::Span; +use rustc_span::edition::Edition; + +use crate::lints::{MutRefSugg, RefOfMutStatic}; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `static_mut_refs` lint checks for shared or mutable references + /// of mutable static inside `unsafe` blocks and `unsafe` functions. + /// + /// ### Example + /// + /// ```rust,edition2021 + /// fn main() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// unsafe { + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// } + /// + /// unsafe fn _foo() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// + /// fn foo<'a>(_x: &'a i32) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Shared or mutable references of mutable static are almost always a mistake and + /// can lead to undefined behavior and various other problems in your code. + /// + /// This lint is "warn" by default on editions up to 2021, in 2024 is "deny". + pub STATIC_MUT_REFS, + Warn, + "shared references or mutable references of mutable static is discouraged", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "", + explain_reason: false, + }; + @edition Edition2024 => Deny; +} + +declare_lint_pass!(StaticMutRefs => [STATIC_MUT_REFS]); + +impl<'tcx> LateLintPass<'tcx> for StaticMutRefs { + #[allow(rustc::usage_of_ty_tykind)] + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + let err_span = expr.span; + match expr.kind { + hir::ExprKind::AddrOf(borrow_kind, m, ex) + if matches!(borrow_kind, hir::BorrowKind::Ref) + && let Some(err_span) = path_is_static_mut(ex, err_span) => + { + emit_static_mut_refs( + cx, + err_span, + err_span.with_hi(ex.span.lo()), + m, + !expr.span.from_expansion(), + ); + } + hir::ExprKind::MethodCall(_, e, _, _) + if let Some(err_span) = path_is_static_mut(e, expr.span) + && let typeck = cx.typeck_results() + && let Some(method_def_id) = typeck.type_dependent_def_id(expr.hir_id) + && let inputs = + cx.tcx.fn_sig(method_def_id).skip_binder().inputs().skip_binder() + && let Some(receiver) = inputs.get(0) + && let TyKind::Ref(_, _, m) = receiver.kind() => + { + emit_static_mut_refs(cx, err_span, err_span.shrink_to_lo(), *m, false); + } + _ => {} + } + } + + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) { + if let hir::StmtKind::Let(loc) = stmt.kind + && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind + && let hir::ByRef::Yes(m) = ba.0 + && let Some(init) = loc.init + && let Some(err_span) = path_is_static_mut(init, init.span) + { + emit_static_mut_refs(cx, err_span, err_span.shrink_to_lo(), m, false); + } + } +} + +fn path_is_static_mut(mut expr: &hir::Expr<'_>, mut err_span: Span) -> Option { + if err_span.from_expansion() { + err_span = expr.span; + } + + while let hir::ExprKind::Field(e, _) = expr.kind { + expr = e; + } + + if let hir::ExprKind::Path(qpath) = expr.kind + && let hir::QPath::Resolved(_, path) = qpath + && let hir::def::Res::Def(def_kind, _) = path.res + && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } = + def_kind + { + return Some(err_span); + } + None +} + +fn emit_static_mut_refs( + cx: &LateContext<'_>, + span: Span, + sugg_span: Span, + mutable: Mutability, + suggest_addr_of: bool, +) { + let (shared_label, shared_note, mut_note, sugg) = match mutable { + Mutability::Mut => { + let sugg = + if suggest_addr_of { Some(MutRefSugg::Mut { span: sugg_span }) } else { None }; + ("mutable ", false, true, sugg) + } + Mutability::Not => { + let sugg = + if suggest_addr_of { Some(MutRefSugg::Shared { span: sugg_span }) } else { None }; + ("shared ", true, false, sugg) + } + }; + + cx.emit_span_lint(STATIC_MUT_REFS, span, RefOfMutStatic { + span, + sugg, + shared_label, + shared_note, + mut_note, + }); +} diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs index f9ecc8c9806f4..44a36142ed480 100644 --- a/compiler/rustc_lint/src/tail_expr_drop_order.rs +++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs @@ -8,8 +8,8 @@ use rustc_macros::LintDiagnostic; use rustc_middle::ty; use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::edition::Edition; use rustc_span::Span; +use rustc_span::edition::Edition; use crate::{LateContext, LateLintPass}; @@ -143,18 +143,18 @@ impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder { } } -struct LintVisitor<'tcx, 'a> { +struct LintVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, // We only record locals that have significant drops locals: Vec, } -struct LocalCollector<'tcx, 'a> { +struct LocalCollector<'a, 'tcx> { cx: &'a LateContext<'tcx>, locals: &'a mut Vec, } -impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for LocalCollector<'a, 'tcx> { type Result = (); fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind { @@ -171,7 +171,7 @@ impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> { } } -impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for LintVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'tcx>) { let mut locals = <_>::default(); swap(&mut locals, &mut self.locals); @@ -183,7 +183,7 @@ impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> { } } -impl<'tcx, 'a> LintVisitor<'tcx, 'a> { +impl<'a, 'tcx> LintVisitor<'a, 'tcx> { fn check_block_inner(&mut self, block: &Block<'tcx>) { if !block.span.at_least_rust_2024() { // We only lint for Edition 2024 onwards @@ -205,13 +205,13 @@ impl<'tcx, 'a> LintVisitor<'tcx, 'a> { } } -struct LintTailExpr<'tcx, 'a> { +struct LintTailExpr<'a, 'tcx> { cx: &'a LateContext<'tcx>, is_root_tail_expr: bool, locals: &'a [Span], } -impl<'tcx, 'a> LintTailExpr<'tcx, 'a> { +impl<'a, 'tcx> LintTailExpr<'a, 'tcx> { fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool { loop { match expr.kind { @@ -239,7 +239,7 @@ impl<'tcx, 'a> LintTailExpr<'tcx, 'a> { } } -impl<'tcx, 'a> Visitor<'tcx> for LintTailExpr<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for LintTailExpr<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { if self.is_root_tail_expr { self.is_root_tail_expr = false; diff --git a/compiler/rustc_lint/src/tests.rs b/compiler/rustc_lint/src/tests.rs index 988d1645fba22..7fbf381a8d321 100644 --- a/compiler/rustc_lint/src/tests.rs +++ b/compiler/rustc_lint/src/tests.rs @@ -1,4 +1,4 @@ -use rustc_span::{create_default_session_globals_then, Symbol}; +use rustc_span::{Symbol, create_default_session_globals_then}; use crate::levels::parse_lint_and_tool_name; diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index a0fe4b5af7402..c0a01b0065ef9 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -101,11 +101,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { continue; } let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; - cx.emit_span_lint( - DROP_BOUNDS, - span, - DropTraitConstraintsDiag { predicate, tcx: cx.tcx, def_id }, - ); + cx.emit_span_lint(DROP_BOUNDS, span, DropTraitConstraintsDiag { + predicate, + tcx: cx.tcx, + def_id, + }); } } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f2f7c0eaa4df8..15fe18adbfb10 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -3,31 +3,32 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; -use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; +use rustc_hir::{Expr, ExprKind}; use rustc_middle::bug; -use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; +use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton}; use rustc_middle::ty::{ self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; -use rustc_span::{source_map, Span, Symbol}; -use rustc_target::abi::{Abi, Integer, Size, TagEncoding, Variants, WrappingRange}; +use rustc_span::{Span, Symbol, source_map}; +use rustc_target::abi::{Abi, TagEncoding, Variants, WrappingRange}; use rustc_target::spec::abi::Abi as SpecAbi; use tracing::debug; -use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_hir as hir}; use crate::lints::{ AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion, AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons, - InvalidNanComparisonsSuggestion, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, - OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, - OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, - UseInclusiveRange, VariantSizeDifferencesDiag, + InvalidNanComparisonsSuggestion, UnusedComparisons, VariantSizeDifferencesDiag, }; -use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext}; +use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; + +mod literal; + +use literal::{int_ty_range, lint_literal, uint_ty_range}; declare_lint! { /// The `unused_comparisons` lint detects comparisons made useless by @@ -185,403 +186,6 @@ impl TypeLimits { } } -/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint (`expr..MAX+1`). -/// Returns `true` iff the lint was emitted. -fn lint_overflowing_range_endpoint<'tcx>( - cx: &LateContext<'tcx>, - lit: &hir::Lit, - lit_val: u128, - max: u128, - expr: &'tcx hir::Expr<'tcx>, - ty: &str, -) -> bool { - // Look past casts to support cases like `0..256 as u8` - let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.parent_hir_node(expr.hir_id) - && let ExprKind::Cast(_, _) = par_expr.kind - { - (par_expr, expr.span) - } else { - (expr, expr.span) - }; - - // We only want to handle exclusive (`..`) ranges, - // which are represented as `ExprKind::Struct`. - let Node::ExprField(field) = cx.tcx.parent_hir_node(expr.hir_id) else { return false }; - let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false }; - if !is_range_literal(struct_expr) { - return false; - }; - let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false }; - - // We can suggest using an inclusive range - // (`..=`) instead only if it is the `end` that is - // overflowing and only by 1. - if !(end.expr.hir_id == expr.hir_id && lit_val - 1 == max) { - return false; - }; - - use rustc_ast::{LitIntType, LitKind}; - let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsuffixed) => "", - _ => bug!(), - }; - - let sub_sugg = if expr.span.lo() == lit_span.lo() { - let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false }; - UseInclusiveRange::WithoutParen { - sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()), - start, - literal: lit_val - 1, - suffix, - } - } else { - UseInclusiveRange::WithParen { - eq_sugg: expr.span.shrink_to_lo(), - lit_sugg: lit_span, - literal: lit_val - 1, - suffix, - } - }; - - cx.emit_span_lint( - OVERFLOWING_LITERALS, - struct_expr.span, - RangeEndpointOutOfRange { ty, sub: sub_sugg }, - ); - - // We've just emitted a lint, special cased for `(...)..MAX+1` ranges, - // return `true` so the callers don't also emit a lint - true -} - -// For `isize` & `usize`, be conservative with the warnings, so that the -// warnings are consistent between 32- and 64-bit platforms. -fn int_ty_range(int_ty: ty::IntTy) -> (i128, i128) { - match int_ty { - ty::IntTy::Isize => (i64::MIN.into(), i64::MAX.into()), - ty::IntTy::I8 => (i8::MIN.into(), i8::MAX.into()), - ty::IntTy::I16 => (i16::MIN.into(), i16::MAX.into()), - ty::IntTy::I32 => (i32::MIN.into(), i32::MAX.into()), - ty::IntTy::I64 => (i64::MIN.into(), i64::MAX.into()), - ty::IntTy::I128 => (i128::MIN, i128::MAX), - } -} - -fn uint_ty_range(uint_ty: ty::UintTy) -> (u128, u128) { - let max = match uint_ty { - ty::UintTy::Usize => u64::MAX.into(), - ty::UintTy::U8 => u8::MAX.into(), - ty::UintTy::U16 => u16::MAX.into(), - ty::UintTy::U32 => u32::MAX.into(), - ty::UintTy::U64 => u64::MAX.into(), - ty::UintTy::U128 => u128::MAX, - }; - (0, max) -} - -fn get_bin_hex_repr(cx: &LateContext<'_>, lit: &hir::Lit) -> Option { - let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?; - let firstch = src.chars().next()?; - - if firstch == '0' { - match src.chars().nth(1) { - Some('x' | 'b') => return Some(src), - _ => return None, - } - } - - None -} - -fn report_bin_hex_error( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - ty: attr::IntType, - size: Size, - repr_str: String, - val: u128, - negative: bool, -) { - let (t, actually) = match ty { - attr::IntType::SignedInt(t) => { - let actually = if negative { -(size.sign_extend(val)) } else { size.sign_extend(val) }; - (t.name_str(), actually.to_string()) - } - attr::IntType::UnsignedInt(t) => { - let actually = size.truncate(val); - (t.name_str(), actually.to_string()) - } - }; - let sign = - if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive }; - let sub = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative).map( - |suggestion_ty| { - if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { - let (sans_suffix, _) = repr_str.split_at(pos); - OverflowingBinHexSub::Suggestion { span: expr.span, suggestion_ty, sans_suffix } - } else { - OverflowingBinHexSub::Help { suggestion_ty } - } - }, - ); - let sign_bit_sub = (!negative) - .then(|| { - let ty::Int(int_ty) = cx.typeck_results().node_type(expr.hir_id).kind() else { - return None; - }; - - let Some(bit_width) = int_ty.bit_width() else { - return None; // isize case - }; - - // Skip if sign bit is not set - if (val & (1 << (bit_width - 1))) == 0 { - return None; - } - - let lit_no_suffix = - if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { - repr_str.split_at(pos).0 - } else { - &repr_str - }; - - Some(OverflowingBinHexSignBitSub { - span: expr.span, - lit_no_suffix, - negative_val: actually.clone(), - int_ty: int_ty.name_str(), - uint_ty: int_ty.to_unsigned().name_str(), - }) - }) - .flatten(); - - cx.emit_span_lint( - OVERFLOWING_LITERALS, - expr.span, - OverflowingBinHex { - ty: t, - lit: repr_str.clone(), - dec: val, - actually, - sign, - sub, - sign_bit_sub, - }, - ) -} - -// This function finds the next fitting type and generates a suggestion string. -// It searches for fitting types in the following way (`X < Y`): -// - `iX`: if literal fits in `uX` => `uX`, else => `iY` -// - `-iX` => `iY` -// - `uX` => `uY` -// -// No suggestion for: `isize`, `usize`. -fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static str> { - use ty::IntTy::*; - use ty::UintTy::*; - macro_rules! find_fit { - ($ty:expr, $val:expr, $negative:expr, - $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => { - { - let _neg = if negative { 1 } else { 0 }; - match $ty { - $($type => { - $(if !negative && val <= uint_ty_range($utypes).1 { - return Some($utypes.name_str()) - })* - $(if val <= int_ty_range($itypes).1 as u128 + _neg { - return Some($itypes.name_str()) - })* - None - },)+ - _ => None - } - } - } - } - match t.kind() { - ty::Int(i) => find_fit!(i, val, negative, - I8 => [U8] => [I16, I32, I64, I128], - I16 => [U16] => [I32, I64, I128], - I32 => [U32] => [I64, I128], - I64 => [U64] => [I128], - I128 => [U128] => []), - ty::Uint(u) => find_fit!(u, val, negative, - U8 => [U8, U16, U32, U64, U128] => [], - U16 => [U16, U32, U64, U128] => [], - U32 => [U32, U64, U128] => [], - U64 => [U64, U128] => [], - U128 => [U128] => []), - _ => None, - } -} - -fn lint_int_literal<'tcx>( - cx: &LateContext<'tcx>, - type_limits: &TypeLimits, - e: &'tcx hir::Expr<'tcx>, - lit: &hir::Lit, - t: ty::IntTy, - v: u128, -) { - let int_type = t.normalize(cx.sess().target.pointer_width); - let (min, max) = int_ty_range(int_type); - let max = max as u128; - let negative = type_limits.negated_expr_id == Some(e.hir_id); - - // Detect literal value out of range [min, max] inclusive - // avoiding use of -min to prevent overflow/panic - if (negative && v > max + 1) || (!negative && v > max) { - if let Some(repr_str) = get_bin_hex_repr(cx, lit) { - report_bin_hex_error( - cx, - e, - attr::IntType::SignedInt(ty::ast_int_ty(t)), - Integer::from_int_ty(cx, t).size(), - repr_str, - v, - negative, - ); - return; - } - - if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) { - // The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`. - return; - } - - let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span }; - let lit = cx - .sess() - .source_map() - .span_to_snippet(span) - .unwrap_or_else(|_| if negative { format!("-{v}") } else { v.to_string() }); - let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) - .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); - - cx.emit_span_lint( - OVERFLOWING_LITERALS, - span, - OverflowingInt { ty: t.name_str(), lit, min, max, help }, - ); - } -} - -fn lint_uint_literal<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx hir::Expr<'tcx>, - lit: &hir::Lit, - t: ty::UintTy, -) { - let uint_type = t.normalize(cx.sess().target.pointer_width); - let (min, max) = uint_ty_range(uint_type); - let lit_val: u128 = match lit.node { - // _v is u8, within range by definition - ast::LitKind::Byte(_v) => return, - ast::LitKind::Int(v, _) => v.get(), - _ => bug!(), - }; - - if lit_val < min || lit_val > max { - if let Node::Expr(par_e) = cx.tcx.parent_hir_node(e.hir_id) { - match par_e.kind { - hir::ExprKind::Cast(..) => { - if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { - cx.emit_span_lint( - OVERFLOWING_LITERALS, - par_e.span, - OnlyCastu8ToChar { span: par_e.span, literal: lit_val }, - ); - return; - } - } - _ => {} - } - } - if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) { - // The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`. - return; - } - if let Some(repr_str) = get_bin_hex_repr(cx, lit) { - report_bin_hex_error( - cx, - e, - attr::IntType::UnsignedInt(ty::ast_uint_ty(t)), - Integer::from_uint_ty(cx, t).size(), - repr_str, - lit_val, - false, - ); - return; - } - cx.emit_span_lint( - OVERFLOWING_LITERALS, - e.span, - OverflowingUInt { - ty: t.name_str(), - lit: cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .unwrap_or_else(|_| lit_val.to_string()), - min, - max, - }, - ); - } -} - -fn lint_literal<'tcx>( - cx: &LateContext<'tcx>, - type_limits: &TypeLimits, - e: &'tcx hir::Expr<'tcx>, - lit: &hir::Lit, -) { - match *cx.typeck_results().node_type(e.hir_id).kind() { - ty::Int(t) => { - match lit.node { - ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { - lint_int_literal(cx, type_limits, e, lit, t, v.get()) - } - _ => bug!(), - }; - } - ty::Uint(t) => lint_uint_literal(cx, e, lit, t), - ty::Float(t) => { - let (is_infinite, sym) = match lit.node { - ast::LitKind::Float(v, _) => match t { - // FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI - // issues resolved). - ty::FloatTy::F16 => (Ok(false), v), - ty::FloatTy::F32 => (v.as_str().parse().map(f32::is_infinite), v), - ty::FloatTy::F64 => (v.as_str().parse().map(f64::is_infinite), v), - ty::FloatTy::F128 => (Ok(false), v), - }, - _ => bug!(), - }; - if is_infinite == Ok(true) { - cx.emit_span_lint( - OVERFLOWING_LITERALS, - e.span, - OverflowingLiteral { - ty: t.name_str(), - lit: cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .unwrap_or_else(|_| sym.to_string()), - }, - ); - } - } - _ => {} - } -} - fn lint_nan<'tcx>( cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>, @@ -830,16 +434,13 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { } fn rev_binop(binop: hir::BinOp) -> hir::BinOp { - source_map::respan( - binop.span, - match binop.node { - hir::BinOpKind::Lt => hir::BinOpKind::Gt, - hir::BinOpKind::Le => hir::BinOpKind::Ge, - hir::BinOpKind::Gt => hir::BinOpKind::Lt, - hir::BinOpKind::Ge => hir::BinOpKind::Le, - _ => return binop, - }, - ) + source_map::respan(binop.span, match binop.node { + hir::BinOpKind::Lt => hir::BinOpKind::Gt, + hir::BinOpKind::Le => hir::BinOpKind::Ge, + hir::BinOpKind::Gt => hir::BinOpKind::Lt, + hir::BinOpKind::Ge => hir::BinOpKind::Le, + _ => return binop, + }) } fn check_limits( @@ -1304,8 +905,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match *ty.kind() { ty::Adt(def, args) => { - if def.is_box() && matches!(self.mode, CItemKind::Definition) { - if ty.boxed_ty().is_sized(tcx, self.cx.param_env) { + if let Some(boxed) = ty.boxed_ty() + && matches!(self.mode, CItemKind::Definition) + { + if boxed.is_sized(tcx, self.cx.param_env) { return FfiSafe; } else { return FfiUnsafe { @@ -1574,11 +1177,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } else { None }; - self.cx.emit_span_lint( - lint, - sp, - ImproperCTypes { ty, desc, label: sp, help, note, span_note }, - ); + self.cx.emit_span_lint(lint, sp, ImproperCTypes { + ty, + desc, + label: sp, + help, + note, + span_note, + }); } fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { @@ -1700,7 +1306,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn is_internal_abi(&self, abi: SpecAbi) -> bool { - matches!(abi, SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustIntrinsic) + matches!( + abi, + SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustCold | SpecAbi::RustIntrinsic + ) } /// Find any fn-ptr types with external ABIs in `ty`. @@ -1711,13 +1320,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { hir_ty: &hir::Ty<'tcx>, ty: Ty<'tcx>, ) -> Vec<(Ty<'tcx>, Span)> { - struct FnPtrFinder<'parent, 'a, 'tcx> { - visitor: &'parent ImproperCTypesVisitor<'a, 'tcx>, + struct FnPtrFinder<'a, 'b, 'tcx> { + visitor: &'a ImproperCTypesVisitor<'b, 'tcx>, spans: Vec, tys: Vec>, } - impl<'parent, 'a, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'parent, 'a, 'tcx> { + impl<'a, 'b, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'a, 'b, 'tcx> { fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) { debug!(?ty); if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind @@ -1730,7 +1339,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor> for FnPtrFinder<'vis, 'a, 'tcx> { + impl<'a, 'b, 'tcx> ty::visit::TypeVisitor> for FnPtrFinder<'a, 'b, 'tcx> { type Result = ControlFlow>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { @@ -1744,7 +1353,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() }; + let mut visitor = FnPtrFinder { visitor: self, spans: Vec::new(), tys: Vec::new() }; ty.visit_with(&mut visitor); hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty); @@ -2043,11 +1652,11 @@ impl InvalidAtomicOrdering { } fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) { - let Some((method, args)) = Self::inherent_atomic_method_call( - cx, - expr, - &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak], - ) else { + let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[ + sym::fetch_update, + sym::compare_exchange, + sym::compare_exchange_weak, + ]) else { return; }; diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs new file mode 100644 index 0000000000000..d1e850990dc3e --- /dev/null +++ b/compiler/rustc_lint/src/types/literal.rs @@ -0,0 +1,374 @@ +use hir::{ExprKind, Node, is_range_literal}; +use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::{bug, ty}; +use rustc_target::abi::{Integer, Size}; +use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; + +use crate::LateContext; +use crate::context::LintContext; +use crate::lints::{ + OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub, + OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, + RangeEndpointOutOfRange, UseInclusiveRange, +}; +use crate::types::{OVERFLOWING_LITERALS, TypeLimits}; + +/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint (`expr..MAX+1`). +/// Returns `true` iff the lint was emitted. +fn lint_overflowing_range_endpoint<'tcx>( + cx: &LateContext<'tcx>, + lit: &hir::Lit, + lit_val: u128, + max: u128, + expr: &'tcx hir::Expr<'tcx>, + ty: &str, +) -> bool { + // Look past casts to support cases like `0..256 as u8` + let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.parent_hir_node(expr.hir_id) + && let ExprKind::Cast(_, _) = par_expr.kind + { + (par_expr, expr.span) + } else { + (expr, expr.span) + }; + + // We only want to handle exclusive (`..`) ranges, + // which are represented as `ExprKind::Struct`. + let Node::ExprField(field) = cx.tcx.parent_hir_node(expr.hir_id) else { return false }; + let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false }; + if !is_range_literal(struct_expr) { + return false; + }; + let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false }; + + // We can suggest using an inclusive range + // (`..=`) instead only if it is the `end` that is + // overflowing and only by 1. + if !(end.expr.hir_id == expr.hir_id && lit_val - 1 == max) { + return false; + }; + + use rustc_ast::{LitIntType, LitKind}; + let suffix = match lit.node { + LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsuffixed) => "", + _ => bug!(), + }; + + let sub_sugg = if expr.span.lo() == lit_span.lo() { + let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false }; + UseInclusiveRange::WithoutParen { + sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()), + start, + literal: lit_val - 1, + suffix, + } + } else { + UseInclusiveRange::WithParen { + eq_sugg: expr.span.shrink_to_lo(), + lit_sugg: lit_span, + literal: lit_val - 1, + suffix, + } + }; + + cx.emit_span_lint(OVERFLOWING_LITERALS, struct_expr.span, RangeEndpointOutOfRange { + ty, + sub: sub_sugg, + }); + + // We've just emitted a lint, special cased for `(...)..MAX+1` ranges, + // return `true` so the callers don't also emit a lint + true +} + +// For `isize` & `usize`, be conservative with the warnings, so that the +// warnings are consistent between 32- and 64-bit platforms. +pub(crate) fn int_ty_range(int_ty: ty::IntTy) -> (i128, i128) { + match int_ty { + ty::IntTy::Isize => (i64::MIN.into(), i64::MAX.into()), + ty::IntTy::I8 => (i8::MIN.into(), i8::MAX.into()), + ty::IntTy::I16 => (i16::MIN.into(), i16::MAX.into()), + ty::IntTy::I32 => (i32::MIN.into(), i32::MAX.into()), + ty::IntTy::I64 => (i64::MIN.into(), i64::MAX.into()), + ty::IntTy::I128 => (i128::MIN, i128::MAX), + } +} + +pub(crate) fn uint_ty_range(uint_ty: ty::UintTy) -> (u128, u128) { + let max = match uint_ty { + ty::UintTy::Usize => u64::MAX.into(), + ty::UintTy::U8 => u8::MAX.into(), + ty::UintTy::U16 => u16::MAX.into(), + ty::UintTy::U32 => u32::MAX.into(), + ty::UintTy::U64 => u64::MAX.into(), + ty::UintTy::U128 => u128::MAX, + }; + (0, max) +} + +fn get_bin_hex_repr(cx: &LateContext<'_>, lit: &hir::Lit) -> Option { + let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?; + let firstch = src.chars().next()?; + + if firstch == '0' { + match src.chars().nth(1) { + Some('x' | 'b') => return Some(src), + _ => return None, + } + } + + None +} + +fn report_bin_hex_error( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + ty: attr::IntType, + size: Size, + repr_str: String, + val: u128, + negative: bool, +) { + let (t, actually) = match ty { + attr::IntType::SignedInt(t) => { + let actually = if negative { -(size.sign_extend(val)) } else { size.sign_extend(val) }; + (t.name_str(), actually.to_string()) + } + attr::IntType::UnsignedInt(t) => { + let actually = size.truncate(val); + (t.name_str(), actually.to_string()) + } + }; + let sign = + if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive }; + let sub = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative).map( + |suggestion_ty| { + if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { + let (sans_suffix, _) = repr_str.split_at(pos); + OverflowingBinHexSub::Suggestion { span: expr.span, suggestion_ty, sans_suffix } + } else { + OverflowingBinHexSub::Help { suggestion_ty } + } + }, + ); + let sign_bit_sub = (!negative) + .then(|| { + let ty::Int(int_ty) = cx.typeck_results().node_type(expr.hir_id).kind() else { + return None; + }; + + let Some(bit_width) = int_ty.bit_width() else { + return None; // isize case + }; + + // Skip if sign bit is not set + if (val & (1 << (bit_width - 1))) == 0 { + return None; + } + + let lit_no_suffix = + if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { + repr_str.split_at(pos).0 + } else { + &repr_str + }; + + Some(OverflowingBinHexSignBitSub { + span: expr.span, + lit_no_suffix, + negative_val: actually.clone(), + int_ty: int_ty.name_str(), + uint_ty: int_ty.to_unsigned().name_str(), + }) + }) + .flatten(); + + cx.emit_span_lint(OVERFLOWING_LITERALS, expr.span, OverflowingBinHex { + ty: t, + lit: repr_str.clone(), + dec: val, + actually, + sign, + sub, + sign_bit_sub, + }) +} + +// Find the "next" fitting integer and return a suggestion string +// +// No suggestion is offered for `{i,u}size`. Otherwise, we try to suggest an equal-sized type. +fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static str> { + match t.kind() { + ty::Uint(ty::UintTy::Usize) | ty::Int(ty::IntTy::Isize) => None, + ty::Uint(_) => Some(Integer::fit_unsigned(val).uint_ty_str()), + ty::Int(_) if negative => Some(Integer::fit_signed(-(val as i128)).int_ty_str()), + ty::Int(int) => { + let signed = Integer::fit_signed(val as i128); + let unsigned = Integer::fit_unsigned(val); + Some(if Some(unsigned.size().bits()) == int.bit_width() { + unsigned.uint_ty_str() + } else { + signed.int_ty_str() + }) + } + _ => None, + } +} + +fn lint_int_literal<'tcx>( + cx: &LateContext<'tcx>, + type_limits: &TypeLimits, + e: &'tcx hir::Expr<'tcx>, + lit: &hir::Lit, + t: ty::IntTy, + v: u128, +) { + let int_type = t.normalize(cx.sess().target.pointer_width); + let (min, max) = int_ty_range(int_type); + let max = max as u128; + let negative = type_limits.negated_expr_id == Some(e.hir_id); + + // Detect literal value out of range [min, max] inclusive + // avoiding use of -min to prevent overflow/panic + if (negative && v > max + 1) || (!negative && v > max) { + if let Some(repr_str) = get_bin_hex_repr(cx, lit) { + report_bin_hex_error( + cx, + e, + attr::IntType::SignedInt(ty::ast_int_ty(t)), + Integer::from_int_ty(cx, t).size(), + repr_str, + v, + negative, + ); + return; + } + + if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) { + // The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`. + return; + } + + let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span }; + let lit = cx + .sess() + .source_map() + .span_to_snippet(span) + .unwrap_or_else(|_| if negative { format!("-{v}") } else { v.to_string() }); + let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) + .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); + + cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingInt { + ty: t.name_str(), + lit, + min, + max, + help, + }); + } +} + +fn lint_uint_literal<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx hir::Expr<'tcx>, + lit: &hir::Lit, + t: ty::UintTy, +) { + let uint_type = t.normalize(cx.sess().target.pointer_width); + let (min, max) = uint_ty_range(uint_type); + let lit_val: u128 = match lit.node { + // _v is u8, within range by definition + ast::LitKind::Byte(_v) => return, + ast::LitKind::Int(v, _) => v.get(), + _ => bug!(), + }; + + if lit_val < min || lit_val > max { + if let Node::Expr(par_e) = cx.tcx.parent_hir_node(e.hir_id) { + match par_e.kind { + hir::ExprKind::Cast(..) => { + if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { + cx.emit_span_lint(OVERFLOWING_LITERALS, par_e.span, OnlyCastu8ToChar { + span: par_e.span, + literal: lit_val, + }); + return; + } + } + _ => {} + } + } + if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) { + // The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`. + return; + } + if let Some(repr_str) = get_bin_hex_repr(cx, lit) { + report_bin_hex_error( + cx, + e, + attr::IntType::UnsignedInt(ty::ast_uint_ty(t)), + Integer::from_uint_ty(cx, t).size(), + repr_str, + lit_val, + false, + ); + return; + } + cx.emit_span_lint(OVERFLOWING_LITERALS, e.span, OverflowingUInt { + ty: t.name_str(), + lit: cx + .sess() + .source_map() + .span_to_snippet(lit.span) + .unwrap_or_else(|_| lit_val.to_string()), + min, + max, + }); + } +} + +pub(crate) fn lint_literal<'tcx>( + cx: &LateContext<'tcx>, + type_limits: &TypeLimits, + e: &'tcx hir::Expr<'tcx>, + lit: &hir::Lit, +) { + match *cx.typeck_results().node_type(e.hir_id).kind() { + ty::Int(t) => { + match lit.node { + ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { + lint_int_literal(cx, type_limits, e, lit, t, v.get()) + } + _ => bug!(), + }; + } + ty::Uint(t) => lint_uint_literal(cx, e, lit, t), + ty::Float(t) => { + let (is_infinite, sym) = match lit.node { + ast::LitKind::Float(v, _) => match t { + // FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI + // issues resolved). + ty::FloatTy::F16 => (Ok(false), v), + ty::FloatTy::F32 => (v.as_str().parse().map(f32::is_infinite), v), + ty::FloatTy::F64 => (v.as_str().parse().map(f64::is_infinite), v), + ty::FloatTy::F128 => (Ok(false), v), + }, + _ => bug!(), + }; + if is_infinite == Ok(true) { + cx.emit_span_lint(OVERFLOWING_LITERALS, e.span, OverflowingLiteral { + ty: t.name_str(), + lit: cx + .sess() + .source_map() + .span_to_snippet(lit.span) + .unwrap_or_else(|_| sym.to_string()), + }); + } + } + _ => {} + } +} diff --git a/compiler/rustc_lint/src/unit_bindings.rs b/compiler/rustc_lint/src/unit_bindings.rs index ed015908ae54a..3c2c5f8fae095 100644 --- a/compiler/rustc_lint/src/unit_bindings.rs +++ b/compiler/rustc_lint/src/unit_bindings.rs @@ -63,11 +63,9 @@ impl<'tcx> LateLintPass<'tcx> for UnitBindings { && !matches!(init.kind, hir::ExprKind::Tup([])) && !matches!(local.pat.kind, hir::PatKind::Tuple([], ..)) { - cx.emit_span_lint( - UNIT_BINDINGS, - local.span, - UnitBindingsDiag { label: local.pat.span }, - ); + cx.emit_span_lint(UNIT_BINDINGS, local.span, UnitBindingsDiag { + label: local.pat.span, + }); } } } diff --git a/compiler/rustc_lint/src/unqualified_local_imports.rs b/compiler/rustc_lint/src/unqualified_local_imports.rs new file mode 100644 index 0000000000000..bea01a33bd6ce --- /dev/null +++ b/compiler/rustc_lint/src/unqualified_local_imports.rs @@ -0,0 +1,85 @@ +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{self as hir}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::symbol::kw; + +use crate::{LateContext, LateLintPass, LintContext, lints}; + +declare_lint! { + /// The `unqualified_local_imports` lint checks for `use` items that import a local item using a + /// path that does not start with `self::`, `super::`, or `crate::`. + /// + /// ### Example + /// + /// ```rust,edition2018 + /// #![warn(unqualified_local_imports)] + /// + /// mod localmod { + /// pub struct S; + /// } + /// + /// use localmod::S; + /// # // We have to actually use `S`, or else the `unused` warnings suppress the lint we care about. + /// # pub fn main() { + /// # let _x = S; + /// # } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is meant to be used with the (unstable) rustfmt setting `group_imports = "StdExternalCrate"`. + /// That setting makes rustfmt group `self::`, `super::`, and `crate::` imports separately from those + /// refering to other crates. However, rustfmt cannot know whether `use c::S;` refers to a local module `c` + /// or an external crate `c`, so it always gets categorized as an import from another crate. + /// To ensure consistent grouping of imports from the local crate, all local imports must + /// start with `self::`, `super::`, or `crate::`. This lint can be used to enforce that style. + pub UNQUALIFIED_LOCAL_IMPORTS, + Allow, + "`use` of a local item without leading `self::`, `super::`, or `crate::`", + @feature_gate = unqualified_local_imports; +} + +declare_lint_pass!(UnqualifiedLocalImports => [UNQUALIFIED_LOCAL_IMPORTS]); + +impl<'tcx> LateLintPass<'tcx> for UnqualifiedLocalImports { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + let hir::ItemKind::Use(path, _kind) = item.kind else { return }; + // `path` has three resolutions for the type, module, value namespaces. + // Check if any of them qualifies: local crate, and not a macro. + // (Macros can't be imported any other way so we don't complain about them.) + let is_local_import = |res: &Res| { + matches!( + res, + hir::def::Res::Def(def_kind, def_id) + if def_id.is_local() && !matches!(def_kind, DefKind::Macro(_)), + ) + }; + if !path.res.iter().any(is_local_import) { + return; + } + // So this does refer to something local. Let's check whether it starts with `self`, + // `super`, or `crate`. If the path is empty, that means we have a `use *`, which is + // equivalent to `use crate::*` so we don't fire the lint in that case. + let Some(first_seg) = path.segments.first() else { return }; + if matches!(first_seg.ident.name, kw::SelfLower | kw::Super | kw::Crate) { + return; + } + + let encl_item_id = cx.tcx.hir().get_parent_item(item.hir_id()); + let encl_item = cx.tcx.hir_node_by_def_id(encl_item_id.def_id); + if encl_item.fn_kind().is_some() { + // `use` in a method -- don't lint, that leads to too many undesirable lints + // when a function imports all variants of an enum. + return; + } + + // This `use` qualifies for our lint! + cx.emit_span_lint( + UNQUALIFIED_LOCAL_IMPORTS, + first_seg.ident.span, + lints::UnqualifiedLocalImportsDiag {}, + ); + } +} diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index c3b80e01c3624..12d5b5cf97938 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -4,14 +4,14 @@ use std::ops::ControlFlow; use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; -use rustc_errors::{pluralize, MultiSpan}; +use rustc_errors::{MultiSpan, pluralize}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; use rustc_infer::traits::util::elaborate; -use rustc_middle::ty::{self, adjustment, Ty}; +use rustc_middle::ty::{self, Ty, adjustment}; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{Symbol, kw, sym}; use rustc_span::{BytePos, Span}; use tracing::instrument; @@ -185,22 +185,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let mut op_warned = false; if let Some(must_use_op) = must_use_op { - cx.emit_span_lint( - UNUSED_MUST_USE, - expr.span, - UnusedOp { - op: must_use_op, - label: expr.span, - suggestion: if expr_is_from_block { - UnusedOpSuggestion::BlockTailExpr { - before_span: expr.span.shrink_to_lo(), - after_span: expr.span.shrink_to_hi(), - } - } else { - UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() } - }, + cx.emit_span_lint(UNUSED_MUST_USE, expr.span, UnusedOp { + op: must_use_op, + label: expr.span, + suggestion: if expr_is_from_block { + UnusedOpSuggestion::BlockTailExpr { + before_span: expr.span.shrink_to_lo(), + after_span: expr.span.shrink_to_hi(), + } + } else { + UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() } }, - ); + }); op_warned = true; } @@ -283,9 +279,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } match *ty.kind() { - ty::Adt(..) if ty.is_box() => { - let boxed_ty = ty.boxed_ty(); - is_ty_must_use(cx, boxed_ty, expr, span) + ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => { + is_ty_must_use(cx, boxed, expr, span) .map(|inner| MustUsePath::Boxed(Box::new(inner))) } ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => { @@ -498,39 +493,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Closure(span) => { - cx.emit_span_lint( - UNUSED_MUST_USE, - *span, - UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post }, - ); + cx.emit_span_lint(UNUSED_MUST_USE, *span, UnusedClosure { + count: plural_len, + pre: descr_pre, + post: descr_post, + }); } MustUsePath::Coroutine(span) => { - cx.emit_span_lint( - UNUSED_MUST_USE, - *span, - UnusedCoroutine { count: plural_len, pre: descr_pre, post: descr_post }, - ); + cx.emit_span_lint(UNUSED_MUST_USE, *span, UnusedCoroutine { + count: plural_len, + pre: descr_pre, + post: descr_post, + }); } MustUsePath::Def(span, def_id, reason) => { - cx.emit_span_lint( - UNUSED_MUST_USE, - *span, - UnusedDef { - pre: descr_pre, - post: descr_post, - cx, - def_id: *def_id, - note: *reason, - suggestion: (!is_inner).then_some(if expr_is_from_block { - UnusedDefSuggestion::BlockTailExpr { - before_span: span.shrink_to_lo(), - after_span: span.shrink_to_hi(), - } - } else { - UnusedDefSuggestion::NormalExpr { span: span.shrink_to_lo() } - }), - }, - ); + cx.emit_span_lint(UNUSED_MUST_USE, *span, UnusedDef { + pre: descr_pre, + post: descr_post, + cx, + def_id: *def_id, + note: *reason, + suggestion: (!is_inner).then_some(if expr_is_from_block { + UnusedDefSuggestion::BlockTailExpr { + before_span: span.shrink_to_lo(), + after_span: span.shrink_to_hi(), + } + } else { + UnusedDefSuggestion::NormalExpr { span: span.shrink_to_lo() } + }), + }); } } } @@ -734,7 +725,7 @@ trait UnusedDelimLint { return false; } - // Check if we need parens for `match &( Struct { feild: }) {}`. + // Check if we need parens for `match &( Struct { field: }) {}`. { let mut innermost = inner; loop { @@ -792,7 +783,7 @@ trait UnusedDelimLint { // ``` // fn f(){(print!(á // ``` - use rustc_ast::visit::{walk_expr, Visitor}; + use rustc_ast::visit::{Visitor, walk_expr}; struct ErrExprVisitor; impl<'ast> Visitor<'ast> for ErrExprVisitor { type Result = ControlFlow<()>; @@ -870,11 +861,11 @@ trait UnusedDelimLint { end_replace: hi_replace, } }); - cx.emit_span_lint( - self.lint(), - primary_span, - UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion }, - ); + cx.emit_span_lint(self.lint(), primary_span, UnusedDelim { + delim: Self::DELIM_STR, + item: msg, + suggestion, + }); } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { @@ -1559,11 +1550,9 @@ impl UnusedImportBraces { ast::UseTreeKind::Nested { .. } => return, }; - cx.emit_span_lint( - UNUSED_IMPORT_BRACES, - item.span, - UnusedImportBracesDiag { node: node_name }, - ); + cx.emit_span_lint(UNUSED_IMPORT_BRACES, item.span, UnusedImportBracesDiag { + node: node_name, + }); } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7063f488209ea..549dc64a562b2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -9,7 +9,7 @@ use rustc_span::edition::Edition; -use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason}; +use crate::{FutureIncompatibilityReason, declare_lint, declare_lint_pass}; declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s @@ -29,7 +29,6 @@ declare_lint_pass! { CENUM_IMPL_DROP_CAST, COHERENCE_LEAK_CHECK, CONFLICTING_REPR_HINTS, - CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, DEAD_CODE, @@ -100,7 +99,6 @@ declare_lint_pass! { SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, STABLE_FEATURES, - STATIC_MUT_REFS, TEST_UNSTABLE_LINT, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TRIVIAL_CASTS, @@ -1871,6 +1869,7 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail + /// # #[cfg_attr(bootstrap)] compile_error!(); // Remove this in bootstrap bump. /// #![deny(elided_named_lifetimes)] /// struct Foo; /// impl Foo { @@ -1927,57 +1926,6 @@ declare_lint! { }; } -declare_lint! { - /// The `static_mut_refs` lint checks for shared or mutable references - /// of mutable static inside `unsafe` blocks and `unsafe` functions. - /// - /// ### Example - /// - /// ```rust,edition2021 - /// fn main() { - /// static mut X: i32 = 23; - /// static mut Y: i32 = 24; - /// - /// unsafe { - /// let y = &X; - /// let ref x = X; - /// let (x, y) = (&X, &Y); - /// foo(&X); - /// } - /// } - /// - /// unsafe fn _foo() { - /// static mut X: i32 = 23; - /// static mut Y: i32 = 24; - /// - /// let y = &X; - /// let ref x = X; - /// let (x, y) = (&X, &Y); - /// foo(&X); - /// } - /// - /// fn foo<'a>(_x: &'a i32) {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Shared or mutable references of mutable static are almost always a mistake and - /// can lead to undefined behavior and various other problems in your code. - /// - /// This lint is "warn" by default on editions up to 2021, in 2024 there is - /// a hard error instead. - pub STATIC_MUT_REFS, - Warn, - "shared references or mutable references of mutable static is discouraged", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), - reference: "issue #114447 ", - explain_reason: false, - }; -} - declare_lint! { /// The `absolute_paths_not_starting_with_crate` lint detects fully /// qualified paths that start with a module name instead of `crate`, @@ -2804,51 +2752,6 @@ declare_lint! { @feature_gate = strict_provenance; } -declare_lint! { - /// The `const_eval_mutable_ptr_in_final_value` lint detects if a mutable pointer - /// has leaked into the final value of a const expression. - /// - /// ### Example - /// - /// ```rust - /// pub enum JsValue { - /// Undefined, - /// Object(std::cell::Cell), - /// } - /// - /// impl ::std::ops::Drop for JsValue { - /// fn drop(&mut self) {} - /// } - /// - /// const UNDEFINED: &JsValue = &JsValue::Undefined; - /// - /// fn main() { - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// In the 1.77 release, the const evaluation machinery adopted some - /// stricter rules to reject expressions with values that could - /// end up holding mutable references to state stored in static memory - /// (which is inherently immutable). - /// - /// This is a [future-incompatible] lint to ease the transition to an error. - /// See [issue #122153] for more details. - /// - /// [issue #122153]: https://github.com/rust-lang/rust/issues/122153 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, - Warn, - "detects a mutable pointer that has leaked into final value of a const expression", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #122153 ", - }; -} - declare_lint! { /// The `const_evaluatable_unchecked` lint detects a generic constant used /// in a type. @@ -3706,7 +3609,7 @@ declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); declare_lint! { /// The `missing_abi` lint detects cases where the ABI is omitted from - /// extern declarations. + /// `extern` declarations. /// /// ### Example /// @@ -3720,10 +3623,12 @@ declare_lint! { /// /// ### Explanation /// - /// Historically, Rust implicitly selected C as the ABI for extern - /// declarations. We expect to add new ABIs, like `C-unwind`, in the future, - /// though this has not yet happened, and especially with their addition - /// seeing the ABI easily will make code review easier. + /// For historic reasons, Rust implicitly selects `C` as the default ABI for + /// `extern` declarations. [Other ABIs] like `C-unwind` and `system` have + /// been added since then, and especially with their addition seeing the ABI + /// easily makes code review easier. + /// + /// [Other ABIs]: https://doc.rust-lang.org/reference/items/external-blocks.html#abi pub MISSING_ABI, Allow, "No declared ABI for extern declaration" diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6ee330416236f..734e7069c9026 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -10,11 +10,11 @@ use rustc_data_structures::stable_hasher::{ }; use rustc_error_messages::{DiagMessage, MultiSpan}; use rustc_hir::def::Namespace; -use rustc_hir::{HashStableContext, HirId}; +use rustc_hir::{HashStableContext, HirId, MissingLifetimeKind}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; -use rustc_span::edition::Edition; +pub use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::spec::abi::Abi; use serde::{Deserialize, Serialize}; @@ -556,6 +556,12 @@ pub enum DeprecatedSinceKind { InVersion(String), } +#[derive(Debug)] +pub enum ElidedLifetimeResolution { + Static, + Param(Symbol, Span), +} + // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). #[derive(Debug)] @@ -568,12 +574,9 @@ pub enum BuiltinLintDiag { }, MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), ElidedLifetimesInPaths(usize, Span, bool, Span), - ElidedIsStatic { - elided: Span, - }, - ElidedIsParam { - elided: Span, - param: (Symbol, Span), + ElidedNamedLifetimes { + elided: (Span, MissingLifetimeKind), + resolution: ElidedLifetimeResolution, }, UnknownCrateTypes { span: Span, @@ -609,6 +612,8 @@ pub enum BuiltinLintDiag { LegacyDeriveHelpers(Span), OrPatternsBackCompat(Span, String), ReservedPrefix(Span, String), + /// `'r#` in edition < 2021. + RawPrefix(Span), TrailingMacro(bool, Ident), BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index b2ff9efb41cba..f092110a324ec 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -220,7 +220,10 @@ fn main() { let mut cmd = Command::new(&llvm_config); cmd.arg(llvm_link_arg).arg("--libs"); - if !is_crossed { + // Don't link system libs if cross-compiling unless targetting Windows. + // On Windows system DLLs aren't linked directly, instead import libraries are used. + // These import libraries are independent of the host. + if !is_crossed || target.contains("windows") { cmd.arg("--system-libs"); } diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index a8c278741a77b..feac6a5649c8e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -196,14 +196,10 @@ extern "C" LLVMRustResult LLVMRustWriteArchive( } } -#if LLVM_VERSION_LT(18, 0) - auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false); -#else auto SymtabMode = WriteSymbtab ? SymtabWritingMode::NormalSymtab : SymtabWritingMode::NoSymtab; auto Result = writeArchive(Dst, Members, SymtabMode, Kind, true, false, nullptr, isEC); -#endif if (!Result) return LLVMRustResult::Success; LLVMRustSetLastError(toString(std::move(Result)).c_str()); diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index e842f47f48c23..4532fd8d48d07 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -58,17 +58,10 @@ fromRust(LLVMRustCounterMappingRegionKind Kind) { return coverage::CounterMappingRegion::GapRegion; case LLVMRustCounterMappingRegionKind::BranchRegion: return coverage::CounterMappingRegion::BranchRegion; -#if LLVM_VERSION_GE(18, 0) case LLVMRustCounterMappingRegionKind::MCDCDecisionRegion: return coverage::CounterMappingRegion::MCDCDecisionRegion; case LLVMRustCounterMappingRegionKind::MCDCBranchRegion: return coverage::CounterMappingRegion::MCDCBranchRegion; -#else - case LLVMRustCounterMappingRegionKind::MCDCDecisionRegion: - break; - case LLVMRustCounterMappingRegionKind::MCDCBranchRegion: - break; -#endif } report_fatal_error("Bad LLVMRustCounterMappingRegionKind!"); } @@ -100,7 +93,7 @@ struct LLVMRustMCDCParameters { // https://github.com/rust-lang/llvm-project/blob/66a2881a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L253-L263 // and representations in 19 // https://github.com/llvm/llvm-project/blob/843cc474faefad1d639f4c44c1cf3ad7dbda76c8/llvm/include/llvm/ProfileData/Coverage/MCDCTypes.h -#if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0) +#if LLVM_VERSION_LT(19, 0) static coverage::CounterMappingRegion::MCDCParameters fromRust(LLVMRustMCDCParameters Params) { auto parameter = coverage::CounterMappingRegion::MCDCParameters{}; @@ -126,7 +119,7 @@ fromRust(LLVMRustMCDCParameters Params) { } report_fatal_error("Bad LLVMRustMCDCParametersTag!"); } -#elif LLVM_VERSION_GE(19, 0) +#else static coverage::mcdc::Parameters fromRust(LLVMRustMCDCParameters Params) { switch (Params.Tag) { case LLVMRustMCDCParametersTag::None: @@ -221,7 +214,7 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer( RustMappingRegions, NumMappingRegions)) { MappingRegions.emplace_back( fromRust(Region.Count), fromRust(Region.FalseCount), -#if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0) +#if LLVM_VERSION_LT(19, 0) // LLVM 19 may move this argument to last. fromRust(Region.MCDCParameters), #endif diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index a493abbbc7e5a..73bbc9de855fa 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -25,7 +25,6 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Scalar.h" #define LLVM_VERSION_GE(major, minor) \ @@ -34,6 +33,12 @@ #define LLVM_VERSION_LT(major, minor) (!LLVM_VERSION_GE((major), (minor))) +#if LLVM_VERSION_GE(20, 0) +#include "llvm/Transforms/Utils/Instrumentation.h" +#else +#include "llvm/Transforms/Instrumentation.h" +#endif + #include "llvm/IR/LegacyPassManager.h" #include "llvm/Bitcode/BitcodeReader.h" diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index da27db29c87ad..165fb7aa6c3d3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -26,22 +26,19 @@ #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/TargetParser/Host.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/IPO/FunctionImport.h" #include "llvm/Transforms/IPO/Internalize.h" #include "llvm/Transforms/IPO/LowerTypeTests.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" -#include "llvm/Transforms/Utils/AddDiscriminators.h" -#include "llvm/Transforms/Utils/FunctionImportUtils.h" -#if LLVM_VERSION_GE(18, 0) -#include "llvm/TargetParser/Host.h" -#endif -#include "llvm/Support/TimeProfiler.h" -#include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" +#include "llvm/Transforms/Utils/AddDiscriminators.h" +#include "llvm/Transforms/Utils/FunctionImportUtils.h" #if LLVM_VERSION_GE(19, 0) #include "llvm/Support/PGOOptions.h" #endif @@ -241,11 +238,7 @@ enum class LLVMRustCodeGenOptLevel { Aggressive, }; -#if LLVM_VERSION_GE(18, 0) using CodeGenOptLevelEnum = llvm::CodeGenOptLevel; -#else -using CodeGenOptLevelEnum = llvm::CodeGenOpt::Level; -#endif static CodeGenOptLevelEnum fromRust(LLVMRustCodeGenOptLevel Level) { switch (Level) { @@ -371,21 +364,16 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, } extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) { -#if LLVM_VERSION_GE(18, 0) const TargetMachine *Target = unwrap(TM); const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const ArrayRef FeatTable = MCInfo->getAllProcessorFeatures(); return FeatTable.size(); -#else - return 0; -#endif } extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index, const char **Feature, const char **Desc) { -#if LLVM_VERSION_GE(18, 0) const TargetMachine *Target = unwrap(TM); const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const ArrayRef FeatTable = @@ -393,7 +381,6 @@ extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index, const SubtargetFeatureKV Feat = FeatTable[Index]; *Feature = Feat.Key; *Desc = Feat.Desc; -#endif } extern "C" const char *LLVMRustGetHostCPUName(size_t *len) { @@ -498,6 +485,22 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.EmitStackSizeSection = EmitStackSizeSection; if (ArgsCstrBuff != nullptr) { +#if LLVM_VERSION_GE(20, 0) + int buffer_offset = 0; + assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); + auto Arg0 = std::string(ArgsCstrBuff); + buffer_offset = Arg0.size() + 1; + auto ArgsCppStr = + std::string(ArgsCstrBuff + buffer_offset, ArgsCstrBuffLen - 1); + auto i = 0; + while (i != std::string::npos) { + i = ArgsCppStr.find('\0', i + 1); + if (i != std::string::npos) + ArgsCppStr.replace(i, i + 1, " "); + } + Options.MCOptions.Argv0 = Arg0; + Options.MCOptions.CommandlineArgs = ArgsCppStr; +#else int buffer_offset = 0; assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); @@ -523,6 +526,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.MCOptions.Argv0 = arg0; Options.MCOptions.CommandLineArgs = llvm::ArrayRef(cmd_arg_strings, num_cmd_arg_strings); +#endif } TargetMachine *TM = TheTarget->createTargetMachine( @@ -531,10 +535,11 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( } extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { - +#if LLVM_VERSION_LT(20, 0) MCTargetOptions &MCOptions = unwrap(TM)->Options.MCOptions; delete[] MCOptions.Argv0; delete[] MCOptions.CommandLineArgs.data(); +#endif delete unwrap(TM); } @@ -570,17 +575,9 @@ enum class LLVMRustFileType { static CodeGenFileType fromRust(LLVMRustFileType Type) { switch (Type) { case LLVMRustFileType::AssemblyFile: -#if LLVM_VERSION_GE(18, 0) return CodeGenFileType::AssemblyFile; -#else - return CGFT_AssemblyFile; -#endif case LLVMRustFileType::ObjectFile: -#if LLVM_VERSION_GE(18, 0) return CodeGenFileType::ObjectFile; -#else - return CGFT_ObjectFile; -#endif default: report_fatal_error("Bad FileType."); } @@ -866,11 +863,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( // cargo run tests in multhreading mode by default // so use atomics for coverage counters Options.Atomic = true; -#if LLVM_VERSION_GE(18, 0) MPM.addPass(InstrProfilingLoweringPass(Options, false)); -#else - MPM.addPass(InstrProfiling(Options, false)); -#endif }); } @@ -1211,7 +1204,6 @@ struct LLVMRustThinLTOData { // Not 100% sure what these are, but they impact what's internalized and // what's inlined across modules, I believe. -#if LLVM_VERSION_GE(18, 0) #if LLVM_VERSION_GE(20, 0) FunctionImporter::ImportListsTy ImportLists; #else @@ -1219,11 +1211,6 @@ struct LLVMRustThinLTOData { #endif DenseMap ExportLists; DenseMap ModuleToDefinedGVSummaries; -#else - StringMap ImportLists; - StringMap ExportLists; - StringMap ModuleToDefinedGVSummaries; -#endif StringMap> ResolvedODR; LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {} @@ -1275,11 +1262,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules, Ret->ModuleMap[module->identifier] = mem_buffer; -#if LLVM_VERSION_GE(18, 0) if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index)) { -#else - if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index, i)) { -#endif LLVMRustSetLastError(toString(std::move(Err)).c_str()); return nullptr; } @@ -1425,13 +1408,13 @@ LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, return true; } -extern "C" bool LLVMRustPrepareThinLTOImport(LLVMRustThinLTOData *Data, +extern "C" bool LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M, LLVMTargetMachineRef TM) { Module &Mod = *unwrap(M); TargetMachine &Target = *unwrap(TM); - const auto &ImportList = Data->ImportLists[Mod.getModuleIdentifier()]; + const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier()); auto Loader = [&](StringRef Identifier) { const auto &Memory = Data->ModuleMap.lookup(Identifier); auto &Context = Mod.getContext(); @@ -1614,7 +1597,7 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, LLVMRustThinLTOData *Data) { SmallString<40> Key; llvm::lto::Config conf; - const auto &ImportList = Data->ImportLists[ModId]; + const auto &ImportList = Data->ImportLists.lookup(ModId); const auto &ExportList = Data->ExportLists.lookup(ModId); const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId); const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index ed12318c88dae..f9fc2bd6da3b0 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -310,16 +310,10 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::SafeStack; case FnRetThunkExtern: return Attribute::FnRetThunkExtern; -#if LLVM_VERSION_GE(18, 0) case Writable: return Attribute::Writable; case DeadOnUnwind: return Attribute::DeadOnUnwind; -#else - case Writable: - case DeadOnUnwind: - report_fatal_error("Not supported on this LLVM version"); -#endif } report_fatal_error("bad AttributeKind"); } @@ -1061,11 +1055,7 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType( return wrap(Builder->createStaticMemberType( unwrapDI(Scope), StringRef(Name, NameLen), unwrapDI(File), LineNo, unwrapDI(Ty), fromRust(Flags), - unwrap(val), -#if LLVM_VERSION_GE(18, 0) - llvm::dwarf::DW_TAG_member, -#endif - AlignInBits)); + unwrap(val), llvm::dwarf::DW_TAG_member, AlignInBits)); } extern "C" LLVMMetadataRef @@ -1182,10 +1172,7 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( unwrapDI(Scope), StringRef(Name, NameLen), unwrapDI(File), LineNumber, SizeInBits, AlignInBits, DINodeArray(unwrapDI(Elements)), unwrapDI(ClassTy), -#if LLVM_VERSION_GE(18, 0) - /* RunTimeLang */ 0, -#endif - "", IsScoped)); + /* RunTimeLang */ 0, "", IsScoped)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( @@ -1552,27 +1539,19 @@ LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_GE(18, 0) return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); -#else - report_fatal_error("LLVM 18.0 is required for mcdc intrinsic functions"); -#endif } extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_GE(18, 0) return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); -#else - report_fatal_error("LLVM 18.0 is required for mcdc intrinsic functions"); -#endif } extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0) +#if LLVM_VERSION_LT(19, 0) return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_condbitmap_update)); #else diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index d625935d92594..54ee79dc290bf 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -150,11 +150,9 @@ extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { return cast(&*Obj)->getMachine() != COFF::IMAGE_FILE_MACHINE_ARM64; -#if LLVM_VERSION_GE(18, 0) if (Obj->isCOFFImportFile()) return cast(&*Obj)->getMachine() != COFF::IMAGE_FILE_MACHINE_ARM64; -#endif if (Obj->isIR()) { Expected TripleStr = diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 3532d50c64e87..055d2bd5bc976 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(unsafe_attributes, unsafe_extern_blocks))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index b6d870768a862..a3890fc937e79 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -44,8 +44,8 @@ use std::io::{self, IsTerminal}; use tracing_core::{Event, Subscriber}; use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter}; -use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields}; use tracing_subscriber::fmt::FmtContext; +use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields}; use tracing_subscriber::layer::SubscriberExt; /// The values of all the environment variables that matter for configuring a logger. diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 52d892a20f4d3..185d070496694 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -8,7 +8,7 @@ use syn::spanned::Spanned; use synstructure::Structure; use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind; -use crate::diagnostics::error::{span_err, DiagnosticDeriveError}; +use crate::diagnostics::error::{DiagnosticDeriveError, span_err}; use crate::diagnostics::utils::SetOnce; /// The central struct for constructing the `into_diag` method from an annotated struct. diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 5c2a429a1ebbe..72f1e5992472d 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -3,17 +3,17 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned}; use syn::spanned::Spanned; -use syn::{parse_quote, Attribute, Meta, Path, Token, Type}; +use syn::{Attribute, Meta, Path, Token, Type, parse_quote}; use synstructure::{BindingInfo, Structure, VariantInfo}; use super::utils::SubdiagnosticVariant; use crate::diagnostics::error::{ - span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError, + DiagnosticDeriveError, span_err, throw_invalid_attr, throw_span_err, }; use crate::diagnostics::utils::{ + FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error, - should_generate_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, - FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, + should_generate_arg, type_is_bool, type_is_unit, type_matches_path, }; /// What kind of diagnostic is being derived - a fatal/error/warning or a lint? diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 5d5d279eaf0a5..909083d5e8652 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -8,13 +8,13 @@ use synstructure::{BindingInfo, Structure, VariantInfo}; use super::utils::SubdiagnosticVariant; use crate::diagnostics::error::{ - invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError, + DiagnosticDeriveError, invalid_attr, span_err, throw_invalid_attr, throw_span_err, }; use crate::diagnostics::utils::{ - build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident, - report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, - should_generate_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, - SetOnce, SpannedOption, SubdiagnosticKind, + AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, + SpannedOption, SubdiagnosticKind, build_field_mapping, build_suggestion_code, is_doc_comment, + new_code_ident, report_error_if_not_applied_to_applicability, + report_error_if_not_applied_to_span, should_generate_arg, }; /// The central struct for constructing the `add_to_diag` method from an annotated struct. diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 0d3b2f52fa2af..5946b11828ea0 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -5,16 +5,16 @@ use std::str::FromStr; use proc_macro::Span; use proc_macro2::{Ident, TokenStream}; -use quote::{format_ident, quote, ToTokens}; +use quote::{ToTokens, format_ident, quote}; use syn::meta::ParseNestedMeta; use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::{parenthesized, Attribute, Field, LitStr, Meta, Path, Token, Type, TypeTuple}; +use syn::{Attribute, Field, LitStr, Meta, Path, Token, Type, TypeTuple, parenthesized}; use synstructure::{BindingInfo, VariantInfo}; use super::error::invalid_attr; use crate::diagnostics::error::{ - span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError, + DiagnosticDeriveError, span_err, throw_invalid_attr, throw_span_err, }; thread_local! { diff --git a/compiler/rustc_macros/src/extension.rs b/compiler/rustc_macros/src/extension.rs index bbaa477237b16..781a06f32eba8 100644 --- a/compiler/rustc_macros/src/extension.rs +++ b/compiler/rustc_macros/src/extension.rs @@ -4,9 +4,9 @@ use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - braced, parse_macro_input, Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature, - Token, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, - WhereClause, + Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature, Token, TraitItem, + TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, WhereClause, + braced, parse_macro_input, }; pub(crate) fn extension( diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index bf4a7665ceb88..341447f7e6f26 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -40,14 +40,11 @@ pub(super) fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::To }); s.add_impl_generic(newtcx); - s.bound_impl( - quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>), - quote! { - type Lifted = #lifted; + s.bound_impl(quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>), quote! { + type Lifted = #lifted; - fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { - Some(match self { #body }) - } - }, - ) + fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { + Some(match self { #body }) + } + }) } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 886a38c8ff252..88ea6e07d6eb6 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -4,8 +4,8 @@ use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - braced, parenthesized, parse_macro_input, parse_quote, token, AttrStyle, Attribute, Block, - Error, Expr, Ident, Pat, ReturnType, Token, Type, + AttrStyle, Attribute, Block, Error, Expr, Ident, Pat, ReturnType, Token, Type, braced, + parenthesized, parse_macro_input, parse_quote, token, }; mod kw { diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 2c33a0ac0aafe..ce692abfb9834 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -105,14 +105,11 @@ fn decodable_body( }; s.underscore_const(true); - s.bound_impl( - quote!(::rustc_serialize::Decodable<#decoder_ty>), - quote! { - fn decode(__decoder: &mut #decoder_ty) -> Self { - #decode_body - } - }, - ) + s.bound_impl(quote!(::rustc_serialize::Decodable<#decoder_ty>), quote! { + fn decode(__decoder: &mut #decoder_ty) -> Self { + #decode_body + } + }) } fn decode_field(field: &syn::Field) -> proc_macro2::TokenStream { @@ -288,16 +285,13 @@ fn encodable_body( quote! {} }; - s.bound_impl( - quote!(::rustc_serialize::Encodable<#encoder_ty>), - quote! { - fn encode( - &self, - __encoder: &mut #encoder_ty, - ) { - #lints - #encode_body - } - }, - ) + s.bound_impl(quote!(::rustc_serialize::Encodable<#encoder_ty>), quote! { + fn encode( + &self, + __encoder: &mut #encoder_ty, + ) { + #lints + #encode_body + } + }) } diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 341186ac1ca3a..2552c0a0cfc79 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -30,7 +30,7 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; -use syn::{braced, Expr, Ident, Lit, LitStr, Macro, Token}; +use syn::{Expr, Ident, Lit, LitStr, Macro, Token, braced}; #[cfg(test)] mod tests; diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs index 9c53453df5b54..b32ce60e204ab 100644 --- a/compiler/rustc_macros/src/symbols/tests.rs +++ b/compiler/rustc_macros/src/symbols/tests.rs @@ -94,8 +94,8 @@ fn check_symbol_order() { aardvark, } }; - test_symbols_macro( - input, - &["Symbol `aardvark` must precede `zebra`", "location of previous symbol `zebra`"], - ); + test_symbols_macro(input, &[ + "Symbol `aardvark` must precede `zebra`", + "location of previous symbol `zebra`", + ]); } diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 8ddfa96e0952f..bc3b82c2893fa 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -1,4 +1,4 @@ -use quote::{quote, ToTokens}; +use quote::{ToTokens, quote}; use syn::parse_quote; pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 14a1a7f67e56e..8adec7554a834 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -8,7 +8,7 @@ use std::time::Duration; use std::{cmp, env, iter}; use proc_macro::bridge::client::ProcMacro; -use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, AllocatorKind}; +use rustc_ast::expand::allocator::{AllocatorKind, alloc_error_handler_name, global_fn_name}; use rustc_ast::{self as ast, *}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::owned_slice::OwnedSlice; @@ -17,7 +17,7 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard}; use rustc_errors::DiagCtxtHandle; use rustc_expand::base::SyntaxExtension; use rustc_fs_util::try_canonicalize; -use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, LOCAL_CRATE, LocalDefId, StableCrateId}; use rustc_hir::definitions::Definitions; use rustc_index::IndexVec; use rustc_middle::bug; @@ -28,8 +28,8 @@ use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_span::edition::Edition; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Symbol, sym}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::{PanicStrategy, Target, TargetTriple}; use tracing::{debug, info, trace}; @@ -1063,15 +1063,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let cnum = self.resolve_crate(name, item.span, dep_kind)?; let path_len = definitions.def_path(def_id).data.len(); - self.cstore.update_extern_crate( - cnum, - ExternCrate { - src: ExternCrateSource::Extern(def_id.to_def_id()), - span: item.span, - path_len, - dependency_of: LOCAL_CRATE, - }, - ); + self.cstore.update_extern_crate(cnum, ExternCrate { + src: ExternCrateSource::Extern(def_id.to_def_id()), + span: item.span, + path_len, + dependency_of: LOCAL_CRATE, + }); Some(cnum) } _ => bug!(), @@ -1081,16 +1078,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option { let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?; - self.cstore.update_extern_crate( - cnum, - ExternCrate { - src: ExternCrateSource::Path, - span, - // to have the least priority in `update_extern_crate` - path_len: usize::MAX, - dependency_of: LOCAL_CRATE, - }, - ); + self.cstore.update_extern_crate(cnum, ExternCrate { + src: ExternCrateSource::Path, + span, + // to have the least priority in `update_extern_crate` + path_len: usize::MAX, + dependency_of: LOCAL_CRATE, + }); Some(cnum) } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 42dec978b78cd..6587125ec677f 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use rustc_errors::codes::*; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use crate::fluent_generated as fluent; diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index b2a979ed6d832..4450d050c8e1f 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -12,7 +12,7 @@ use crate::errors::{ BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile, FailedCreateTempdir, FailedWriteError, }; -use crate::{encode_metadata, EncodedMetadata}; +use crate::{EncodedMetadata, encode_metadata}; // FIXME(eddyb) maybe include the crate name in this? pub const METADATA_FILENAME: &str = "lib.rmeta"; @@ -128,8 +128,7 @@ pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> { } pub fn copy_to_stdout(from: &Path) -> io::Result<()> { - let file = fs::File::open(from)?; - let mut reader = io::BufReader::new(file); + let mut reader = fs::File::open_buffered(from)?; let mut stdout = io::stdout(); io::copy(&mut reader, &mut stdout)?; Ok(()) diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 58b352f263de6..10f2087d1e6f1 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -8,6 +8,7 @@ #![feature(decl_macro)] #![feature(error_iter)] #![feature(extract_if)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(iter_from_coroutine)] #![feature(let_chains)] @@ -34,11 +35,12 @@ pub mod errors; pub mod fs; pub mod locator; -pub use creader::{load_symbol_from_dylib, DylibError}; -pub use fs::{emit_wrapper_file, METADATA_FILENAME}; +pub use creader::{DylibError, load_symbol_from_dylib}; +pub use fs::{METADATA_FILENAME, emit_wrapper_file}; pub use native_libs::{ - find_native_static_library, try_find_native_static_library, walk_native_lib_search_dirs, + find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, + walk_native_lib_search_dirs, }; -pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER}; +pub use rmeta::{EncodedMetadata, METADATA_HEADER, encode_metadata, rendered_const}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 90228db378a95..089ac060ba848 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -224,20 +224,20 @@ use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; +use rustc_session::Session; use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; -use rustc_session::Session; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use rustc_target::spec::{Target, TargetTriple}; use snap::read::FrameDecoder; use tracing::{debug, info}; use crate::creader::{Library, MetadataLoader}; use crate::errors; -use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER}; +use crate::rmeta::{METADATA_HEADER, MetadataBlob, rustc_version}; #[derive(Clone)] pub(crate) struct CrateLocator<'a> { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index a6ad449cb53e8..82b907d2501fe 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -1,11 +1,12 @@ use std::ops::ControlFlow; use std::path::{Path, PathBuf}; -use rustc_ast::{NestedMetaItem, CRATE_NODE_ID}; +use rustc_ast::{CRATE_NODE_ID, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_middle::query::LocalCrate; use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; +use rustc_session::Session; use rustc_session::config::CrateType; use rustc_session::cstore::{ DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType, @@ -13,11 +14,10 @@ use rustc_session::cstore::{ use rustc_session::parse::feature_err; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; -use rustc_session::Session; use rustc_span::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_target::spec::abi::Abi; +use rustc_span::symbol::{Symbol, sym}; use rustc_target::spec::LinkSelfContainedComponents; +use rustc_target::spec::abi::Abi; use crate::{errors, fluent_generated}; @@ -109,6 +109,44 @@ pub fn try_find_native_static_library( .break_value() } +pub fn try_find_native_dynamic_library( + sess: &Session, + name: &str, + verbatim: bool, +) -> Option { + let formats = if verbatim { + vec![("".into(), "".into())] + } else { + // While the official naming convention for MSVC import libraries + // is foo.lib... + let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone()); + // ... Meson follows the libfoo.dll.a convention to + // disambiguate .a for static libraries + let meson = ("lib".into(), ".dll.a".into()); + // and MinGW uses .a altogether + let mingw = ("lib".into(), ".a".into()); + vec![os, meson, mingw] + }; + + walk_native_lib_search_dirs( + sess, + LinkSelfContainedComponents::empty(), + None, + |dir, is_framework| { + if !is_framework { + for (prefix, suffix) in &formats { + let test = dir.join(format!("{prefix}{name}{suffix}")); + if test.exists() { + return ControlFlow::Break(test); + } + } + } + ControlFlow::Continue(()) + }, + ) + .break_value() +} + pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf { try_find_native_static_library(sess, name, verbatim) .unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim))) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f3ae24a5895a8..4425c93211a01 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -22,16 +22,16 @@ use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_index::Idx; use rustc_middle::middle::lib_features::LibFeatures; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::Visibility; +use rustc_middle::ty::codec::TyDecoder; use rustc_middle::{bug, implement_ty_decoder}; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::{Decodable, Decoder}; -use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_session::Session; +use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_span::hygiene::HygieneDecodeContext; use rustc_span::symbol::kw; -use rustc_span::{BytePos, Pos, SpanData, SpanDecoder, SyntaxContext, DUMMY_SP}; +use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext}; use tracing::debug; use crate::creader::CStore; diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 0f46cacc27a1a..69707fdbe8fa1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -18,14 +18,14 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; use rustc_session::cstore::{CrateStore, ExternCrate}; use rustc_session::{Session, StableCrateId}; -use rustc_span::hygiene::ExpnId; -use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; +use rustc_span::hygiene::ExpnId; +use rustc_span::symbol::{Symbol, kw}; use super::{Decodable, DecodeContext, DecodeIterator}; use crate::creader::{CStore, LoadedMacro}; -use crate::rmeta::table::IsDefault; use crate::rmeta::AttrFlags; +use crate::rmeta::table::IsDefault; use crate::{foreign_modules, native_libs}; trait ProcessQueryValue<'tcx, T> { @@ -71,8 +71,8 @@ impl<'a, 'tcx, T: Copy + Decodable>> ProcessQueryValue<' for Option> { #[inline(always)] - fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> &'tcx [T] { - if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { &[] } + fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx [T] { + if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { err() } } } @@ -84,12 +84,12 @@ impl<'a, 'tcx, T: Copy + Decodable>> fn process_decoded( self, tcx: TyCtxt<'tcx>, - _err: impl Fn() -> !, + err: impl Fn() -> !, ) -> ty::EarlyBinder<'tcx, &'tcx [T]> { ty::EarlyBinder::bind(if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { - &[] + err() }) } } @@ -247,8 +247,8 @@ provide! { tcx, def_id, other, cdata, explicit_predicates_of => { table } generics_of => { table } inferred_outlives_of => { table_defaulted_array } - explicit_super_predicates_of => { table } - explicit_implied_predicates_of => { table } + explicit_super_predicates_of => { table_defaulted_array } + explicit_implied_predicates_of => { table_defaulted_array } type_of => { table } type_alias_is_lazy => { table_direct } variances_of => { table } @@ -290,6 +290,7 @@ provide! { tcx, def_id, other, cdata, fn_arg_names => { table } coroutine_kind => { table_direct } coroutine_for_closure => { table } + coroutine_by_move_body_def_id => { table } eval_static_initializer => { Ok(cdata .root @@ -300,7 +301,20 @@ provide! { tcx, def_id, other, cdata, .unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer"))) } trait_def => { table } - deduced_param_attrs => { table } + deduced_param_attrs => { + // FIXME: `deduced_param_attrs` has some sketchy encoding settings, + // where we don't encode unless we're optimizing, doing codegen, + // and not incremental (see `encoder.rs`). I don't think this is right! + cdata + .root + .tables + .deduced_param_attrs + .get(cdata, def_id.index) + .map(|lazy| { + &*tcx.arena.alloc_from_iter(lazy.decode((cdata, tcx))) + }) + .unwrap_or_default() + } is_type_alias_impl_trait => { debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index) @@ -333,7 +347,7 @@ provide! { tcx, def_id, other, cdata, tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index)) } associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } - inherent_impls => { Ok(cdata.get_inherent_implementations_for_type(tcx, def_id.index)) } + inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } is_mir_available => { cdata.is_item_mir_available(def_id.index) } is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } @@ -379,7 +393,7 @@ provide! { tcx, def_id, other, cdata, traits => { tcx.arena.alloc_from_iter(cdata.get_traits()) } trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } - crate_incoherent_impls => { Ok(cdata.get_incoherent_impls(tcx, other)) } + crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } dep_kind => { cdata.dep_kind } module_children => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 88256c4db04ec..5f756672b049e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -7,10 +7,11 @@ use std::path::{Path, PathBuf}; use rustc_ast::Attribute; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; -use rustc_data_structures::sync::{join, par_for_each_in, Lrc}; +use rustc_data_structures::sync::{Lrc, join, par_for_each_in}; use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_feature::Features; use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, LocalDefIdSet, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet}; use rustc_hir::definitions::DefPathData; use rustc_hir_pretty::id_to_string; use rustc_middle::middle::dependency_format::Linkage; @@ -23,7 +24,7 @@ use rustc_middle::ty::fast_reject::{self, TreatParams}; use rustc_middle::ty::{AssocItemContainer, SymbolName}; use rustc_middle::util::common::to_readable_str; use rustc_middle::{bug, span_bug}; -use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque}; use rustc_session::config::{CrateType, OptLevel}; use rustc_span::hygiene::HygieneEncodeContext; use rustc_span::symbol::sym; @@ -797,9 +798,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } -struct AnalyzeAttrState { +struct AnalyzeAttrState<'a> { is_exported: bool, is_doc_hidden: bool, + features: &'a Features, } /// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and @@ -812,7 +814,7 @@ struct AnalyzeAttrState { /// visibility: this is a piece of data that can be computed once per defid, and not once per /// attribute. Some attributes would only be usable downstream if they are public. #[inline] -fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool { +fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState<'_>) -> bool { let mut should_encode = false; if !rustc_feature::encode_cross_crate(attr.name_or_empty()) { // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. @@ -837,6 +839,9 @@ fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool { } } } + } else if attr.path().starts_with(&[sym::diagnostic]) && attr.path().len() == 2 { + should_encode = + rustc_feature::is_stable_diagnostic_attribute(attr.path()[1], state.features); } else { should_encode = true; } @@ -1343,6 +1348,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let mut state = AnalyzeAttrState { is_exported: tcx.effective_visibilities(()).is_exported(def_id), is_doc_hidden: false, + features: &tcx.features(), }; let attr_iter = tcx .hir() @@ -1443,9 +1449,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::Trait = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - record_array!(self.tables.explicit_super_predicates_of[def_id] <- + record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <- self.tcx.explicit_super_predicates_of(def_id).skip_binder()); - record_array!(self.tables.explicit_implied_predicates_of[def_id] <- + record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id).skip_binder()); let module_children = self.tcx.module_children_local(local_id); @@ -1454,9 +1460,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::TraitAlias = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - record_array!(self.tables.explicit_super_predicates_of[def_id] <- + record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <- self.tcx.explicit_super_predicates_of(def_id).skip_binder()); - record_array!(self.tables.explicit_implied_predicates_of[def_id] <- + record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id).skip_binder()); } if let DefKind::Trait | DefKind::Impl { .. } = def_kind { @@ -1482,9 +1488,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if def_kind == DefKind::Closure && tcx.type_of(def_id).skip_binder().is_coroutine_closure() { + let coroutine_for_closure = self.tcx.coroutine_for_closure(def_id); self.tables .coroutine_for_closure - .set_some(def_id.index, self.tcx.coroutine_for_closure(def_id).into()); + .set_some(def_id.index, coroutine_for_closure.into()); + + // If this async closure has a by-move body, record it too. + if tcx.needs_coroutine_by_move_body_def_id(coroutine_for_closure) { + self.tables.coroutine_by_move_body_def_id.set_some( + coroutine_for_closure.index, + self.tcx.coroutine_by_move_body_def_id(coroutine_for_closure).into(), + ); + } } if let DefKind::Static { .. } = def_kind { if !self.tcx.is_foreign_item(def_id) { @@ -1525,7 +1540,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - for (def_id, impls) in &tcx.crate_inherent_impls(()).unwrap().inherent_impls { + for (def_id, impls) in &tcx.crate_inherent_impls(()).0.inherent_impls { record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| { assert!(def_id.is_local()); def_id.index @@ -2033,7 +2048,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let simplified_self_ty = fast_reject::simplify_type( self.tcx, trait_ref.self_ty(), - TreatParams::AsCandidateKey, + TreatParams::InstantiateWithInfer, ); trait_impls .entry(trait_ref.def_id) @@ -2074,7 +2089,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let all_impls: Vec<_> = tcx .crate_inherent_impls(()) - .unwrap() + .0 .incoherent_impls .iter() .map(|(&simp, impls)| IncoherentImpls { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a84923130c3ab..79bd1c13b1216 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -5,7 +5,7 @@ pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; use decoder::{DecodeContext, Metadata}; use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; -pub use encoder::{encode_metadata, rendered_const, EncodedMetadata}; +pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; use rustc_ast::expand::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; @@ -13,8 +13,8 @@ use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_macros::{ Decodable, Encodable, MetadataDecodable, MetadataEncodable, TyDecodable, TyEncodable, }; @@ -390,6 +390,8 @@ define_tables! { explicit_item_bounds: Table, Span)>>, explicit_item_super_predicates: Table, Span)>>, inferred_outlives_of: Table, Span)>>, + explicit_super_predicates_of: Table, Span)>>, + explicit_implied_predicates_of: Table, Span)>>, inherent_impls: Table>, associated_types_for_impl_traits_in_associated_fn: Table>, associated_type_for_effects: Table>>, @@ -419,10 +421,6 @@ define_tables! { lookup_deprecation_entry: Table>, explicit_predicates_of: Table>>, generics_of: Table>, - explicit_super_predicates_of: Table, Span)>>, - // As an optimization, we only store this for trait aliases, - // since it's identical to explicit_super_predicates_of for traits. - explicit_implied_predicates_of: Table, Span)>>, type_of: Table>>>, variances_of: Table>, fn_sig: Table>>>, @@ -448,6 +446,7 @@ define_tables! { fn_arg_names: Table>, coroutine_kind: Table, coroutine_for_closure: Table, + coroutine_by_move_body_def_id: Table, eval_static_initializer: Table>>, trait_def: Table>, trait_item_def_id: Table, diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 69e3b703ccee1..b23589afb5874 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -40,5 +40,6 @@ tracing = "0.1" [features] # tidy-alphabetical-start +rustc_randomized_layouts = [] rustc_use_parallel_compiler = ["dep:rustc-rayon-core"] # tidy-alphabetical-end diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 2b9d9a07a98ef..39485a324f2e2 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -103,5 +103,5 @@ middle_unknown_layout = the type `{$ty}` has an unknown layout middle_values_too_big = - values of the type `{$ty}` are too big for the current architecture + values of the type `{$ty}` are too big for the target architecture middle_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 2d47d1d19afb9..87bbeb178ee19 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -57,12 +57,12 @@ //! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html use rustc_data_structures::fingerprint::Fingerprint; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, ModDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId}; use rustc_hir::definitions::DefPathHash; use rustc_hir::{HirId, ItemLocalId, OwnerId}; -pub use rustc_query_system::dep_graph::dep_node::DepKind; pub use rustc_query_system::dep_graph::DepNode; use rustc_query_system::dep_graph::FingerprintStyle; +pub use rustc_query_system::dep_graph::dep_node::DepKind; pub(crate) use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index b24954584fe26..2090c3e6da6fa 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -7,12 +7,12 @@ use crate::ty::{self, TyCtxt}; #[macro_use] mod dep_node; -pub use dep_node::{dep_kinds, label_strs, DepKind, DepNode, DepNodeExt}; +pub use dep_node::{DepKind, DepNode, DepNodeExt, dep_kinds, label_strs}; pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; pub use rustc_query_system::dep_graph::debug::{DepNodeFilter, EdgeFilter}; pub use rustc_query_system::dep_graph::{ - hash_result, DepContext, DepGraphQuery, DepNodeIndex, Deps, SerializedDepGraph, - SerializedDepNodeIndex, TaskDepsRef, WorkProduct, WorkProductId, WorkProductMap, + DepContext, DepGraphQuery, DepNodeIndex, Deps, SerializedDepGraph, SerializedDepNodeIndex, + TaskDepsRef, WorkProduct, WorkProductId, WorkProductMap, hash_result, }; pub type DepGraph = rustc_query_system::dep_graph::DepGraph; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 3d346b9cc5d0a..e11361a615f4c 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,16 +1,16 @@ -use rustc_ast::visit::{walk_list, VisitorResult}; +use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{par_for_each_in, try_par_for_each_in, DynSend, DynSync}; +use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::Visitor; use rustc_hir::*; use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_target::spec::abi::Abi; use {rustc_ast as ast, rustc_hir_pretty as pprust_hir}; @@ -71,7 +71,7 @@ impl<'hir> Iterator for ParentHirIterator<'hir> { debug_assert_ne!(parent_id, self.current_id); self.current_id = parent_id; - return Some(parent_id); + Some(parent_id) } } @@ -103,7 +103,7 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { self.current_id = HirId::make_owner(parent_id.def_id); let node = self.map.tcx.hir_owner_node(self.current_id.owner); - return Some((self.current_id.owner, node)); + Some((self.current_id.owner, node)) } } @@ -598,7 +598,10 @@ impl<'hir> Map<'hir> { /// in the HIR which is recorded by the map and is an item, either an item /// in a module, trait, or impl. pub fn get_parent_item(self, hir_id: HirId) -> OwnerId { - if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() { + if hir_id.local_id != ItemLocalId::ZERO { + // If this is a child of a HIR owner, return the owner. + hir_id.owner + } else if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() { def_id } else { CRATE_OWNER_ID @@ -1233,14 +1236,14 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod body_owners, .. } = collector; - return ModuleItems { + ModuleItems { submodules: submodules.into_boxed_slice(), free_items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), body_owners: body_owners.into_boxed_slice(), - }; + } } pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { @@ -1262,14 +1265,14 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { .. } = collector; - return ModuleItems { + ModuleItems { submodules: submodules.into_boxed_slice(), free_items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), body_owners: body_owners.into_boxed_slice(), - }; + } } struct ItemCollector<'tcx> { diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 596d9f077372e..7a07ef80dedb4 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -9,7 +9,7 @@ pub mod place; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{try_par_for_each_in, DynSend, DynSync}; +use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index bde05210d9fc5..742797fdeef14 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::{DefId, DefPathHash}; use rustc_session::StableCrateId; use rustc_span::def_id::{CrateNum, LocalDefId}; -use rustc_span::{ExpnHash, ExpnId, DUMMY_SP}; +use rustc_span::{DUMMY_SP, ExpnHash, ExpnId}; use tracing::instrument; use crate::mir; diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 3fd4aba31696e..cf692b145b8dc 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -2,8 +2,8 @@ use std::cmp; use std::marker::PhantomData; use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue}; -use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_span::def_id::DefId; use crate::ty::{self, Ty, TyCtxt}; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 2a85f85a9f4eb..a32b19b067a55 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -28,12 +28,12 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(min_exhaustive_patterns, unsafe_extern_blocks))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] #![feature(array_windows)] #![feature(assert_matches)] +#![feature(associated_type_defaults)] #![feature(box_as_ptr)] #![feature(box_patterns)] #![feature(closure_track_caller)] @@ -45,6 +45,7 @@ #![feature(discriminant_kind)] #![feature(extern_types)] #![feature(extract_if)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(iter_from_coroutine)] diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 70da66af64be8..b5862565e8e87 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -5,11 +5,11 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::{Diag, MultiSpan}; use rustc_hir::{HirId, ItemLocalId}; use rustc_macros::HashStable; +use rustc_session::Session; use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS}; use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId}; -use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::{symbol, DesugaringKind, Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, DesugaringKind, Span, Symbol, symbol}; use tracing::instrument; use crate::ty::TyCtxt; diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index b7d290e58d22b..90dff0f5c7da8 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -120,9 +120,7 @@ bitflags::bitflags! { /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. const FFI_CONST = 1 << 12; - /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a - /// function as an entry function from Non-Secure code. - const CMSE_NONSECURE_ENTRY = 1 << 13; + // (Bit 13 was used for `#[cmse_nonsecure_entry]`, but is now unused.) // (Bit 14 was used for `#[coverage(off)]`, but is now unused.) /// `#[used(linker)]`: /// indicates that neither LLVM nor the linker will eliminate this function. diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index f141af4490057..b20673fe8daf5 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -7,8 +7,8 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. -use rustc_hir::def_id::DefId; use rustc_hir::LangItem; +use rustc_hir::def_id::DefId; use rustc_span::Span; use rustc_target::spec::PanicStrategy; diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 70810f51a1f34..270bcabcc86a2 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -12,7 +12,7 @@ use std::num::IntErrorKind; use rustc_ast::Attribute; use rustc_session::{Limit, Limits, Session}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use crate::error::LimitInvalid; use crate::query::Providers; diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 0c4f37ab14f79..83873439bd927 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -6,8 +6,8 @@ pub mod lang_items; pub mod lib_features { use rustc_data_structures::unord::UnordMap; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; - use rustc_span::symbol::Symbol; use rustc_span::Span; + use rustc_span::symbol::Symbol; #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index db70f53b7b498..03549091d62d3 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -9,7 +9,7 @@ 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::{LocalDefId, CRATE_DEF_ID}; +use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId}; use crate::ty::{TyCtxt, Visibility}; diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 6ef1801717c81..4e44de33611b9 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -14,7 +14,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::{HirId, HirIdMap, Node}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use tracing::debug; use crate::ty::TyCtxt; @@ -96,6 +96,7 @@ impl fmt::Debug for Scope { ScopeData::Arguments => write!(fmt, "Arguments({:?})", self.id), ScopeData::Destruction => write!(fmt, "Destruction({:?})", self.id), ScopeData::IfThen => write!(fmt, "IfThen({:?})", self.id), + ScopeData::IfThenRescope => write!(fmt, "IfThen[edition2024]({:?})", self.id), ScopeData::Remainder(fsi) => write!( fmt, "Remainder {{ block: {:?}, first_statement_index: {}}}", @@ -126,6 +127,11 @@ pub enum ScopeData { /// Used for variables introduced in an if-let expression. IfThen, + /// Scope of the condition and then block of an if expression + /// Used for variables introduced in an if-let expression, + /// whose lifetimes do not cross beyond this scope. + IfThenRescope, + /// Scope following a `let id = expr;` binding in a block. Remainder(FirstStatementIndex), } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 3b8861378e08e..54cfd99583215 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -15,12 +15,12 @@ use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::{self as hir, HirId}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_session::Session; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer}; use rustc_session::parse::feature_err_issue; -use rustc_session::Session; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use tracing::debug; pub use self::StabilityLevel::*; @@ -444,10 +444,11 @@ impl<'tcx> TyCtxt<'tcx> { // the `-Z force-unstable-if-unmarked` flag present (we're // compiling a compiler crate), then let this missing feature // annotation slide. - if feature == sym::rustc_private && issue == NonZero::new(27812) { - if self.sess.opts.unstable_opts.force_unstable_if_unmarked { - return EvalResult::Allow; - } + if feature == sym::rustc_private + && issue == NonZero::new(27812) + && self.sess.opts.unstable_opts.force_unstable_if_unmarked + { + return EvalResult::Allow; } if matches!(allow_unstable, AllowUnstable::Yes) { diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 183b898253e50..4602c918160b7 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph; -use rustc_data_structures::graph::dominators::{dominators, Dominators}; +use rustc_data_structures::graph::dominators::{Dominators, dominators}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::OnceLock; use rustc_index::{IndexSlice, IndexVec}; @@ -9,7 +9,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use smallvec::SmallVec; use crate::mir::traversal::Postorder; -use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind, START_BLOCK}; +use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK, Terminator, TerminatorKind}; #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct BasicBlocks<'tcx> { @@ -71,7 +71,7 @@ impl<'tcx> BasicBlocks<'tcx> { #[inline] pub fn reverse_postorder(&self) -> &[BasicBlock] { self.cache.reverse_postorder.get_or_init(|| { - let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK).collect(); + let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, ()).collect(); rpo.reverse(); rpo }) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 563647ad4e678..89d4c46016006 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -2,13 +2,13 @@ use std::fmt::{self, Debug, Display, Formatter}; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_session::config::RemapPathScopeComponents; use rustc_session::RemapFileNameExt; -use rustc_span::{Span, DUMMY_SP}; +use rustc_session::config::RemapPathScopeComponents; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{HasDataLayout, Size}; -use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar}; -use crate::mir::{pretty_print_const_value, Promoted}; +use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range}; +use crate::mir::{Promoted, pretty_print_const_value}; use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; use crate::ty::{self, GenericArgsRef, ScalarInt, Ty, TyCtxt}; @@ -240,7 +240,7 @@ impl<'tcx> Const<'tcx> { match self { Const::Ty(ty, ct) => { match ct.kind() { - // Dont use the outter ty as on invalid code we can wind up with them not being the same. + // Dont use the outer ty as on invalid code we can wind up with them not being the same. // this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir // was originally `({N: usize} + 1_usize)` under `generic_const_exprs`. ty::ConstKind::Value(ty, _) => ty, diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 5fb8af576ae93..b8ecfa3c3f946 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -18,9 +18,9 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ - read_target_uint, write_target_uint, AllocId, BadBytesAccess, CtfeProvenance, InterpError, - InterpResult, Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, - ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, + AllocId, BadBytesAccess, CtfeProvenance, InterpError, InterpResult, Pointer, PointerArithmetic, + Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo, + UnsupportedOpInfo, read_target_uint, write_target_uint, }; use crate::ty; @@ -448,22 +448,20 @@ impl Allocation bad: uninit_range, })) })?; - if !Prov::OFFSET_IS_ADDR { - if !self.provenance.range_empty(range, cx) { - // Find the provenance. - let (offset, _prov) = self - .provenance - .range_get_ptrs(range, cx) - .first() - .copied() - .expect("there must be provenance somewhere here"); - let start = offset.max(range.start); // the pointer might begin before `range`! - let end = (offset + cx.pointer_size()).min(range.end()); // the pointer might end after `range`! - return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess { - access: range, - bad: AllocRange::from(start..end), - }))); - } + if !Prov::OFFSET_IS_ADDR && !self.provenance.range_empty(range, cx) { + // Find the provenance. + let (offset, _prov) = self + .provenance + .range_get_ptrs(range, cx) + .first() + .copied() + .expect("there must be provenance somewhere here"); + let start = offset.max(range.start); // the pointer might begin before `range`! + let end = (offset + cx.pointer_size()).min(range.end()); // the pointer might end after `range`! + return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess { + access: range, + bad: AllocRange::from(start..end), + }))); } Ok(self.get_bytes_unchecked(range)) } @@ -640,6 +638,12 @@ impl Allocation /// Write "uninit" to the given memory range. pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { self.mark_init(range, false); + self.provenance.clear(range, cx)?; + Ok(()) + } + + /// Remove all provenance in the given memory range. + pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { self.provenance.clear(range, cx)?; return Ok(()); } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 4fe219441a064..b3940530f69cc 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -9,7 +9,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_target::abi::{HasDataLayout, Size}; use tracing::trace; -use super::{alloc_range, AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance}; +use super::{AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance, alloc_range}; /// Stores the provenance information of pointers stored in memory. #[derive(Clone, PartialEq, Eq, Hash, Debug)] diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 69ce3e087350b..46646e759d59e 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -10,13 +10,13 @@ use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, Into use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_session::CtfeBacktrace; use rustc_span::def_id::DefId; -use rustc_span::{Span, Symbol, DUMMY_SP}; -use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange}; +use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_target::abi::{Align, Size, VariantIdx, WrappingRange, call}; use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; -use crate::ty::{self, layout, tls, Ty, TyCtxt, ValTree}; +use crate::ty::{self, Ty, TyCtxt, ValTree, layout, tls}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum ErrorHandled { @@ -91,9 +91,9 @@ pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled pub type EvalStaticInitializerRawResult<'tcx> = Result, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; /// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed -/// because the value containts something of type `ty` that is not valtree-compatible. +/// because the value contains something of type `ty` that is not valtree-compatible. /// The caller can then show an appropriate error; the query does not have the -/// necssary context to give good user-facing errors for this case. +/// necessary context to give good user-facing errors for this case. pub type EvalToValTreeResult<'tcx> = Result, Ty<'tcx>>, ErrorHandled>; #[cfg(target_pointer_width = "64")] @@ -231,7 +231,7 @@ pub enum CheckInAllocMsg { pub enum CheckAlignMsg { /// The accessed pointer did not have proper alignment. AccessedPtr, - /// The access ocurred with a place that was based on a misaligned pointer. + /// The access occurred with a place that was based on a misaligned pointer. BasedOn, } @@ -365,8 +365,10 @@ pub enum UndefinedBehaviorInfo<'tcx> { InvalidVTablePointer(Pointer), /// Using a vtable for the wrong trait. InvalidVTableTrait { - expected_trait: &'tcx ty::List>, - vtable_trait: Option>, + /// The vtable that was actually referenced by the wide pointer metadata. + vtable_dyn_type: &'tcx ty::List>, + /// The vtable that was expected at the point in MIR that it was accessed. + expected_dyn_type: &'tcx ty::List>, }, /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), @@ -479,8 +481,10 @@ pub enum ValidationErrorKind<'tcx> { value: String, }, InvalidMetaWrongTrait { - expected_trait: &'tcx ty::List>, - vtable_trait: Option>, + /// The vtable that was actually referenced by the wide pointer metadata. + vtable_dyn_type: &'tcx ty::List>, + /// The vtable that was expected at the point in MIR that it was accessed. + expected_dyn_type: &'tcx ty::List>, }, InvalidMetaSliceTooLarge { ptr_kind: PointerKind, diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 91e71c12cae45..d7809cc4343d2 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -30,8 +30,8 @@ pub use { }; pub use self::allocation::{ - alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, - InitChunk, InitChunkIter, + AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk, + InitChunkIter, alloc_range, }; pub use self::error::{ BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult, @@ -232,9 +232,8 @@ impl<'s> AllocDecodingSession<'s> { } AllocDiscriminant::VTable => { trace!("creating vtable alloc ID"); - let ty = as Decodable>::decode(decoder); - let poly_trait_ref = - > as Decodable>::decode(decoder); + let ty = Decodable::decode(decoder); + let poly_trait_ref = Decodable::decode(decoder); trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref, CTFE_ALLOC_SALT) } @@ -259,7 +258,10 @@ pub enum GlobalAlloc<'tcx> { /// The alloc ID is used as a function pointer. Function { instance: Instance<'tcx> }, /// This alloc ID points to a symbolic (not-reified) vtable. - VTable(Ty<'tcx>, Option>), + /// We remember the full dyn type, not just the principal trait, so that + /// const-eval and Miri can detect UB due to invalid transmutes of + /// `dyn Trait` types. + VTable(Ty<'tcx>, &'tcx ty::List>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). /// This is also used to break the cycle in recursive statics. Static(DefId), @@ -293,7 +295,7 @@ impl<'tcx> GlobalAlloc<'tcx> { #[inline] pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option>) { match *self { - GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref), + GlobalAlloc::VTable(ty, dyn_ty) => (ty, dyn_ty.principal()), _ => bug!("expected vtable, got {:?}", self), } } @@ -398,10 +400,10 @@ impl<'tcx> TyCtxt<'tcx> { pub fn reserve_and_set_vtable_alloc( self, ty: Ty<'tcx>, - poly_trait_ref: Option>, + dyn_ty: &'tcx ty::List>, salt: usize, ) -> AllocId { - self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref), salt) + self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, dyn_ty), salt) } /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 6cfd07d699c3e..1700b0f02ecc8 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -80,14 +80,23 @@ pub trait Provenance: Copy + fmt::Debug + 'static { } /// The type of provenance in the compile-time interpreter. -/// This is a packed representation of an `AllocId` and an `immutable: bool`. +/// This is a packed representation of: +/// - an `AllocId` (non-zero) +/// - an `immutable: bool` +/// - a `shared_ref: bool` +/// +/// with the extra invariant that if `immutable` is `true`, then so +/// is `shared_ref`. #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct CtfeProvenance(NonZero); impl From for CtfeProvenance { fn from(value: AllocId) -> Self { let prov = CtfeProvenance(value.0); - assert!(!prov.immutable(), "`AllocId` with the highest bit set cannot be used in CTFE"); + assert!( + prov.alloc_id() == value, + "`AllocId` with the highest bits set cannot be used in CTFE" + ); prov } } @@ -103,12 +112,14 @@ impl fmt::Debug for CtfeProvenance { } const IMMUTABLE_MASK: u64 = 1 << 63; // the highest bit +const SHARED_REF_MASK: u64 = 1 << 62; +const ALLOC_ID_MASK: u64 = u64::MAX & !IMMUTABLE_MASK & !SHARED_REF_MASK; impl CtfeProvenance { /// Returns the `AllocId` of this provenance. #[inline(always)] pub fn alloc_id(self) -> AllocId { - AllocId(NonZero::new(self.0.get() & !IMMUTABLE_MASK).unwrap()) + AllocId(NonZero::new(self.0.get() & ALLOC_ID_MASK).unwrap()) } /// Returns whether this provenance is immutable. @@ -117,10 +128,38 @@ impl CtfeProvenance { self.0.get() & IMMUTABLE_MASK != 0 } + /// Returns whether this provenance is derived from a shared reference. + #[inline] + pub fn shared_ref(self) -> bool { + self.0.get() & SHARED_REF_MASK != 0 + } + + pub fn into_parts(self) -> (AllocId, bool, bool) { + (self.alloc_id(), self.immutable(), self.shared_ref()) + } + + pub fn from_parts((alloc_id, immutable, shared_ref): (AllocId, bool, bool)) -> Self { + let prov = CtfeProvenance::from(alloc_id); + if immutable { + // This sets both flags, so we don't even have to check `shared_ref`. + prov.as_immutable() + } else if shared_ref { + prov.as_shared_ref() + } else { + prov + } + } + /// Returns an immutable version of this provenance. #[inline] pub fn as_immutable(self) -> Self { - CtfeProvenance(self.0 | IMMUTABLE_MASK) + CtfeProvenance(self.0 | IMMUTABLE_MASK | SHARED_REF_MASK) + } + + /// Returns a "shared reference" (but not necessarily immutable!) version of this provenance. + #[inline] + pub fn as_shared_ref(self) -> Self { + CtfeProvenance(self.0 | SHARED_REF_MASK) } } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 675e78603aebd..59bc55269a30a 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,7 +1,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_session::lint; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; use super::{ diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 84c17b39a623e..c6c2ab414ed41 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -1,8 +1,8 @@ use std::fmt; use either::{Either, Left, Right}; -use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_target::abi::{HasDataLayout, Size}; @@ -307,6 +307,13 @@ impl<'tcx, Prov: Provenance> Scalar { } } + pub fn clear_provenance(&mut self) -> InterpResult<'tcx> { + if matches!(self, Scalar::Ptr(..)) { + *self = self.to_scalar_int()?.into(); + } + Ok(()) + } + #[inline(always)] pub fn to_scalar_int(self) -> InterpResult<'tcx, ScalarInt> { self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None)).into()) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7b90191503702..cd148aef29ba8 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -3,8 +3,6 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html use std::borrow::Cow; -use std::cell::RefCell; -use std::collections::hash_map::Entry; use std::fmt::{self, Debug, Formatter}; use std::ops::{Index, IndexMut}; use std::{iter, mem}; @@ -18,7 +16,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; use rustc_hir::def::{CtorKind, Namespace}; -use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{ self as hir, BindingMode, ByRef, CoroutineDesugaring, CoroutineKind, HirId, ImplicitSelfKind, }; @@ -26,10 +24,9 @@ use rustc_index::bit_set::BitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_serialize::{Decodable, Encodable}; -use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{FieldIdx, VariantIdx}; use tracing::trace; @@ -39,7 +36,7 @@ use crate::mir::interpret::{AllocRange, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::ty::print::{pretty_print_const, with_no_trimmed_paths, FmtPrinter, Printer}; +use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{ self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, @@ -75,7 +72,7 @@ pub use terminator::*; pub use self::generic_graph::graphviz_safe_def_name; pub use self::graphviz::write_mir_graphviz; pub use self::pretty::{ - create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere, + PassWhere, create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, }; /// Types for locals @@ -106,65 +103,6 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { } } -thread_local! { - static PASS_NAMES: RefCell> = { - RefCell::new(FxHashMap::default()) - }; -} - -/// Converts a MIR pass name into a snake case form to match the profiling naming style. -fn to_profiler_name(type_name: &'static str) -> &'static str { - PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let snake_case: String = type_name - .chars() - .flat_map(|c| { - if c.is_ascii_uppercase() { - vec!['_', c.to_ascii_lowercase()] - } else if c == '-' { - vec!['_'] - } else { - vec![c] - } - }) - .collect(); - let result = &*String::leak(format!("mir_pass{}", snake_case)); - e.insert(result); - result - } - }) -} - -/// A streamlined trait that you can implement to create a pass; the -/// pass will be named after the type, and it will consist of a main -/// loop that goes over each available MIR and applies `run_pass`. -pub trait MirPass<'tcx> { - fn name(&self) -> &'static str { - // FIXME Simplify the implementation once more `str` methods get const-stable. - // See copypaste in `MirLint` - const { - let name = std::any::type_name::(); - crate::util::common::c_name(name) - } - } - - fn profiler_name(&self) -> &'static str { - to_profiler_name(self.name()) - } - - /// Returns `true` if this pass is enabled with the current combination of compiler flags. - fn is_enabled(&self, _sess: &Session) -> bool { - true - } - - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); - - fn is_mir_dump_enabled(&self) -> bool { - true - } -} - impl MirPhase { /// Gets the index of the current MirPhase within the set of all `MirPhase`s. /// @@ -1146,6 +1084,9 @@ pub enum LocalInfo<'tcx> { /// (with no intervening statement context). // FIXME(matthewjasper) Don't store in this in `Body` BlockTailTemp(BlockTailInfo), + /// A temporary created during evaluating `if` predicate, possibly for pattern matching for `let`s, + /// and subject to Edition 2024 temporary lifetime rules + IfThenRescopeTemp { if_then: HirId }, /// A temporary created during the pass `Derefer` to avoid it's retagging DerefTemp, /// A temporary created for borrow checking. @@ -1228,10 +1169,9 @@ impl<'tcx> LocalDecl<'tcx> { /// Returns `true` if this is a DerefTemp pub fn is_deref_temp(&self) -> bool { match self.local_info() { - LocalInfo::DerefTemp => return true, - _ => (), + LocalInfo::DerefTemp => true, + _ => false, } - return false; } /// Returns `true` is the local is from a compiler desugaring, e.g., @@ -1459,10 +1399,10 @@ impl<'tcx> BasicBlockData<'tcx> { // existing elements from before the gap to the end of the gap. // For now, this is safe code, emulating a gap but initializing it. let mut gap = self.statements.len()..self.statements.len() + extra_stmts; - self.statements.resize( - gap.end, - Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop }, - ); + self.statements.resize(gap.end, Statement { + source_info: SourceInfo::outermost(DUMMY_SP), + kind: StatementKind::Nop, + }); for (splice_start, new_stmts) in splices.into_iter().rev() { let splice_end = splice_start + new_stmts.size_hint().0; while gap.end > splice_end { @@ -1484,6 +1424,19 @@ impl<'tcx> BasicBlockData<'tcx> { pub fn is_empty_unreachable(&self) -> bool { self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable) } + + /// Like [`Terminator::successors`] but tries to use information available from the [`Instance`] + /// to skip successors like the `false` side of an `if const {`. + /// + /// This is used to implement [`traversal::mono_reachable`] and + /// [`traversal::mono_reachable_reverse_postorder`]. + pub fn mono_successors(&self, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Successors<'_> { + if let Some((bits, targets)) = Body::try_const_mono_switchint(tcx, instance, self) { + targets.successors_for_value(bits) + } else { + self.terminator().successors() + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 69b5e0a79c7fa..954f746ce5b61 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -2,19 +2,19 @@ use std::fmt; use std::hash::Hash; use rustc_attr::InlineAttr; -use rustc_data_structures::base_n::{BaseNString, ToBaseN, CASE_INSENSITIVE}; +use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher, ToStableHashKey}; use rustc_data_structures::unord::UnordMap; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_index::Idx; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; use rustc_session::config::OptLevel; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use tracing::debug; use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 9906be60e3e95..4878956521831 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -6,8 +6,8 @@ use std::path::{Path, PathBuf}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir::interpret::{ - alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, - Provenance, + AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range, + read_target_uint, }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; @@ -208,12 +208,10 @@ fn dump_path<'tcx>( let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { String::new() + } else if pass_num { + format!(".{:03}-{:03}", body.phase.phase_index(), body.pass_count) } else { - if pass_num { - format!(".{:03}-{:03}", body.phase.phase_index(), body.pass_count) - } else { - ".-------".to_string() - } + ".-------".to_string() }; let crate_name = tcx.crate_name(source.def_id().krate); @@ -279,9 +277,9 @@ pub fn create_dump_file<'tcx>( ) })?; } - Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| { + Ok(fs::File::create_buffered(&file_path).map_err(|e| { io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) - })?)) + })?) } /////////////////////////////////////////////////////////////////////////// @@ -612,7 +610,9 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io: let def_id = body.source.def_id(); let kind = tcx.def_kind(def_id); let is_function = match kind { - DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::SyntheticCoroutineBody => { + true + } _ => tcx.is_closure_like(def_id), }; match (kind, body.source.promoted) { @@ -1536,11 +1536,8 @@ pub fn write_allocations<'tcx>( // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function { instance, .. }) => write!(w, " (fn: {instance})")?, - Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { - write!(w, " (vtable: impl {trait_ref} for {ty})")? - } - Some(GlobalAlloc::VTable(ty, None)) => { - write!(w, " (vtable: impl for {ty})")? + Some(GlobalAlloc::VTable(ty, dyn_ty)) => { + write!(w, " (vtable: impl {dyn_ty} for {ty})")? } Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { match tcx.eval_static_initializer(did) { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a36e49f6ee0fb..70331214ac5a8 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -10,8 +10,8 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitMatrix; use rustc_index::{Idx, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use rustc_target::abi::{FieldIdx, VariantIdx}; use smallvec::SmallVec; @@ -234,7 +234,9 @@ pub enum ConstraintCategory<'tcx> { UseAsStatic, TypeAnnotation, Cast { - /// Whether this is an unsizing cast and if yes, this contains the target type. + /// Whether this cast is a coercion that was automatically inserted by the compiler. + is_implicit_coercion: bool, + /// Whether this is an unsizing coercion and if yes, this contains the target type. /// Region variables are erased to ReErased. #[derive_where(skip)] unsize_to: Option>, diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index bc7dfa6205e71..88ed90c311463 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -432,9 +432,8 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::IntToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr - | CastKind::PointerCoercion(_) + | CastKind::PointerCoercion(_, _) | CastKind::PointerWithExposedProvenance - | CastKind::DynStar | CastKind::Transmute, _, _, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 748ca047754a9..ae75f2d4187ba 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -5,14 +5,14 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, Mutability}; use rustc_data_structures::packed::Pu128; -use rustc_hir::def_id::DefId; use rustc_hir::CoroutineKind; +use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; -use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::asm::InlineAsmRegOrRegClass; use smallvec::SmallVec; @@ -579,7 +579,8 @@ pub struct CopyNonOverlapping<'tcx> { pub count: Operand<'tcx>, } -/// Represents how a `TerminatorKind::Call` was constructed, used for diagnostics +/// Represents how a [`TerminatorKind::Call`] was constructed. +/// Used only for diagnostics. #[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, PartialEq, Hash, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub enum CallSource { @@ -1094,7 +1095,7 @@ pub struct Place<'tcx> { pub projection: &'tcx List>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum ProjectionElem { Deref, @@ -1307,6 +1308,9 @@ pub enum Rvalue<'tcx> { /// If the type of the place is an array, this is the array length. For slices (`[T]`, not /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is /// ill-formed for places of other types. + /// + /// This cannot be a `UnOp(PtrMetadata, _)` because that expects a value, and we only + /// have a place, and `UnOp(PtrMetadata, RawPtr(place))` is not a thing. Len(Place<'tcx>), /// Performs essentially all of the casts that can be performed via `as`. @@ -1400,9 +1404,7 @@ pub enum CastKind { /// * [`PointerCoercion::MutToConstPointer`] /// /// Both are runtime nops, so should be [`CastKind::PtrToPtr`] instead in runtime MIR. - PointerCoercion(PointerCoercion), - /// Cast into a dyn* object. - DynStar, + PointerCoercion(PointerCoercion, CoercionSource), IntToInt, FloatToInt, FloatToFloat, @@ -1418,6 +1420,16 @@ pub enum CastKind { Transmute, } +/// Represents how a [`CastKind::PointerCoercion`] was constructed. +/// Used only for diagnostics. +#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum CoercionSource { + /// The coercion was manually written by the user with an `as` cast. + AsCast, + /// The coercion was automatically inserted by the compiler. + Implicit, +} + #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub enum AggregateKind<'tcx> { @@ -1465,7 +1477,7 @@ pub enum NullOp<'tcx> { UbChecks, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub enum UnOp { /// The `!` operator for logical inversion @@ -1483,7 +1495,7 @@ pub enum UnOp { PtrMetadata, } -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum BinOp { /// The `+` operator (addition) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 962b93a25aac6..783952fb9cb8a 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -5,7 +5,7 @@ use std::slice; use rustc_data_structures::packed::Pu128; use rustc_hir::LangItem; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use super::{TerminatorKind, *}; @@ -413,6 +413,17 @@ mod helper { use super::*; pub type Successors<'a> = impl DoubleEndedIterator + 'a; pub type SuccessorsMut<'a> = impl DoubleEndedIterator + 'a; + + impl SwitchTargets { + /// Like [`SwitchTargets::target_for_value`], but returning the same type as + /// [`Terminator::successors`]. + #[inline] + pub fn successors_for_value(&self, value: u128) -> Successors<'_> { + let target = self.target_for_value(value); + (&[]).into_iter().copied().chain(Some(target)) + } + } + impl<'tcx> TerminatorKind<'tcx> { #[inline] pub fn successors(&self) -> Successors<'_> { diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 245e9096bad47..b8b74da401c9f 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -104,36 +104,46 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { /// ``` /// /// A Postorder traversal of this graph is `D B C A` or `D C B A` -pub struct Postorder<'a, 'tcx> { +pub struct Postorder<'a, 'tcx, C> { basic_blocks: &'a IndexSlice>, visited: BitSet, visit_stack: Vec<(BasicBlock, Successors<'a>)>, root_is_start_block: bool, + extra: C, } -impl<'a, 'tcx> Postorder<'a, 'tcx> { +impl<'a, 'tcx, C> Postorder<'a, 'tcx, C> +where + C: Customization<'tcx>, +{ pub fn new( basic_blocks: &'a IndexSlice>, root: BasicBlock, - ) -> Postorder<'a, 'tcx> { + extra: C, + ) -> Postorder<'a, 'tcx, C> { let mut po = Postorder { basic_blocks, visited: BitSet::new_empty(basic_blocks.len()), visit_stack: Vec::new(), root_is_start_block: root == START_BLOCK, + extra, }; - let data = &po.basic_blocks[root]; - - if let Some(ref term) = data.terminator { - po.visited.insert(root); - po.visit_stack.push((root, term.successors())); - po.traverse_successor(); - } + po.visit(root); + po.traverse_successor(); po } + fn visit(&mut self, bb: BasicBlock) { + if !self.visited.insert(bb) { + return; + } + let data = &self.basic_blocks[bb]; + let successors = C::successors(data, self.extra); + self.visit_stack.push((bb, successors)); + } + fn traverse_successor(&mut self) { // This is quite a complex loop due to 1. the borrow checker not liking it much // and 2. what exactly is going on is not clear @@ -183,16 +193,15 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // since we've already visited `E`, that child isn't added to the stack. The last // two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A] while let Some(bb) = self.visit_stack.last_mut().and_then(|(_, iter)| iter.next_back()) { - if self.visited.insert(bb) { - if let Some(term) = &self.basic_blocks[bb].terminator { - self.visit_stack.push((bb, term.successors())); - } - } + self.visit(bb); } } } -impl<'tcx> Iterator for Postorder<'_, 'tcx> { +impl<'tcx, C> Iterator for Postorder<'_, 'tcx, C> +where + C: Customization<'tcx>, +{ type Item = BasicBlock; fn next(&mut self) -> Option { @@ -232,6 +241,40 @@ pub fn postorder<'a, 'tcx>( reverse_postorder(body).rev() } +/// Lets us plug in some additional logic and data into a Postorder traversal. Or not. +pub trait Customization<'tcx>: Copy { + fn successors<'a>(_: &'a BasicBlockData<'tcx>, _: Self) -> Successors<'a>; +} + +impl<'tcx> Customization<'tcx> for () { + fn successors<'a>(data: &'a BasicBlockData<'tcx>, _: ()) -> Successors<'a> { + data.terminator().successors() + } +} + +impl<'tcx> Customization<'tcx> for (TyCtxt<'tcx>, Instance<'tcx>) { + fn successors<'a>( + data: &'a BasicBlockData<'tcx>, + (tcx, instance): (TyCtxt<'tcx>, Instance<'tcx>), + ) -> Successors<'a> { + data.mono_successors(tcx, instance) + } +} + +pub fn mono_reachable_reverse_postorder<'a, 'tcx>( + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> Vec { + let mut iter = Postorder::new(&body.basic_blocks, START_BLOCK, (tcx, instance)); + let mut items = Vec::with_capacity(body.basic_blocks.len()); + while let Some(block) = iter.next() { + items.push(block); + } + items.reverse(); + items +} + /// Returns an iterator over all basic blocks reachable from the `START_BLOCK` in no particular /// order. /// @@ -358,14 +401,8 @@ impl<'a, 'tcx> Iterator for MonoReachable<'a, 'tcx> { let data = &self.body[idx]; - if let Some((bits, targets)) = - Body::try_const_mono_switchint(self.tcx, self.instance, data) - { - let target = targets.target_for_value(bits); - self.add_work([target]); - } else { - self.add_work(data.terminator().successors()); - } + let targets = data.mono_successors(self.tcx, self.instance); + self.add_work(targets); return Some((idx, data)); } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index bd20e6aa00537..48bf4ffced0ce 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -1,6 +1,8 @@ use std::intrinsics::transmute_unchecked; use std::mem::MaybeUninit; +use rustc_span::ErrorGuaranteed; + use crate::query::CyclePlaceholder; use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty}; @@ -216,6 +218,10 @@ impl EraseType for (&'_ T0, &'_ [T1]) { type Result = [u8; size_of::<(&'static (), &'static [()])>()]; } +impl EraseType for (&'_ T0, Result<(), ErrorGuaranteed>) { + type Result = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()]; +} + macro_rules! trivial { ($($ty:ty),+ $(,)?) => { $( diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 6562d46d7b866..80adbe74fe702 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -1,10 +1,10 @@ //! Defines the set of legal keys that can be used in queries. -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, ModDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId}; use rustc_hir::hir_id::{HirId, OwnerId}; use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache}; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi; use crate::infer::canonical::Canonical; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d6bdc1af0d2ca..9609ef46d5c31 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -12,8 +12,8 @@ use std::path::PathBuf; use std::sync::Arc; use rustc_arena::TypedArena; -use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::StrippedCfgItem; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; @@ -30,16 +30,16 @@ use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate}; use rustc_index::IndexVec; use rustc_macros::rustc_queries; use rustc_query_system::ich::StableHashingContext; -use rustc_query_system::query::{try_get_cached, QueryCache, QueryMode, QueryState}; +use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached}; +use rustc_session::Limits; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{ CrateDepKind, CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib, }; use rustc_session::lint::LintExpectationId; -use rustc_session::Limits; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi; use rustc_target::spec::PanicStrategy; use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; @@ -59,9 +59,9 @@ use crate::mir::interpret::{ EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput, }; use crate::mir::mono::CodegenUnit; -use crate::query::erase::{erase, restore, Erase}; +use crate::query::erase::{Erase, erase, restore}; use crate::query::plumbing::{ - query_ensure, query_ensure_error_guaranteed, query_get_at, CyclePlaceholder, DynamicQuery, + CyclePlaceholder, DynamicQuery, query_ensure, query_ensure_error_guaranteed, query_get_at, }; use crate::traits::query::{ CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal, @@ -70,12 +70,12 @@ use crate::traits::query::{ MethodAutoderefStepsResult, NoSolution, NormalizationResult, OutlivesBound, }; use crate::traits::{ - specialization_graph, CodegenObligationError, EvaluationResult, ImplSource, - ObjectSafetyViolation, ObligationCause, OverflowError, WellFormedLoc, + CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause, + OverflowError, WellFormedLoc, specialization_graph, }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; -use crate::ty::print::{describe_as_module, PrintTraitRefExt}; +use crate::ty::print::{PrintTraitRefExt, describe_as_module}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{ self, CrateInherentImpls, GenericArg, GenericArgsRef, ParamEnvAnd, Ty, TyCtxt, TyCtxtFeed, @@ -327,7 +327,7 @@ rustc_queries! { } } - /// Returns the list of bounds that are required to be satsified + /// Returns the list of bounds that are required to be satisfied /// by a implementation or definition. For associated types, these /// must be satisfied for an implementation to be well-formed, /// and for opaque types, these are required to be satisfied by @@ -881,13 +881,13 @@ rustc_queries! { /// Maps a `DefId` of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - query inherent_impls(key: DefId) -> Result<&'tcx [DefId], ErrorGuaranteed> { + query inherent_impls(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - query incoherent_impls(key: SimplifiedType) -> Result<&'tcx [DefId], ErrorGuaranteed> { + query incoherent_impls(key: SimplifiedType) -> &'tcx [DefId] { desc { |tcx| "collecting all inherent impls for `{:?}`", key } } @@ -1017,8 +1017,14 @@ rustc_queries! { /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. - query crate_inherent_impls(k: ()) -> Result<&'tcx CrateInherentImpls, ErrorGuaranteed> { + query crate_inherent_impls(k: ()) -> (&'tcx CrateInherentImpls, Result<(), ErrorGuaranteed>) { desc { "finding all inherent impls defined in crate" } + } + + /// Checks all types in the crate for overlap in their inherent impls. Reports errors. + /// Not meant to be used directly outside of coherence. + query crate_inherent_impls_validity_check(_: ()) -> Result<(), ErrorGuaranteed> { + desc { "check for inherent impls that should not be defined in crate" } ensure_forwards_result_if_red } @@ -1715,7 +1721,7 @@ rustc_queries! { /// /// Do not call this directly, but instead use the `incoherent_impls` query. /// This query is only used to get the data necessary for that query. - query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> Result<&'tcx [DefId], ErrorGuaranteed> { + query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> &'tcx [DefId] { desc { |tcx| "collecting all impls for a type in a crate" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index ca52358218e92..06c9ebc87b5ab 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -6,7 +6,7 @@ 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::{UnordMap, UnordSet}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId}; use rustc_hir::definitions::DefPathHash; use rustc_index::{Idx, IndexVec}; use rustc_macros::{Decodable, Encodable}; @@ -328,18 +328,15 @@ impl<'sess> OnDiskCache<'sess> { // Encode the file footer. let footer_pos = encoder.position() as u64; - encoder.encode_tagged( - TAG_FILE_FOOTER, - &Footer { - file_index_to_stable_id, - query_result_index, - side_effects_index, - interpret_alloc_index, - syntax_contexts, - expn_data, - foreign_expn_data, - }, - ); + encoder.encode_tagged(TAG_FILE_FOOTER, &Footer { + file_index_to_stable_id, + query_result_index, + side_effects_index, + interpret_alloc_index, + syntax_contexts, + expn_data, + foreign_expn_data, + }); // Encode the position of the footer as the last 8 bytes of the // file so we know where to look for it. diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index c9bd702cce340..564d274bc8b1e 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -5,11 +5,11 @@ use rustc_data_structures::sync::{AtomicU64, WorkerLocal}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::OwnerId; use rustc_macros::HashStable; +use rustc_query_system::HandleCycleError; use rustc_query_system::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; pub(crate) use rustc_query_system::query::QueryJobId; use rustc_query_system::query::*; -use rustc_query_system::HandleCycleError; -use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use crate::dep_graph; use crate::dep_graph::DepKind; @@ -337,6 +337,7 @@ macro_rules! define_callbacks { // Ensure that values grow no larger than 64 bytes by accident. // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] + #[cfg(not(feature = "rustc_randomized_layouts"))] const _: () = { if mem::size_of::>() > 64 { panic!("{}", concat!( diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index aca1390935ef1..e614d41899a0e 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -16,7 +16,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; -use rustc_index::{newtype_index, IndexVec}; +use rustc_index::{IndexVec, newtype_index}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable}; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; @@ -338,6 +338,8 @@ pub enum ExprKind<'tcx> { PointerCoercion { cast: PointerCoercion, source: ExprId, + /// Whether this coercion is written with an `as` cast in the source code. + is_from_as_cast: bool, }, /// A `loop` expression. Loop { @@ -453,12 +455,14 @@ pub enum ExprKind<'tcx> { source: ExprId, /// Type that the user gave to this expression user_ty: UserTy<'tcx>, + user_ty_span: Span, }, - /// A type ascription on a value, e.g. `42: i32`. + /// A type ascription on a value, e.g. `type_ascribe!(42, i32)` or `42 as i32`. ValueTypeAscription { source: ExprId, /// Type that the user gave to this expression user_ty: UserTy<'tcx>, + user_ty_span: Span, }, /// A closure definition. Closure(Box>), diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index e246ecebbec0b..58e2ebaeaf8df 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -68,7 +68,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( Cast { source } => visitor.visit_expr(&visitor.thir()[source]), Use { source } => visitor.visit_expr(&visitor.thir()[source]), NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), - PointerCoercion { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + PointerCoercion { source, cast: _, is_from_as_cast: _ } => { + visitor.visit_expr(&visitor.thir()[source]) + } Let { expr, ref pat } => { visitor.visit_expr(&visitor.thir()[expr]); visitor.visit_pat(pat); @@ -129,7 +131,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_expr(&visitor.thir()[base.base]); } } - PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { + PlaceTypeAscription { source, user_ty: _, user_ty_span: _ } + | ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => { visitor.visit_expr(&visitor.thir()[source]) } Closure(box ClosureExpr { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a3277fb96d229..c3295a9ce51cc 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -14,17 +14,17 @@ use std::hash::{Hash, Hasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::HirId; +use rustc_hir::def_id::DefId; use rustc_macros::{ Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, }; -use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; // FIXME: Remove this import and import via `solve::` pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal}; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; use crate::mir::ConstraintCategory; diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 1236c9efb41cf..41a20e89cbf78 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -35,6 +35,9 @@ pub enum PointerCoercion { /// type. Codegen backends and miri figure out what has to be done /// based on the precise source/target type at hand. Unsize, + + /// Go from a pointer-like type to a `dyn*` object. + DynStar, } /// Represents coercing a value to a different type of value. @@ -102,8 +105,8 @@ pub enum Adjust<'tcx> { Pointer(PointerCoercion), - /// Cast into a dyn* object. - DynStar, + /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`. + ReborrowPin(ty::Region<'tcx>, hir::Mutability), } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 204f61b4804e4..8f89f5c25afb4 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -17,7 +17,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; use rustc_session::DataTypeKind; use rustc_span::symbol::sym; -use rustc_target::abi::{ReprOptions, VariantIdx, FIRST_VARIANT}; +use rustc_target::abi::{FIRST_VARIANT, ReprOptions, VariantIdx}; use tracing::{debug, info, trace}; use super::{ diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index 46f3765953678..b1316ceef5ac7 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -34,15 +34,12 @@ pub enum CastTy<'tcx> { FnPtr, /// Raw pointers. Ptr(ty::TypeAndMut<'tcx>), - /// Casting into a `dyn*` value. - DynStar, } /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) /// (or rustc_hir_analysis/check/cast.rs). #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum CastKind { - CoercionCast, PtrPtrCast, PtrAddrCast, AddrPtrCast, @@ -53,7 +50,6 @@ pub enum CastKind { ArrayPtrCast, FnPtrPtrCast, FnPtrAddrCast, - DynStarCast, } impl<'tcx> CastTy<'tcx> { @@ -71,7 +67,6 @@ impl<'tcx> CastTy<'tcx> { ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::RawPtr(ty, mutbl) => Some(CastTy::Ptr(ty::TypeAndMut { ty, mutbl })), ty::FnPtr(..) => Some(CastTy::FnPtr), - ty::Dynamic(_, _, ty::DynStar) => Some(CastTy::DynStar), _ => None, } } @@ -86,7 +81,6 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin mir::CastKind::PointerExposeProvenance } (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance, - (_, Some(CastTy::DynStar)) => mir::CastKind::DynStar, (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt, (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr, diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 8eb3c0156796a..9ee8294291123 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -3,8 +3,8 @@ use std::fmt::Write; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; use rustc_hir::HirId; +use rustc_hir::def_id::LocalDefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::def_id::LocalDefIdMap; use rustc_span::symbol::Ident; @@ -88,9 +88,6 @@ pub struct CapturedPlace<'tcx> { /// Represents if `place` can be mutated or not. pub mutability: hir::Mutability, - - /// Region of the resulting reference if the upvar is captured by ref. - pub region: Option>, } impl<'tcx> CapturedPlace<'tcx> { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 46203ee150f64..7e533bc4291a1 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -165,8 +165,7 @@ impl<'tcx, E: TyEncoder>> Encodable for AllocId { impl<'tcx, E: TyEncoder>> Encodable for CtfeProvenance { fn encode(&self, e: &mut E) { - self.alloc_id().encode(e); - self.immutable().encode(e); + self.into_parts().encode(e); } } @@ -295,10 +294,8 @@ impl<'tcx, D: TyDecoder>> Decodable for AllocId { impl<'tcx, D: TyDecoder>> Decodable for CtfeProvenance { fn decode(decoder: &mut D) -> Self { - let alloc_id: AllocId = Decodable::decode(decoder); - let prov = CtfeProvenance::from(alloc_id); - let immutable: bool = Decodable::decode(decoder); - if immutable { prov.as_immutable() } else { prov } + let parts = Decodable::decode(decoder); + CtfeProvenance::from_parts(parts) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 362ff8e988d36..73d0acf95f4f5 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -18,7 +18,7 @@ mod valtree; pub use int::*; pub use kind::*; -use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; pub use valtree::*; pub type ConstKind<'tcx> = ir::ConstKind>; @@ -242,13 +242,10 @@ impl<'tcx> Const<'tcx> { match Self::try_from_lit_or_param(tcx, ty, expr) { Some(v) => v, - None => ty::Const::new_unevaluated( - tcx, - ty::UnevaluatedConst { - def: def.to_def_id(), - args: GenericArgs::identity_for_item(tcx, def.to_def_id()), - }, - ), + None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { + def: def.to_def_id(), + args: GenericArgs::identity_for_item(tcx, def.to_def_id()), + }), } } @@ -295,20 +292,12 @@ impl<'tcx> Const<'tcx> { _ => expr, }; - if let hir::ExprKind::Path( - qpath @ hir::QPath::Resolved( - _, - &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, - ), - ) = expr.kind + if let hir::ExprKind::Path(hir::QPath::Resolved( + _, + &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, + )) = expr.kind { - if tcx.features().const_arg_path { - span_bug!( - expr.span, - "try_from_lit: received const param which shouldn't be possible" - ); - } - return Some(Const::from_param(tcx, qpath, expr.hir_id)); + span_bug!(expr.span, "try_from_lit: received const param which shouldn't be possible"); }; let lit_input = match expr.kind { @@ -396,7 +385,7 @@ impl<'tcx> Const<'tcx> { Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c)) } Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)), - Err(err) => Err(Either::Right(err.into())), + Err(err) => Err(Either::Right(err)), } } ConstKind::Value(ty, val) => Ok((ty, val)), @@ -529,6 +518,10 @@ impl<'tcx> Const<'tcx> { self.try_to_valtree()?.try_to_scalar() } + pub fn try_to_bool(self) -> Option { + self.try_to_scalar()?.to_bool().ok() + } + #[inline] pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { self.try_to_valtree()?.try_to_target_usize(tcx) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 0024a2ae756ea..1732374ab8c26 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -1,8 +1,8 @@ use std::fmt; use std::num::NonZero; -use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_target::abi::Size; diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index c7c2e8afa1e71..91b764ae1d451 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,6 +1,6 @@ use std::assert_matches::assert_matches; -use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension}; use super::Const; use crate::mir; @@ -31,13 +31,10 @@ impl<'tcx> ty::UnevaluatedConst<'tcx> { // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that // we can call `infcx.const_eval_resolve` which handles inference variables. if (param_env, self).has_non_region_infer() { - ( - tcx.param_env(self.def), - ty::UnevaluatedConst { - def: self.def, - args: ty::GenericArgs::identity_for_item(tcx, self.def), - }, - ) + (tcx.param_env(self.def), ty::UnevaluatedConst { + def: self.def, + args: ty::GenericArgs::identity_for_item(tcx, self.def), + }) } else { (tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self)) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 43dda252f835e..f017216489d0c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -30,7 +30,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::Definitions; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; @@ -45,17 +45,17 @@ use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; use rustc_session::lint::Lint; use rustc_session::{Limit, MetadataKind, Session}; -use rustc_span::def_id::{DefPathHash, StableCrateId, CRATE_DEF_ID}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; +use rustc_type_ir::TyKind::*; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::solve::SolverMode; -use rustc_type_ir::TyKind::*; -use rustc_type_ir::{search_graph, CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; +use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; use tracing::{debug, instrument}; use crate::arena::Arena; @@ -181,6 +181,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } } + fn evaluation_is_concurrent(&self) -> bool { + self.sess.threads() > 1 + } + fn expand_abstract_consts>>(self, t: T) -> T { self.expand_abstract_consts(t) } @@ -426,7 +430,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { let simp = ty::fast_reject::simplify_type( tcx, self_ty, - ty::fast_reject::TreatParams::ForLookup, + ty::fast_reject::TreatParams::AsRigid, ) .unwrap(); consider_impls_for_simplified_type(simp); @@ -1011,10 +1015,10 @@ impl<'tcx> CommonLifetimes<'tcx> { .map(|i| { (0..NUM_PREINTERNED_RE_LATE_BOUNDS_V) .map(|v| { - mk(ty::ReBound( - ty::DebruijnIndex::from(i), - ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BrAnon }, - )) + mk(ty::ReBound(ty::DebruijnIndex::from(i), ty::BoundRegion { + var: ty::BoundVar::from(v), + kind: ty::BrAnon, + })) }) .collect() }) @@ -1475,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> { /// provides a `TyCtxt`. /// /// By only providing the `TyCtxt` inside of the closure we enforce that the type - /// context and any interned alue (types, args, etc.) can only be used while `ty::tls` + /// context and any interned value (types, args, etc.) can only be used while `ty::tls` /// has a valid reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( s: &'tcx Session, @@ -2003,7 +2007,7 @@ impl<'tcx> TyCtxt<'tcx> { )); } } - return None; + None } /// Checks if the bound region is in Impl Item. @@ -2602,33 +2606,31 @@ impl<'tcx> TyCtxt<'tcx> { /// With `cfg(debug_assertions)`, assert that args are compatible with their generics, /// and print out the args if not. pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { - if cfg!(debug_assertions) { - if !self.check_args_compatible(def_id, args) { - if let DefKind::AssocTy = self.def_kind(def_id) - && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) - { - bug!( - "args not compatible with generics for {}: args={:#?}, generics={:#?}", - self.def_path_str(def_id), - args, - // Make `[Self, GAT_ARGS...]` (this could be simplified) - self.mk_args_from_iter( - [self.types.self_param.into()].into_iter().chain( - self.generics_of(def_id) - .own_args(ty::GenericArgs::identity_for_item(self, def_id)) - .iter() - .copied() - ) + if cfg!(debug_assertions) && !self.check_args_compatible(def_id, args) { + if let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) + { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + // Make `[Self, GAT_ARGS...]` (this could be simplified) + self.mk_args_from_iter( + [self.types.self_param.into()].into_iter().chain( + self.generics_of(def_id) + .own_args(ty::GenericArgs::identity_for_item(self, def_id)) + .iter() + .copied() ) - ); - } else { - bug!( - "args not compatible with generics for {}: args={:#?}, generics={:#?}", - self.def_path_str(def_id), - args, - ty::GenericArgs::identity_for_item(self, def_id) - ); - } + ) + ); + } else { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + ty::GenericArgs::identity_for_item(self, def_id) + ); } } } @@ -3050,15 +3052,12 @@ impl<'tcx> TyCtxt<'tcx> { } let generics = self.generics_of(new_parent); - return ty::Region::new_early_param( - self, - ty::EarlyParamRegion { - index: generics - .param_def_id_to_index(self, ebv.to_def_id()) - .expect("early-bound var should be present in fn generics"), - name: self.item_name(ebv.to_def_id()), - }, - ); + return ty::Region::new_early_param(self, ty::EarlyParamRegion { + index: generics + .param_def_id_to_index(self, ebv.to_def_id()) + .expect("early-bound var should be present in fn generics"), + name: self.item_name(ebv.to_def_id()), + }); } Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { let new_parent = self.local_parent(lbv); @@ -3169,7 +3168,7 @@ impl<'tcx> TyCtxt<'tcx> { self.impl_trait_header(def_id).map_or(ty::ImplPolarity::Positive, |h| h.polarity) } - pub fn needs_coroutine_by_move_body_def_id(self, def_id: LocalDefId) -> bool { + pub fn needs_coroutine_by_move_body_def_id(self, def_id: DefId) -> bool { if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) = self.coroutine_kind(def_id) && let ty::Coroutine(_, args) = self.type_of(def_id).instantiate_identity().kind() @@ -3183,8 +3182,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]` pub fn do_not_recommend_impl(self, def_id: DefId) -> bool { - matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true }) - && self.impl_trait_header(def_id).is_some_and(|header| header.do_not_recommend) + self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some() } } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index c14dadc68c903..992eb264163ba 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -5,7 +5,7 @@ use std::fmt::Write; use std::ops::ControlFlow; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{into_diag_arg_using_display, Applicability, Diag, DiagArgValue, IntoDiagArg}; +use rustc_errors::{Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem, PredicateOrigin, WherePredicate}; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index d974a86a3036f..b02eff3bfd6a3 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{CtorOf, DefKind}; use rustc_macros::extension; pub use rustc_type_ir::error::ExpectedFound; -use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter}; +use crate::ty::print::{FmtPrinter, PrettyPrinter, with_forced_trimmed_paths}; use crate::ty::{self, Ty, TyCtxt}; pub type TypeError<'tcx> = rustc_type_ir::error::TypeError>; diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 91344c4e39c8b..2945a0be424f8 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -3,6 +3,14 @@ pub use rustc_type_ir::fast_reject::*; use super::TyCtxt; -pub type DeepRejectCtxt<'tcx> = rustc_type_ir::fast_reject::DeepRejectCtxt>; +pub type DeepRejectCtxt< + 'tcx, + const INSTANTIATE_LHS_WITH_INFER: bool, + const INSTANTIATE_RHS_WITH_INFER: bool, +> = rustc_type_ir::fast_reject::DeepRejectCtxt< + TyCtxt<'tcx>, + INSTANTIATE_LHS_WITH_INFER, + INSTANTIATE_RHS_WITH_INFER, +>; pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType; diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 7892ef818194a..2ee7497497aa9 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; pub use rustc_type_ir::fold::{ - shift_region, shift_vars, FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, + FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region, shift_vars, }; use tracing::{debug, instrument}; @@ -336,26 +336,21 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable>, { let shift_bv = |bv: ty::BoundVar| ty::BoundVar::from_usize(bv.as_usize() + bound_vars); - self.replace_escaping_bound_vars_uncached( - value, - FnMutDelegate { - regions: &mut |r: ty::BoundRegion| { - ty::Region::new_bound( - self, - ty::INNERMOST, - ty::BoundRegion { var: shift_bv(r.var), kind: r.kind }, - ) - }, - types: &mut |t: ty::BoundTy| { - Ty::new_bound( - self, - ty::INNERMOST, - ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, - ) - }, - consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)), + self.replace_escaping_bound_vars_uncached(value, FnMutDelegate { + regions: &mut |r: ty::BoundRegion| { + ty::Region::new_bound(self, ty::INNERMOST, ty::BoundRegion { + var: shift_bv(r.var), + kind: r.kind, + }) }, - ) + types: &mut |t: ty::BoundTy| { + Ty::new_bound(self, ty::INNERMOST, ty::BoundTy { + var: shift_bv(t.var), + kind: t.kind, + }) + }, + consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)), + }) } /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 80c31e236e2c2..daf1362e25c1f 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -11,7 +11,7 @@ use rustc_ast_ir::walk_visitable_list; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; -use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension}; use rustc_serialize::{Decodable, Encodable}; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index bbc696e0f0814..660686f4aa280 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -2,8 +2,8 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, kw}; use tracing::instrument; use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; @@ -255,7 +255,9 @@ impl<'tcx> Generics { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Lifetime => param, - _ => bug!("expected lifetime parameter, but found another generic parameter"), + _ => { + bug!("expected lifetime parameter, but found another generic parameter: {param:#?}") + } } } @@ -264,7 +266,7 @@ impl<'tcx> Generics { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Type { .. } => param, - _ => bug!("expected type parameter, but found another generic parameter"), + _ => bug!("expected type parameter, but found another generic parameter: {param:#?}"), } } @@ -273,7 +275,7 @@ impl<'tcx> Generics { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Const { .. } => param, - _ => bug!("expected const parameter, but found another generic parameter"), + _ => bug!("expected const parameter, but found another generic parameter: {param:#?}"), } } diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index b5b7b8bcfef00..5f6305bb48ad4 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -75,11 +75,9 @@ impl<'a> HashStable> for mir::interpret::AllocId { } } -// CtfeProvenance is an AllocId and a bool. impl<'a> HashStable> for mir::interpret::CtfeProvenance { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.alloc_id().hash_stable(hcx, hasher); - self.immutable().hash_stable(hcx, hasher); + self.into_parts().hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 698104b0462e3..dd00db8635f4d 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -81,10 +81,6 @@ impl<'tcx> VariantDef { adt: ty::AdtDef<'_>, ) -> InhabitedPredicate<'tcx> { debug_assert!(!adt.is_union()); - if self.is_field_list_non_exhaustive() && !self.def_id.is_local() { - // Non-exhaustive variants from other crates are always considered inhabited. - return InhabitedPredicate::True; - } InhabitedPredicate::all( tcx, self.fields.iter().map(|field| { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 7d5f0f1e9c415..bfef4c4c8c6b9 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -12,12 +12,12 @@ use rustc_index::bit_set::FiniteBitSet; use rustc_macros::{Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable}; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use tracing::{debug, instrument}; use crate::error; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::ty::print::{shrunk_instance_name, FmtPrinter, Printer}; +use crate::ty::print::{FmtPrinter, Printer, shrunk_instance_name}; use crate::ty::{ self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -38,7 +38,7 @@ pub struct Instance<'tcx> { pub args: GenericArgsRef<'tcx>, } -/// Describes why a `ReifyShim` was created. This is needed to distingish a ReifyShim created to +/// Describes why a `ReifyShim` was created. This is needed to distinguish a ReifyShim created to /// adjust for things like `#[track_caller]` in a vtable from a `ReifyShim` created to produce a /// function pointer from a vtable entry. /// Currently, this is only used when KCFI is enabled, as only KCFI needs to treat those two diff --git a/compiler/rustc_middle/src/ty/intrinsic.rs b/compiler/rustc_middle/src/ty/intrinsic.rs index 41a966da8aa49..ed0fb37d3b897 100644 --- a/compiler/rustc_middle/src/ty/intrinsic.rs +++ b/compiler/rustc_middle/src/ty/intrinsic.rs @@ -1,6 +1,6 @@ use rustc_macros::{Decodable, Encodable, HashStable}; -use rustc_span::def_id::DefId; use rustc_span::Symbol; +use rustc_span::def_id::DefId; use super::TyCtxt; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d0a9039441dc4..cf0c29e0c8c39 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::num::NonZero; use std::ops::Bound; use std::{cmp, fmt}; @@ -8,13 +7,13 @@ use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::LangItem; +use rustc_hir::def_id::DefId; use rustc_index::IndexVec; -use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_session::config::OptLevel; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; +use rustc_span::symbol::{Symbol, sym}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::*; use rustc_target::spec::abi::Abi as SpecAbi; @@ -265,7 +264,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { match *self { LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"), LayoutError::SizeOverflow(ty) => { - write!(f, "values of the type `{ty}` are too big for the current architecture") + write!(f, "values of the type `{ty}` are too big for the target architecture") } LayoutError::NormalizationFailure(t, e) => write!( f, @@ -286,20 +285,14 @@ impl<'tcx> IntoDiagArg for LayoutError<'tcx> { } #[derive(Clone, Copy)] -pub struct LayoutCx<'tcx, C> { - pub tcx: C, +pub struct LayoutCx<'tcx> { + pub calc: LayoutCalculator>, pub param_env: ty::ParamEnv<'tcx>, } -impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> { - type TargetDataLayoutRef = &'tcx TargetDataLayout; - - fn delayed_bug(&self, txt: impl Into>) { - self.tcx.dcx().delayed_bug(txt); - } - - fn current_data_layout(&self) -> Self::TargetDataLayoutRef { - &self.tcx.data_layout +impl<'tcx> LayoutCx<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { + Self { calc: LayoutCalculator::new(tcx), param_env } } } @@ -568,33 +561,33 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> { } } -impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> { +impl<'tcx> HasParamEnv<'tcx> for LayoutCx<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } } -impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> { +impl<'tcx> HasDataLayout for LayoutCx<'tcx> { fn data_layout(&self) -> &TargetDataLayout { - self.tcx.data_layout() + self.calc.cx.data_layout() } } -impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> { +impl<'tcx> HasTargetSpec for LayoutCx<'tcx> { fn target_spec(&self) -> &Target { - self.tcx.target_spec() + self.calc.cx.target_spec() } } -impl<'tcx, T: HasWasmCAbiOpt> HasWasmCAbiOpt for LayoutCx<'tcx, T> { +impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> { fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.tcx.wasm_c_abi_opt() + self.calc.cx.wasm_c_abi_opt() } } -impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { +impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx.tcx() + self.calc.cx } } @@ -634,7 +627,7 @@ pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>; pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> { /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be /// returned from `layout_of` (see also `handle_layout_err`). - type LayoutOfResult: MaybeResult>; + type LayoutOfResult: MaybeResult> = TyAndLayout<'tcx>; /// `Span` to use for `tcx.at(span)`, from `layout_of`. // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better? @@ -685,28 +678,9 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> { impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {} -impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { - type LayoutOfResult = Result, &'tcx LayoutError<'tcx>>; - - #[inline] - fn handle_layout_err( - &self, - err: LayoutError<'tcx>, - _: Span, - _: Ty<'tcx>, - ) -> &'tcx LayoutError<'tcx> { - self.tcx.arena.alloc(err) - } -} - -impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> { +impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> { type LayoutOfResult = Result, &'tcx LayoutError<'tcx>>; - #[inline] - fn layout_tcx_at_span(&self) -> Span { - self.tcx.span - } - #[inline] fn handle_layout_err( &self, @@ -714,7 +688,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> { _: Span, _: Ty<'tcx>, ) -> &'tcx LayoutError<'tcx> { - self.tcx.arena.alloc(err) + self.tcx().arena.alloc(err) } } @@ -1075,11 +1049,13 @@ where // the raw pointer, so size and align are set to the boxed type, but `pointee.safe` // will still be `None`. if let Some(ref mut pointee) = result { - if offset.bytes() == 0 && this.ty.is_box() { + if offset.bytes() == 0 + && let Some(boxed_ty) = this.ty.boxed_ty() + { debug_assert!(pointee.safe.is_none()); let optimize = tcx.sess.opts.optimize != OptLevel::No; pointee.safe = Some(PointerKind::Box { - unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()), + unpin: optimize && boxed_ty.is_unpin(tcx, cx.param_env()), global: this.ty.is_box_global(tcx), }); } @@ -1181,10 +1157,10 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> // // This is not part of `codegen_fn_attrs` as it can differ between crates // and therefore cannot be computed in core. - if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort { - if tcx.is_lang_item(did, LangItem::DropInPlace) { - return false; - } + if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort + && tcx.is_lang_item(did, LangItem::DropInPlace) + { + return false; } } @@ -1215,6 +1191,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> | RiscvInterruptM | RiscvInterruptS | CCmseNonSecureCall + | CCmseNonSecureEntry | Unadjusted => false, Rust | RustCall | RustCold | RustIntrinsic => { tcx.sess.panic_strategy() == PanicStrategy::Unwind @@ -1257,7 +1234,7 @@ pub enum FnAbiRequest<'tcx> { pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> { /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`). - type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>; + type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>> = &'tcx FnAbi<'tcx, Ty<'tcx>>; /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`). @@ -1318,11 +1295,10 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { // However, we don't do this early in order to avoid calling // `def_span` unconditionally (which may have a perf penalty). let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) }; - self.handle_fn_abi_err( - *err, - span, - FnAbiRequest::OfInstance { instance, extra_args }, - ) + self.handle_fn_abi_err(*err, span, FnAbiRequest::OfInstance { + instance, + extra_args, + }) }), ) } @@ -1340,7 +1316,7 @@ impl<'tcx> TyCtxt<'tcx> { where I: Iterator, { - let cx = LayoutCx { tcx: self, param_env }; + let cx = LayoutCx::new(self, param_env); let mut offset = Size::ZERO; for (variant, field) in indices { diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index af76d5b7d9267..ec9ca65dbda83 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -4,7 +4,7 @@ use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::{fmt, iter, mem, ptr, slice}; -use rustc_data_structures::aligned::{align_of, Aligned}; +use rustc_data_structures::aligned::{Aligned, align_of}; #[cfg(parallel_compiler)] use rustc_data_structures::sync::DynSync; use rustc_serialize::{Encodable, Encoder}; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e41ea7507efff..2b1212a5eb567 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -26,51 +26,55 @@ pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; -pub use rustc_ast_ir::{try_visit, Movability, Mutability}; +pub use rustc_ast_ir::{Movability, Mutability, try_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_errors::{Diag, ErrorGuaranteed, StashKey}; +use rustc_hir::LangItem; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_index::IndexVec; use rustc_macros::{ - extension, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, - TypeVisitable, + Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, + extension, }; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; -pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::ConstKind::{ Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt, Placeholder as PlaceholderCt, Unevaluated, Value, }; +pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::*; use tracing::{debug, instrument}; pub use vtable::*; use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; +pub use self::AssocItemContainer::*; +pub use self::BorrowKind::*; +pub use self::IntVarValue::*; pub use self::closure::{ - analyze_coroutine_closure_captures, is_ancestor_or_same_capture, place_to_string_for_capture, - BorrowKind, CaptureInfo, CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, - MinCaptureList, RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath, - CAPTURE_STRUCT_LOCAL, + BorrowKind, CAPTURE_STRUCT_LOCAL, CaptureInfo, CapturedPlace, ClosureTypeInfo, + MinCaptureInformationMap, MinCaptureList, RootVariableMinCaptureList, UpvarCapture, UpvarId, + UpvarPath, analyze_coroutine_closure_captures, is_ancestor_or_same_capture, + place_to_string_for_capture, }; pub use self::consts::{ Const, ConstInt, ConstKind, Expr, ExprKind, FeedConstTy, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ - tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, - TyCtxt, TyCtxtFeed, + CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, + TyCtxtFeed, tls, }; pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; pub use self::instance::{Instance, InstanceKind, ReifyReason, ShortInstance, UnusedGenericParams}; @@ -103,9 +107,6 @@ pub use self::typeck_results::{ TypeckResults, UserType, UserTypeAnnotationIndex, }; pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -pub use self::AssocItemContainer::*; -pub use self::BorrowKind::*; -pub use self::IntVarValue::*; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; @@ -262,7 +263,6 @@ pub struct ImplTraitHeader<'tcx> { pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>, pub polarity: ImplPolarity, pub safety: hir::Safety, - pub do_not_recommend: bool, } #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] @@ -1570,8 +1570,15 @@ impl<'tcx> TyCtxt<'tcx> { flags.insert(ReprFlags::RANDOMIZE_LAYOUT); } + // box is special, on the one hand the compiler assumes an ordered layout, with the pointer + // always at offset zero. On the other hand we want scalar abi optimizations. + let is_box = self.is_lang_item(did.to_def_id(), LangItem::OwnedBox); + // This is here instead of layout because the choice must make it into metadata. - if !self.consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did))) { + if is_box + || !self + .consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did))) + { flags.insert(ReprFlags::IS_LINEAR); } @@ -1789,6 +1796,37 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Get an attribute from the diagnostic attribute namespace + /// + /// This function requests an attribute with the following structure: + /// + /// `#[diagnostic::$attr]` + /// + /// This function performs feature checking, so if an attribute is returned + /// it can be used by the consumer + pub fn get_diagnostic_attr( + self, + did: impl Into, + attr: Symbol, + ) -> Option<&'tcx ast::Attribute> { + let did: DefId = did.into(); + if did.as_local().is_some() { + // it's a crate local item, we need to check feature flags + if rustc_feature::is_stable_diagnostic_attribute(attr, self.features()) { + self.get_attrs_by_path(did, &[sym::diagnostic, sym::do_not_recommend]).next() + } else { + None + } + } else { + // we filter out unstable diagnostic attributes before + // encoding attributes + debug_assert!(rustc_feature::encode_cross_crate(attr)); + self.item_attrs(did) + .iter() + .find(|a| matches!(a.path().as_ref(), [sym::diagnostic, a] if *a == attr)) + } + } + pub fn get_attrs_by_path<'attr>( self, did: DefId, @@ -1819,7 +1857,7 @@ impl<'tcx> TyCtxt<'tcx> { self.get_attrs(did, attr).next().is_some() } - /// Determines whether an item is annotated with a multi-segement attribute + /// Determines whether an item is annotated with a multi-segment attribute pub fn has_attrs_with_path(self, did: impl Into, attrs: &[Symbol]) -> bool { self.get_attrs_by_path(did.into(), attrs).next().is_some() } diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index d3f44326c272d..cf789807bb04a 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_span::def_id::DefId; use tracing::{debug, instrument, trace}; use crate::error::ConstNotUsedTraitAlias; diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 8e72505b86200..534a8c99c5adb 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -3,7 +3,7 @@ use std::cmp::Ordering; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; use rustc_hir::def_id::DefId; -use rustc_macros::{extension, HashStable}; +use rustc_macros::{HashStable, extension}; use rustc_type_ir as ir; use tracing::instrument; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f1ff90831b04f..5b4ee2791f8dd 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3,23 +3,23 @@ use std::fmt::{self, Write as _}; use std::iter; use std::ops::{Deref, DerefMut}; -use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; +use rustc_hir::LangItem; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; -use rustc_hir::def_id::{DefIdMap, DefIdSet, ModDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefIdMap, DefIdSet, LOCAL_CRATE, ModDefId}; use rustc_hir::definitions::{DefKey, DefPathDataName}; -use rustc_hir::LangItem; -use rustc_macros::{extension, Lift}; -use rustc_session::cstore::{ExternCrate, ExternCrateSource}; +use rustc_macros::{Lift, extension}; use rustc_session::Limit; -use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::FileNameDisplayPreference; +use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use rustc_type_ir::{elaborate, Upcast as _}; +use rustc_type_ir::{Upcast as _, elaborate}; use smallvec::SmallVec; // `pretty` is a separate module only for organization. @@ -1526,7 +1526,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let precedence = |binop: rustc_middle::mir::BinOp| { use rustc_ast::util::parser::AssocOp; - AssocOp::from_ast_binop(binop.to_hir_binop().into()).precedence() + AssocOp::from_ast_binop(binop.to_hir_binop()).precedence() }; let op_precedence = precedence(op); let formatted_op = op.to_hir_binop().as_str(); @@ -3361,10 +3361,8 @@ pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { // name. // // Any stable ordering would be fine here though. - if *v.get() != symbol { - if v.get().as_str() > symbol.as_str() { - v.insert(symbol); - } + if *v.get() != symbol && v.get().as_str() > symbol.as_str() { + v.insert(symbol); } } Vacant(v) => { diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index a2a961057771a..be4772e888f86 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -4,8 +4,8 @@ use rustc_data_structures::intern::Interned; use rustc_errors::MultiSpan; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{ErrorGuaranteed, DUMMY_SP}; +use rustc_span::symbol::{Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed}; use rustc_type_ir::RegionKind as IrRegionKind; pub use rustc_type_ir::RegionVid; use tracing::debug; @@ -431,7 +431,7 @@ impl BoundRegionKind { pub fn get_id(&self) -> Option { match *self { - BoundRegionKind::BrNamed(id, _) => return Some(id), + BoundRegionKind::BrNamed(id, _) => Some(id), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index bcab54cf8bad0..37dcf7c0d649f 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -41,7 +41,15 @@ impl RvalueScopes { debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]"); return Some(id); } - _ => id = p, + ScopeData::IfThenRescope => { + debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]"); + return Some(p); + } + ScopeData::Node + | ScopeData::CallSite + | ScopeData::Arguments + | ScopeData::IfThen + | ScopeData::Remainder(_) => id = p, } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 80b33c2cda929..cd9ff9b60d859 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -16,7 +16,7 @@ use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Pattern, Region}; use crate::mir::interpret; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; -use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; +use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b144fd0feb00e..db9978a7f5334 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -11,15 +11,15 @@ use hir::def::{CtorKind, DefKind}; use rustc_data_structures::captures::Captures; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::LangItem; -use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; +use rustc_hir::def_id::DefId; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension}; +use rustc_span::symbol::{Symbol, sym}; +use rustc_span::{DUMMY_SP, Span}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_target::spec::abi; -use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::TyKind::*; +use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; @@ -1091,29 +1091,21 @@ impl<'tcx> Ty<'tcx> { } pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { - match self.kind() { - Adt(def, args) => { - assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type"); - let variant = def.non_enum_variant(); - let f0_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args); - - match f0_ty.kind() { - // If the first field is an array, we assume it is the only field and its - // elements are the SIMD components. - Array(f0_elem_ty, f0_len) => { - // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112 - // The way we evaluate the `N` in `[T; N]` here only works since we use - // `simd_size_and_type` post-monomorphization. It will probably start to ICE - // if we use it in generic code. See the `simd-array-trait` ui test. - (f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty) - } - // Otherwise, the fields of this Adt are the SIMD components (and we assume they - // all have the same type). - _ => (variant.fields.len() as u64, f0_ty), - } - } - _ => bug!("`simd_size_and_type` called on invalid type"), - } + let Adt(def, args) = self.kind() else { + bug!("`simd_size_and_type` called on invalid type") + }; + assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type"); + let variant = def.non_enum_variant(); + assert_eq!(variant.fields.len(), 1); + let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args); + let Array(f0_elem_ty, f0_len) = field_ty.kind() else { + bug!("Simd type has non-array field type {field_ty:?}") + }; + // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112 + // The way we evaluate the `N` in `[T; N]` here only works since we use + // `simd_size_and_type` post-monomorphization. It will probably start to ICE + // if we use it in generic code. See the `simd-array-trait` ui test. + (f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty) } #[inline] @@ -1136,6 +1128,7 @@ impl<'tcx> Ty<'tcx> { } /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). + /// `Box` is *not* considered a pointer here! #[inline] pub fn is_any_ptr(self) -> bool { self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr() @@ -1170,14 +1163,19 @@ impl<'tcx> Ty<'tcx> { } } - /// Panics if called on any type other than `Box`. - pub fn boxed_ty(self) -> Ty<'tcx> { + pub fn boxed_ty(self) -> Option> { match self.kind() { - Adt(def, args) if def.is_box() => args.type_at(0), - _ => bug!("`boxed_ty` is called on non-box type {:?}", self), + Adt(def, args) if def.is_box() => Some(args.type_at(0)), + _ => None, } } + /// Panics if called on any type other than `Box`. + pub fn expect_boxed_ty(self) -> Ty<'tcx> { + self.boxed_ty() + .unwrap_or_else(|| bug!("`expect_boxed_ty` is called on non-box type {:?}", self)) + } + /// A scalar type is one that denotes an atomic datum, with no sub-components. /// (A RawPtr is scalar because it represents a non-managed pointer, so its /// contents are abstract to rustc.) @@ -1323,7 +1321,7 @@ impl<'tcx> Ty<'tcx> { /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. pub fn builtin_deref(self, explicit: bool) -> Option> { match *self.kind() { - Adt(def, _) if def.is_box() => Some(self.boxed_ty()), + _ if let Some(boxed) = self.boxed_ty() => Some(boxed), Ref(_, ty, _) => Some(ty), RawPtr(ty, _) if explicit => Some(ty), _ => None, @@ -1930,7 +1928,7 @@ impl<'tcx> Ty<'tcx> { /// Returns `true` when the outermost type cannot be further normalized, /// resolved, or instantiated. This includes all primitive types, but also - /// things like ADTs and trait objects, sice even if their arguments or + /// things like ADTs and trait objects, since even if their arguments or /// nested types may be further simplified, the outermost [`TyKind`] or /// type constructor remains the same. pub fn is_known_rigid(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index dfb137f738f1e..188107e5d5498 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -168,9 +168,9 @@ impl<'tcx> TyCtxt<'tcx> { // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option`, `Vec`, `ConcreteType` and so on. - // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using - // `TreatParams::AsCandidateKey` while actually adding them. - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup) { + // Note that we're using `TreatParams::AsRigid` to query `non_blanket_impls` while using + // `TreatParams::InstantiateWithInfer` while actually adding them. + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsRigid) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { f(impl_def_id); @@ -190,7 +190,9 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, ) -> impl Iterator + 'tcx { let impls = self.trait_impls_of(trait_def_id); - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) { + if let Some(simp) = + fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer) + { if let Some(impls) = impls.non_blanket_impls.get(&simp) { return impls.iter().copied(); } @@ -239,7 +241,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity(); if let Some(simplified_self_ty) = - fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey) + fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::InstantiateWithInfer) { impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); } else { @@ -251,30 +253,16 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } /// Query provider for `incoherent_impls`. -pub(super) fn incoherent_impls_provider( - tcx: TyCtxt<'_>, - simp: SimplifiedType, -) -> Result<&[DefId], ErrorGuaranteed> { +pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { let mut impls = Vec::new(); - - let mut res = Ok(()); for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) { - let incoherent_impls = match tcx.crate_incoherent_impls((cnum, simp)) { - Ok(impls) => impls, - Err(e) => { - res = Err(e); - continue; - } - }; - for &impl_def_id in incoherent_impls { + for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) { impls.push(impl_def_id) } } - debug!(?impls); - res?; - Ok(tcx.arena.alloc_slice(&impls)) + tcx.arena.alloc_slice(&impls) } pub(super) fn traits_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index a92bdb2eae0de..17280c3d0476f 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -23,8 +23,8 @@ use crate::hir::place::Place as HirPlace; use crate::infer::canonical::Canonical; use crate::traits::ObligationCause; use crate::ty::{ - self, tls, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, GenericArgs, - GenericArgsRef, Ty, UserArgs, + self, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, GenericArgs, + GenericArgsRef, Ty, UserArgs, tls, }; #[derive(TyEncodable, TyDecodable, Debug, HashStable)] diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index efbccca77c1f0..321b51289fb08 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -11,12 +11,12 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; -use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_session::Limit; use rustc_span::sym; use rustc_target::abi::{Float, Integer, IntegerType, Size}; use rustc_target::spec::abi::Abi; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument, trace}; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -571,7 +571,10 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `true` if `def_id` refers to a definition that does not have its own /// type-checking context, i.e. closure, coroutine or inline const. pub fn is_typeck_child(self, def_id: DefId) -> bool { - matches!(self.def_kind(def_id), DefKind::Closure | DefKind::InlineConst) + matches!( + self.def_kind(def_id), + DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody + ) } /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). @@ -1628,7 +1631,7 @@ impl<'tcx> ExplicitSelf<'tcx> { _ if is_self_ty(self_arg_ty) => ByValue, ty::Ref(region, ty, mutbl) if is_self_ty(ty) => ByReference(region, mutbl), ty::RawPtr(ty, mutbl) if is_self_ty(ty) => ByRawPointer(mutbl), - ty::Adt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox, + _ if self_arg_ty.boxed_ty().is_some_and(is_self_ty) => ByBox, _ => Other, } } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 951112dfe858e..963fa12a8c739 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -3,7 +3,7 @@ use std::fmt; use rustc_ast::Mutability; use rustc_macros::HashStable; -use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, CTFE_ALLOC_SALT}; +use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; #[derive(Clone, Copy, PartialEq, HashStable)] diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index abd6df17514bb..a93a146ec7c42 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -2,7 +2,7 @@ //! WARNING: this does not keep track of the region depth. use rustc_data_structures::sso::SsoHashSet; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use tracing::debug; use crate::ty::{self, GenericArg, GenericArgKind, Ty}; diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index 32f5251568f1b..b99336c2c85ba 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -1,12 +1,12 @@ // These functions are used by macro expansion for bug! and span_bug! use std::fmt; -use std::panic::{panic_any, Location}; +use std::panic::{Location, panic_any}; use rustc_errors::MultiSpan; use rustc_span::Span; -use crate::ty::{tls, TyCtxt}; +use crate::ty::{TyCtxt, tls}; #[cold] #[inline(never)] diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index 75ae4e11fa9ea..fe30cbfae4e32 100644 --- a/compiler/rustc_middle/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -3,9 +3,9 @@ //! context. use rustc_hir::def_id::DefId; -use rustc_hir::{lang_items, LangItem}; +use rustc_hir::{LangItem, lang_items}; use rustc_span::symbol::Ident; -use rustc_span::{sym, DesugaringKind, Span}; +use rustc_span::{DesugaringKind, Span, sym}; use tracing::debug; use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, ParamEnv, Ty, TyCtxt}; diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs index 2038d3f84484e..223b2b3bfe4de 100644 --- a/compiler/rustc_middle/src/util/common.rs +++ b/compiler/rustc_middle/src/util/common.rs @@ -20,19 +20,3 @@ pub fn to_readable_str(mut val: usize) -> String { groups.join("_") } - -// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }` -pub const fn c_name(name: &'static str) -> &'static str { - // FIXME Simplify the implementation once more `str` methods get const-stable. - // and inline into call site - let bytes = name.as_bytes(); - let mut i = bytes.len(); - while i > 0 && bytes[i - 1] != b':' { - i = i - 1; - } - let (_, bytes) = bytes.split_at(i); - match std::str::from_utf8(bytes) { - Ok(name) => name, - Err(_) => name, - } -} diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs index 8c95988477d9c..8dafc42264485 100644 --- a/compiler/rustc_middle/src/util/mod.rs +++ b/compiler/rustc_middle/src/util/mod.rs @@ -3,7 +3,7 @@ pub mod call_kind; pub mod common; pub mod find_self_call; -pub use call_kind::{call_kind, CallDesugaringKind, CallKind}; +pub use call_kind::{CallDesugaringKind, CallKind, call_kind}; pub use find_self_call::find_self_call; #[derive(Default, Copy, Clone)] diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 9e429f5a4c737..c98d88e22d409 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -4,12 +4,12 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan}; +use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; -use rustc_query_system::query::{report_cycle, CycleError}; use rustc_query_system::Value; +use rustc_query_system::query::{CycleError, report_cycle}; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span}; @@ -56,7 +56,7 @@ impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { && let Some(node) = tcx.hir().get_if_local(def_id) && let Some(sig) = node.fn_sig() { - sig.decl.inputs.len() + sig.decl.implicit_self.has_implicit_self() as usize + sig.decl.inputs.len() } else { tcx.dcx().abort_if_errors(); unreachable!() diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 7a10e627ccd89..1c4e9fd11cbd6 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -338,6 +338,7 @@ mir_build_unreachable_pattern = unreachable pattern .unreachable_covered_by_catchall = matches any value .unreachable_covered_by_one = matches all the relevant values .unreachable_covered_by_many = multiple earlier patterns match some of the same values + .suggestion = remove the match arm mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 7afa628843f22..89e64015bc439 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -5,8 +5,8 @@ use rustc_middle::{span_bug, ty}; use rustc_span::Span; use tracing::debug; -use crate::build::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops}; use crate::build::ForGuard::OutsideGuard; +use crate::build::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; impl<'a, 'tcx> Builder<'a, 'tcx> { diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs index e80b654309ea5..9c5ee5b0996e5 100644 --- a/compiler/rustc_mir_build/src/build/cfg.rs +++ b/compiler/rustc_mir_build/src/build/cfg.rs @@ -40,10 +40,10 @@ impl<'tcx> CFG<'tcx> { place: Place<'tcx>, rvalue: Rvalue<'tcx>, ) { - self.push( - block, - Statement { source_info, kind: StatementKind::Assign(Box::new((place, rvalue))) }, - ); + self.push(block, Statement { + source_info, + kind: StatementKind::Assign(Box::new((place, rvalue))), + }); } pub(crate) fn push_assign_constant( diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 3aa6e708476d5..6019a93e7876a 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -268,10 +268,9 @@ impl Builder<'_, '_> { pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) { if let Some(coverage_info) = self.coverage_info.as_mut() && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() + && mcdc_info.state.decision_ctx_stack.pop().is_none() { - if mcdc_info.state.decision_ctx_stack.pop().is_none() { - bug!("Unexpected empty decision stack"); - } + bug!("Unexpected empty decision stack"); }; } } diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index 28477e527c721..4815db47b16c1 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -19,8 +19,8 @@ use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefId; use rustc_hir::HirId; +use rustc_hir::def_id::DefId; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::*; use rustc_middle::span_bug; @@ -134,13 +134,12 @@ fn parse_attribute(attr: &Attribute) -> MirPhase { MirPhase::parse(dialect, phase) } -struct ParseCtxt<'tcx, 'body> { +struct ParseCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, - thir: &'body Thir<'tcx>, + thir: &'a Thir<'tcx>, source_scope: SourceScope, - - body: &'body mut Body<'tcx>, + body: &'a mut Body<'tcx>, local_map: FxHashMap, block_map: FxHashMap, } @@ -151,7 +150,7 @@ struct ParseError { expected: String, } -impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { +impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { fn expr_error(&self, expr: ExprId, expected: &'static str) -> ParseError { let expr = &self.thir[expr]; ParseError { diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs index 646aefa08829e..538068e1fac8e 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse.rs @@ -68,7 +68,7 @@ macro_rules! parse_by_kind { } pub(crate) use parse_by_kind; -impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { +impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { /// Expressions should only ever be matched on after preparsing them. This removes extra scopes /// we don't care about. fn preparse(&self, expr_id: ExprId) -> ExprId { @@ -82,13 +82,11 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { fn statement_as_expr(&self, stmt_id: StmtId) -> PResult { match &self.thir[stmt_id].kind { StmtKind::Expr { expr, .. } => Ok(*expr), - kind @ StmtKind::Let { pattern, .. } => { - return Err(ParseError { - span: pattern.span, - item_description: format!("{kind:?}"), - expected: "expression".to_string(), - }); - } + kind @ StmtKind::Let { pattern, .. } => Err(ParseError { + span: pattern.span, + item_description: format!("{kind:?}"), + expected: "expression".to_string(), + }), } } diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 0b13ceb574d04..9e3af89105294 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -4,15 +4,15 @@ use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty; use rustc_middle::ty::cast::mir_cast_kind; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; use rustc_target::abi::{FieldIdx, VariantIdx}; -use super::{parse_by_kind, PResult, ParseCtxt}; +use super::{PResult, ParseCtxt, parse_by_kind}; use crate::build::custom::ParseError; use crate::build::expr::as_constant::as_constant_inner; -impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { +impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { pub(crate) fn parse_statement(&self, expr_id: ExprId) -> PResult> { parse_by_kind!(self, expr_id, _, "statement", @call(mir_storage_live, args) => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 4f1166f91118e..ae164cf760569 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -3,7 +3,7 @@ use rustc_ast as ast; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{ - Allocation, LitToConstError, LitToConstInput, Scalar, CTFE_ALLOC_SALT, + Allocation, CTFE_ALLOC_SALT, LitToConstError, LitToConstInput, Scalar, }; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -14,7 +14,7 @@ use rustc_middle::{bug, mir, span_bug}; use rustc_target::abi::Size; use tracing::{instrument, trace}; -use crate::build::{parse_float_into_constval, Builder}; +use crate::build::{Builder, parse_float_into_constval}; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 07784982631f8..c7298e3ddfa90 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -12,11 +12,11 @@ use rustc_middle::thir::*; use rustc_middle::ty::{self, AdtDef, CanonicalUserTypeAnnotation, Ty, Variance}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use tracing::{debug, instrument, trace}; -use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; +use crate::build::expr::category::Category; use crate::build::{BlockAnd, BlockAndExtension, Builder, Capture, CaptureMap}; /// The "outermost" place that holds this value. @@ -470,60 +470,56 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(place_builder) } - ExprKind::PlaceTypeAscription { source, ref user_ty } => { + ExprKind::PlaceTypeAscription { source, ref user_ty, user_ty_span } => { let place_builder = unpack!( block = this.expr_as_place(block, source, mutability, fake_borrow_temps,) ); if let Some(user_ty) = user_ty { + let ty_source_info = this.source_info(user_ty_span); let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { - span: source_info.span, + span: user_ty_span, user_ty: user_ty.clone(), inferred_ty: expr.ty, }); let place = place_builder.to_place(this); - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::AscribeUserType( - Box::new(( - place, - UserTypeProjection { base: annotation_index, projs: vec![] }, - )), - Variance::Invariant, - ), - }, - ); + this.cfg.push(block, Statement { + source_info: ty_source_info, + kind: StatementKind::AscribeUserType( + Box::new((place, UserTypeProjection { + base: annotation_index, + projs: vec![], + })), + Variance::Invariant, + ), + }); } block.and(place_builder) } - ExprKind::ValueTypeAscription { source, ref user_ty } => { + ExprKind::ValueTypeAscription { source, ref user_ty, user_ty_span } => { let source_expr = &this.thir[source]; let temp = unpack!( block = this.as_temp(block, source_expr.temp_lifetime, source, mutability) ); if let Some(user_ty) = user_ty { + let ty_source_info = this.source_info(user_ty_span); let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { - span: source_info.span, + span: user_ty_span, user_ty: user_ty.clone(), inferred_ty: expr.ty, }); - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::AscribeUserType( - Box::new(( - Place::from(temp), - UserTypeProjection { base: annotation_index, projs: vec![] }, - )), - Variance::Invariant, - ), - }, - ); + this.cfg.push(block, Statement { + source_info: ty_source_info, + kind: StatementKind::AscribeUserType( + Box::new((Place::from(temp), UserTypeProjection { + base: annotation_index, + projs: vec![], + })), + Variance::Invariant, + ), + }); } block.and(PlaceBuilder::from(temp)) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 0c9571da3cf7f..fd949a533845e 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -7,12 +7,12 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::thir::*; -use rustc_middle::ty::cast::{mir_cast_kind, CastTy}; +use rustc_middle::ty::cast::{CastTy, mir_cast_kind}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Ty, UpvarArgs}; use rustc_span::source_map::Spanned; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{Abi, FieldIdx, Primitive}; use tracing::debug; @@ -57,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value)) } ExprKind::Repeat { value, count } => { - if Some(0) == count.try_eval_target_usize(this.tcx, this.param_env) { + if Some(0) == count.try_to_target_usize(this.tcx) { this.build_zero_repeat(block, value, scope, source_info) } else { let value_operand = unpack!( @@ -147,23 +147,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let storage = this.temp(Ty::new_mut_ptr(tcx, tcx.types.u8), expr_span); let success = this.cfg.start_new_block(); - this.cfg.terminate( - block, - source_info, - TerminatorKind::Call { - func: exchange_malloc, - args: [ - Spanned { node: Operand::Move(size), span: DUMMY_SP }, - Spanned { node: Operand::Move(align), span: DUMMY_SP }, - ] - .into(), - destination: storage, - target: Some(success), - unwind: UnwindAction::Continue, - call_source: CallSource::Misc, - fn_span: expr_span, - }, - ); + this.cfg.terminate(block, source_info, TerminatorKind::Call { + func: exchange_malloc, + args: [Spanned { node: Operand::Move(size), span: DUMMY_SP }, Spanned { + node: Operand::Move(align), + span: DUMMY_SP, + }] + .into(), + destination: storage, + target: Some(success), + unwind: UnwindAction::Continue, + call_source: CallSource::Misc, + fn_span: expr_span, + }); this.diverge_from(block); block = success; @@ -171,10 +167,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // and therefore is not considered during coroutine auto-trait // determination. See the comment about `box` at `yield_in_scope`. let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span)); - this.cfg.push( - block, - Statement { source_info, kind: StatementKind::StorageLive(result) }, - ); + this.cfg.push(block, Statement { + source_info, + kind: StatementKind::StorageLive(result), + }); if let Some(scope) = scope { // schedule a shallow free of that memory, lest we unwind: this.schedule_drop_storage_and_value(expr_span, scope, result); @@ -268,15 +264,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); merge_place }; - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::Intrinsic(Box::new( - NonDivergingIntrinsic::Assume(Operand::Move(assert_place)), - )), - }, - ); + this.cfg.push(block, Statement { + source_info, + kind: StatementKind::Intrinsic(Box::new( + NonDivergingIntrinsic::Assume(Operand::Move(assert_place)), + )), + }); } (op, ty) @@ -299,7 +292,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cast_kind = mir_cast_kind(ty, expr.ty); block.and(Rvalue::Cast(cast_kind, source, expr.ty)) } - ExprKind::PointerCoercion { cast, source } => { + ExprKind::PointerCoercion { cast, source, is_from_as_cast } => { let source = unpack!( block = this.as_operand( block, @@ -309,7 +302,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { NeedsTemporary::No ) ); - block.and(Rvalue::Cast(CastKind::PointerCoercion(cast), source, expr.ty)) + let origin = + if is_from_as_cast { CoercionSource::AsCast } else { CoercionSource::Implicit }; + block.and(Rvalue::Cast(CastKind::PointerCoercion(cast, origin), source, expr.ty)) } ExprKind::Array { ref fields } => { // (*) We would (maybe) be closer to codegen if we @@ -721,16 +716,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); if let Operand::Move(to_drop) = value_operand { let success = this.cfg.start_new_block(); - this.cfg.terminate( - block, - outer_source_info, - TerminatorKind::Drop { - place: to_drop, - target: success, - unwind: UnwindAction::Continue, - replace: false, - }, - ); + this.cfg.terminate(block, outer_source_info, TerminatorKind::Drop { + place: to_drop, + target: success, + unwind: UnwindAction::Continue, + replace: false, + }); this.diverge_from(block); block = success; } diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index af5940ff50e61..b8b5e4634ed89 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -1,7 +1,9 @@ //! See docs in build/expr/mod.rs use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::HirId; use rustc_middle::middle::region; +use rustc_middle::middle::region::{Scope, ScopeData}; use rustc_middle::mir::*; use rustc_middle::thir::*; use tracing::{debug, instrument}; @@ -73,11 +75,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ if let Some(tail_info) = this.block_context.currently_in_block_tail() => { LocalInfo::BlockTailTemp(tail_info) } + + _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) = temp_lifetime => { + LocalInfo::IfThenRescopeTemp { + if_then: HirId { owner: this.hir_id.owner, local_id: id }, + } + } + _ => LocalInfo::Boring, }; **local_decl.local_info.as_mut().assert_crate_local() = local_info; this.local_decls.push(local_decl) }; + debug!(?temp); if deduplicate_temps { this.fixed_temps.insert(expr_id, temp); } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1c805ed20cc36..86fe447f39973 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -221,14 +221,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| { // conduct the test, if necessary let body_block = this.cfg.start_new_block(); - this.cfg.terminate( - loop_block, - source_info, - TerminatorKind::FalseUnwind { - real_target: body_block, - unwind: UnwindAction::Continue, - }, - ); + this.cfg.terminate(loop_block, source_info, TerminatorKind::FalseUnwind { + real_target: body_block, + unwind: UnwindAction::Continue, + }); this.diverge_from(loop_block); // The “return” value of the loop body must always be a unit. We therefore @@ -259,30 +255,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("expr_into_dest: fn_span={:?}", fn_span); - this.cfg.terminate( - block, - source_info, - TerminatorKind::Call { - func: fun, - args, - unwind: UnwindAction::Continue, - destination, - // The presence or absence of a return edge affects control-flow sensitive - // MIR checks and ultimately whether code is accepted or not. We can only - // omit the return edge if a return type is visibly uninhabited to a module - // that makes the call. - target: expr - .ty - .is_inhabited_from(this.tcx, this.parent_module, this.param_env) - .then_some(success), - call_source: if from_hir_call { - CallSource::Normal - } else { - CallSource::OverloadedOperator - }, - fn_span, + this.cfg.terminate(block, source_info, TerminatorKind::Call { + func: fun, + args, + unwind: UnwindAction::Continue, + destination, + // The presence or absence of a return edge affects control-flow sensitive + // MIR checks and ultimately whether code is accepted or not. We can only + // omit the return edge if a return type is visibly uninhabited to a module + // that makes the call. + target: expr + .ty + .is_inhabited_from(this.tcx, this.parent_module, this.param_env) + .then_some(success), + call_source: if from_hir_call { + CallSource::Normal + } else { + CallSource::OverloadedOperator }, - ); + fn_span, + }); this.diverge_from(block); success.unit() } @@ -469,11 +461,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tmp = this.get_unit_temp(); let target = this.ast_block(tmp, target, block, source_info).into_block(); - this.cfg.terminate( - target, - source_info, - TerminatorKind::Goto { target: destination_block }, - ); + this.cfg.terminate(target, source_info, TerminatorKind::Goto { + target: destination_block, + }); mir::InlineAsmOperand::Label { target_index } } @@ -484,22 +474,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign_unit(block, source_info, destination, this.tcx); } - this.cfg.terminate( - block, - source_info, - TerminatorKind::InlineAsm { - template, - operands, - options, - line_spans, - targets: targets.into_boxed_slice(), - unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) { - UnwindAction::Continue - } else { - UnwindAction::Unreachable - }, + this.cfg.terminate(block, source_info, TerminatorKind::InlineAsm { + template, + operands, + options, + line_spans, + targets: targets.into_boxed_slice(), + unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) { + UnwindAction::Continue + } else { + UnwindAction::Unreachable }, - ); + }); if options.contains(InlineAsmOptions::MAY_UNWIND) { this.diverge_from(block); } @@ -562,11 +548,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) ); let resume = this.cfg.start_new_block(); - this.cfg.terminate( - block, - source_info, - TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None }, - ); + this.cfg.terminate(block, source_info, TerminatorKind::Yield { + value, + resume, + resume_arg: destination, + drop: None, + }); this.coroutine_drop_cleanup(block); resume.unit() } diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index b38f0a41e5d21..76034c03b4bf6 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -123,11 +123,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unpack!(block = this.break_for_tail_call(block, &args, source_info)); - this.cfg.terminate( - block, - source_info, - TerminatorKind::TailCall { func: fun, args, fn_span }, - ); + this.cfg.terminate(block, source_info, TerminatorKind::TailCall { + func: fun, + args, + fn_span, + }); this.cfg.start_new_block().unit() }) diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs index ab2bfcbca3aa6..6df50057ee83a 100644 --- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -2,9 +2,9 @@ use rustc_middle::mir::*; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use crate::build::Builder; use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; use crate::build::matches::{FlatPat, MatchPairTree, TestCase}; -use crate::build::Builder; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Builds and returns [`MatchPairTree`] subtrees, one for each pattern in @@ -42,7 +42,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.tcx; let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { match place_resolved.ty(&self.local_decls, tcx).ty.kind() { - ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), + ty::Array(_, length) => ( + length + .try_to_target_usize(tcx) + .expect("expected len of array pat to be definite"), + true, + ), _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), } } else { @@ -162,13 +167,10 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { let ascription = place.map(|source| { let span = pattern.span; let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); - let args = ty::InlineConstArgs::new( - cx.tcx, - ty::InlineConstArgsParts { - parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), - ty: cx.infcx.next_ty_var(span), - }, - ) + let args = ty::InlineConstArgs::new(cx.tcx, ty::InlineConstArgsParts { + parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), + ty: cx.infcx.next_ty_var(span), + }) .args; let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( def.to_def_id(), diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index cae4aa7bad3d2..51ead57020556 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -18,9 +18,9 @@ use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; +use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; -use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::{ BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, }; @@ -104,11 +104,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { variable_source_info: SourceInfo, declare_let_bindings: DeclareLetBindings, ) -> BlockAnd<()> { - self.then_else_break_inner( - block, - expr_id, - ThenElseArgs { temp_scope_override, variable_source_info, declare_let_bindings }, - ) + self.then_else_break_inner(block, expr_id, ThenElseArgs { + temp_scope_override, + variable_source_info, + declare_let_bindings, + }) } fn then_else_break_inner( @@ -134,24 +134,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let local_scope = this.local_scope(); let (lhs_success_block, failure_block) = this.in_if_then_scope(local_scope, expr_span, |this| { - this.then_else_break_inner( - block, - lhs, - ThenElseArgs { - declare_let_bindings: DeclareLetBindings::LetNotPermitted, - ..args - }, - ) - }); - let rhs_success_block = this - .then_else_break_inner( - failure_block, - rhs, - ThenElseArgs { + this.then_else_break_inner(block, lhs, ThenElseArgs { declare_let_bindings: DeclareLetBindings::LetNotPermitted, ..args - }, - ) + }) + }); + let rhs_success_block = this + .then_else_break_inner(failure_block, rhs, ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }) .into_block(); // Make the LHS and RHS success arms converge to a common block. @@ -178,14 +170,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if this.tcx.sess.instrument_coverage() { this.cfg.push_coverage_span_marker(block, this.source_info(expr_span)); } - this.then_else_break_inner( - block, - arg, - ThenElseArgs { - declare_let_bindings: DeclareLetBindings::LetNotPermitted, - ..args - }, - ) + this.then_else_break_inner(block, arg, ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }) }); this.break_for_else(success_block, args.variable_source_info); failure_block.unit() @@ -638,30 +626,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ty_source_info = self.source_info(annotation.span); let base = self.canonical_user_type_annotations.push(annotation.clone()); - self.cfg.push( - block, - Statement { - source_info: ty_source_info, - kind: StatementKind::AscribeUserType( - Box::new((place, UserTypeProjection { base, projs: Vec::new() })), - // We always use invariant as the variance here. This is because the - // variance field from the ascription refers to the variance to use - // when applying the type to the value being matched, but this - // ascription applies rather to the type of the binding. e.g., in this - // example: - // - // ``` - // let x: T = - // ``` - // - // We are creating an ascription that defines the type of `x` to be - // exactly `T` (i.e., with invariance). The variance field, in - // contrast, is intended to be used to relate `T` to the type of - // ``. - ty::Invariant, - ), - }, - ); + self.cfg.push(block, Statement { + source_info: ty_source_info, + kind: StatementKind::AscribeUserType( + Box::new((place, UserTypeProjection { base, projs: Vec::new() })), + // We always use invariant as the variance here. This is because the + // variance field from the ascription refers to the variance to use + // when applying the type to the value being matched, but this + // ascription applies rather to the type of the binding. e.g., in this + // example: + // + // ``` + // let x: T = + // ``` + // + // We are creating an ascription that defines the type of `x` to be + // exactly `T` (i.e., with invariance). The variance field, in + // contrast, is intended to be used to relate `T` to the type of + // ``. + ty::Invariant, + ), + }); self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() @@ -2559,19 +2544,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = self.source_info(ascription.annotation.span); let base = self.canonical_user_type_annotations.push(ascription.annotation); - self.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::AscribeUserType( - Box::new(( - ascription.source, - UserTypeProjection { base, projs: Vec::new() }, - )), - ascription.variance, - ), - }, - ); + self.cfg.push(block, Statement { + source_info, + kind: StatementKind::AscribeUserType( + Box::new((ascription.source, UserTypeProjection { base, projs: Vec::new() })), + ascription.variance, + ), + }); } } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 04cf81d54e9df..5b402604395af 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -16,8 +16,8 @@ use std::mem; use tracing::{debug, instrument}; -use crate::build::matches::{MatchPairTree, PatternExtraData, TestCase}; use crate::build::Builder; +use crate::build::matches::{MatchPairTree, PatternExtraData, TestCase}; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 7af1ede24a4f4..020c202f96503 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -16,12 +16,12 @@ use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::symbol::{Symbol, sym}; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; -use crate::build::matches::{Candidate, MatchPairTree, Test, TestBranch, TestCase, TestKind}; use crate::build::Builder; +use crate::build::matches::{Candidate, MatchPairTree, Test, TestBranch, TestCase, TestKind}; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. @@ -322,23 +322,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); // `let temp = ::deref(ref_src);` // or `let temp = ::deref_mut(ref_src);` - self.cfg.terminate( - block, - source_info, - TerminatorKind::Call { - func: Operand::Constant(Box::new(ConstOperand { - span, - user_ty: None, - const_: method, - })), - args: [Spanned { node: Operand::Move(ref_src), span }].into(), - destination: temp, - target: Some(target_block), - unwind: UnwindAction::Continue, - call_source: CallSource::Misc, - fn_span: source_info.span, - }, - ); + self.cfg.terminate(block, source_info, TerminatorKind::Call { + func: Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_: method })), + args: [Spanned { node: Operand::Move(ref_src), span }].into(), + destination: temp, + target: Some(target_block), + unwind: UnwindAction::Continue, + call_source: CallSource::Misc, + fn_span: source_info.span, + }); } /// Compare using the provided built-in comparison operator @@ -415,7 +407,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, temp, Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize), + CastKind::PointerCoercion( + PointerCoercion::Unsize, + CoercionSource::Implicit, + ), Operand::Copy(val), ty, ), @@ -429,7 +424,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, slice, Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize), + CastKind::PointerCoercion( + PointerCoercion::Unsize, + CoercionSource::Implicit, + ), expect, ty, ), @@ -466,33 +464,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); let eq_block = self.cfg.start_new_block(); - self.cfg.terminate( - block, - source_info, - TerminatorKind::Call { - func: Operand::Constant(Box::new(ConstOperand { - span: source_info.span, - - // FIXME(#54571): This constant comes from user input (a - // constant in a pattern). Are there forms where users can add - // type annotations here? For example, an associated constant? - // Need to experiment. - user_ty: None, - - const_: method, - })), - args: [ - Spanned { node: Operand::Copy(val), span: DUMMY_SP }, - Spanned { node: expect, span: DUMMY_SP }, - ] - .into(), - destination: eq_result, - target: Some(eq_block), - unwind: UnwindAction::Continue, - call_source: CallSource::MatchCmp, - fn_span: source_info.span, - }, - ); + self.cfg.terminate(block, source_info, TerminatorKind::Call { + func: Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + + // FIXME(#54571): This constant comes from user input (a + // constant in a pattern). Are there forms where users can add + // type annotations here? For example, an associated constant? + // Need to experiment. + user_ty: None, + + const_: method, + })), + args: [Spanned { node: Operand::Copy(val), span: DUMMY_SP }, Spanned { + node: expect, + span: DUMMY_SP, + }] + .into(), + destination: eq_result, + target: Some(eq_block), + unwind: UnwindAction::Continue, + call_source: CallSource::MatchCmp, + fn_span: source_info.span, + }); self.diverge_from(block); // check the result diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 8491b5fe380c7..555684ded81a1 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -4,9 +4,9 @@ use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; +use crate::build::Builder; use crate::build::expr::as_place::PlaceBase; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestCase}; -use crate::build::Builder; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Creates a false edge to `imaginary_target` and a real edge to @@ -20,11 +20,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: SourceInfo, ) { if imaginary_target != real_target { - self.cfg.terminate( - from_block, - source_info, - TerminatorKind::FalseEdge { real_target, imaginary_target }, - ); + self.cfg.terminate(from_block, source_info, TerminatorKind::FalseEdge { + real_target, + imaginary_target, + }); } else { self.cfg.goto(from_block, source_info, real_target) } diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 26906973ca86c..53cb99d44e8f8 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -45,16 +45,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> Place<'tcx> { let usize_ty = self.tcx.types.usize; let temp = self.temp(usize_ty, source_info.span); - self.cfg.push_assign_constant( - block, - source_info, - temp, - ConstOperand { - span: source_info.span, - user_ty: None, - const_: Const::from_usize(self.tcx, value), - }, - ); + self.cfg.push_assign_constant(block, source_info, temp, ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::from_usize(self.tcx, value), + }); temp } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index b98deda8fd022..8c20d2e0d3a62 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,6 +1,6 @@ use itertools::Itertools; -use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 693037d03e017..dfc82f705a81b 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -92,7 +92,7 @@ use rustc_middle::thir::{ExprId, LintLevel}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::Level; use rustc_span::source_map::Spanned; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; @@ -510,16 +510,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Some(normal_block), Some(exit_block)) => { let target = self.cfg.start_new_block(); let source_info = self.source_info(span); - self.cfg.terminate( - normal_block.into_block(), - source_info, - TerminatorKind::Goto { target }, - ); - self.cfg.terminate( - exit_block.into_block(), - source_info, - TerminatorKind::Goto { target }, - ); + self.cfg.terminate(normal_block.into_block(), source_info, TerminatorKind::Goto { + target, + }); + self.cfg.terminate(exit_block.into_block(), source_info, TerminatorKind::Goto { + target, + }); target.unit() } } @@ -806,25 +802,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unwind_drops.add_entry_point(block, unwind_entry_point); let next = self.cfg.start_new_block(); - self.cfg.terminate( - block, - source_info, - TerminatorKind::Drop { - place: local.into(), - target: next, - unwind: UnwindAction::Continue, - replace: false, - }, - ); + self.cfg.terminate(block, source_info, TerminatorKind::Drop { + place: local.into(), + target: next, + unwind: UnwindAction::Continue, + replace: false, + }); block = next; } DropKind::Storage => { // Only temps and vars need their storage dead. assert!(local.index() > self.arg_count); - self.cfg.push( - block, - Statement { source_info, kind: StatementKind::StorageDead(local) }, - ); + self.cfg.push(block, Statement { + source_info, + kind: StatementKind::StorageDead(local), + }); } } } @@ -1283,16 +1275,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let assign_unwind = self.cfg.start_new_cleanup_block(); self.cfg.push_assign(assign_unwind, source_info, place, value.clone()); - self.cfg.terminate( - block, - source_info, - TerminatorKind::Drop { - place, - target: assign, - unwind: UnwindAction::Cleanup(assign_unwind), - replace: true, - }, - ); + self.cfg.terminate(block, source_info, TerminatorKind::Drop { + place, + target: assign, + unwind: UnwindAction::Cleanup(assign_unwind), + replace: true, + }); self.diverge_from(block); assign.unit() @@ -1312,17 +1300,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = self.source_info(span); let success_block = self.cfg.start_new_block(); - self.cfg.terminate( - block, - source_info, - TerminatorKind::Assert { - cond, - expected, - msg: Box::new(msg), - target: success_block, - unwind: UnwindAction::Continue, - }, - ); + self.cfg.terminate(block, source_info, TerminatorKind::Assert { + cond, + expected, + msg: Box::new(msg), + target: success_block, + unwind: UnwindAction::Continue, + }); self.diverge_from(block); success_block @@ -1397,16 +1381,12 @@ fn build_scope_drops<'tcx>( unwind_drops.add_entry_point(block, unwind_to); let next = cfg.start_new_block(); - cfg.terminate( - block, - source_info, - TerminatorKind::Drop { - place: local.into(), - target: next, - unwind: UnwindAction::Continue, - replace: false, - }, - ); + cfg.terminate(block, source_info, TerminatorKind::Drop { + place: local.into(), + target: next, + unwind: UnwindAction::Continue, + replace: false, + }); block = next; } DropKind::Storage => { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index c7fcfe3ce2aa0..8512763a595d5 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -12,11 +12,11 @@ use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; -use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; +use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use crate::build::ExprCategory; use crate::errors::*; @@ -218,6 +218,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { warnings: self.warnings, suggest_unsafe_block: self.suggest_unsafe_block, }; + // params in THIR may be unsafe, e.g. a union pattern. + for param in &inner_thir.params { + if let Some(param_pat) = param.pat.as_deref() { + inner_visitor.visit_pat(param_pat); + } + } + // Visit the body. inner_visitor.visit_expr(&inner_thir[expr]); // Unsafe blocks can be used in the inner body, make sure to take it into account self.safety_context = inner_visitor.safety_context; @@ -315,14 +322,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | PatKind::DerefPattern { .. } | PatKind::Range { .. } | PatKind::Slice { .. } - | PatKind::Array { .. } => { + | PatKind::Array { .. } + // Never constitutes a witness of uninhabitedness. + | PatKind::Never => { self.requires_unsafe(pat.span, AccessToUnionField); return; // we can return here since this already requires unsafe } - // wildcard/never don't take anything + // wildcard doesn't read anything. PatKind::Wild | - PatKind::Never | - // these just wrap other patterns + // these just wrap other patterns, which we recurse on below. PatKind::Or { .. } | PatKind::InlineConstant { .. } | PatKind::AscribeUserType { .. } | @@ -491,10 +499,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { .copied() .filter(|feature| missing.contains(feature)) .collect(); - self.requires_unsafe( - expr.span, - CallToFunctionWith { function: func_did, missing, build_enabled }, - ); + self.requires_unsafe(expr.span, CallToFunctionWith { + function: func_did, + missing, + build_enabled, + }); } } } @@ -1032,16 +1041,21 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { warnings: &mut warnings, suggest_unsafe_block: true, }; + // params in THIR may be unsafe, e.g. a union pattern. + for param in &thir.params { + if let Some(param_pat) = param.pat.as_deref() { + visitor.visit_pat(param_pat); + } + } + // Visit the body. visitor.visit_expr(&thir[expr]); warnings.sort_by_key(|w| w.block_span); for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings { let block_span = tcx.sess.source_map().guess_head_span(block_span); - tcx.emit_node_span_lint( - UNUSED_UNSAFE, - hir_id, - block_span, - UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe }, - ); + tcx.emit_node_span_lint(UNUSED_UNSAFE, hir_id, block_span, UnusedUnsafe { + span: block_span, + enclosing: enclosing_unsafe, + }); } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 7f9eefd1d52e3..42be7f9402ecc 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -7,8 +7,8 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_pattern_analysis::errors::Uncovered; use rustc_pattern_analysis::rustc::RustcPatCtxt; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use crate::fluent_generated as fluent; @@ -598,6 +598,8 @@ pub(crate) struct UnreachablePattern<'tcx> { #[note(mir_build_unreachable_covered_by_many)] pub(crate) covered_by_many: Option, pub(crate) covered_by_many_n_more_count: usize, + #[suggestion(code = "", applicability = "machine-applicable")] + pub(crate) suggest_remove: Option, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 80e91811b1c5f..cb9a4e2604e25 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -54,12 +54,10 @@ fn check_recursion<'tcx>( let sp = tcx.def_span(def_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); - tcx.emit_node_span_lint( - UNCONDITIONAL_RECURSION, - hir_id, - sp, - UnconditionalRecursion { span: sp, call_sites: vis.reachable_recursive_calls }, - ); + tcx.emit_node_span_lint(UNCONDITIONAL_RECURSION, hir_id, sp, UnconditionalRecursion { + span: sp, + call_sites: vis.reachable_recursive_calls, + }); } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 89f98a40201e7..fbd45f59a4fb4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -17,13 +17,13 @@ use rustc_middle::ty::{ UserType, }; use rustc_middle::{bug, span_bug}; -use rustc_span::{sym, Span}; -use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; +use rustc_span::{Span, sym}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx}; use tracing::{debug, info, instrument, trace}; use crate::errors; -use crate::thir::cx::region::Scope; use crate::thir::cx::Cx; +use crate::thir::cx::region::Scope; use crate::thir::util::UserAnnotatedTyHelpers; impl<'tcx> Cx<'tcx> { @@ -74,6 +74,7 @@ impl<'tcx> Cx<'tcx> { self.thir.exprs.push(expr) } + #[instrument(level = "trace", skip(self, expr, span))] fn apply_adjustment( &mut self, hir_expr: &'tcx hir::Expr<'tcx>, @@ -103,16 +104,29 @@ impl<'tcx> Cx<'tcx> { }; let kind = match adjustment.kind { - Adjust::Pointer(PointerCoercion::Unsize) => { - adjust_span(&mut expr); + Adjust::Pointer(cast) => { + if cast == PointerCoercion::Unsize { + adjust_span(&mut expr); + } + + let is_from_as_cast = if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Cast(..), + span: cast_span, + .. + }) = self.tcx.parent_hir_node(hir_expr.hir_id) + { + // Use the whole span of the `x as T` expression for the coercion. + span = *cast_span; + true + } else { + false + }; ExprKind::PointerCoercion { - cast: PointerCoercion::Unsize, + cast, source: self.thir.exprs.push(expr), + is_from_as_cast, } } - Adjust::Pointer(cast) => { - ExprKind::PointerCoercion { cast, source: self.thir.exprs.push(expr) } - } Adjust::NeverToAny if adjustment.target.is_never() => return expr, Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) }, Adjust::Deref(None) => { @@ -145,7 +159,67 @@ impl<'tcx> Cx<'tcx> { Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => { ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) } } - Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) }, + Adjust::ReborrowPin(region, mutbl) => { + debug!("apply ReborrowPin adjustment"); + // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }` + + // We'll need these types later on + let pin_ty_args = match expr.ty.kind() { + ty::Adt(_, args) => args, + _ => bug!("ReborrowPin with non-Pin type"), + }; + let pin_ty = pin_ty_args.iter().next().unwrap().expect_ty(); + let ptr_target_ty = match pin_ty.kind() { + ty::Ref(_, ty, _) => *ty, + _ => bug!("ReborrowPin with non-Ref type"), + }; + + // pointer = ($expr).__pointer + let pointer_target = ExprKind::Field { + lhs: self.thir.exprs.push(expr), + variant_index: FIRST_VARIANT, + name: FieldIdx::from(0u32), + }; + let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target }; + let arg = self.thir.exprs.push(arg); + + // arg = *pointer + let expr = ExprKind::Deref { arg }; + let arg = self.thir.exprs.push(Expr { + temp_lifetime, + ty: ptr_target_ty, + span, + kind: expr, + }); + + // expr = &mut target + let borrow_kind = match mutbl { + hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, + hir::Mutability::Not => BorrowKind::Shared, + }; + let new_pin_target = Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl); + let expr = self.thir.exprs.push(Expr { + temp_lifetime, + ty: new_pin_target, + span, + kind: ExprKind::Borrow { borrow_kind, arg }, + }); + + // kind = Pin { __pointer: pointer } + let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span)); + let args = self.tcx.mk_args(&[new_pin_target.into()]); + let kind = ExprKind::Adt(Box::new(AdtExpr { + adt_def: self.tcx.adt_def(pin_did), + variant_index: FIRST_VARIANT, + args, + fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]), + user_ty: None, + base: None, + })); + + debug!(?kind); + kind + } }; Expr { temp_lifetime, ty: adjustment.target, span, kind } @@ -174,6 +248,7 @@ impl<'tcx> Cx<'tcx> { ExprKind::PointerCoercion { source: self.mirror_expr(source), cast: PointerCoercion::ArrayToPointer, + is_from_as_cast: true, } } else if let hir::ExprKind::Path(ref qpath) = source.kind && let res = self.typeck_results().qpath_res(qpath, source.hir_id) @@ -706,7 +781,13 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::If(cond, then, else_opt) => ExprKind::If { if_then_scope: region::Scope { id: then.hir_id.local_id, - data: region::ScopeData::IfThen, + data: { + if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope { + region::ScopeData::IfThenRescope + } else { + region::ScopeData::IfThen + } + }, }, cond: self.mirror_expr(cond), then: self.mirror_expr(then), @@ -773,6 +854,7 @@ impl<'tcx> Cx<'tcx> { ExprKind::ValueTypeAscription { source: cast_expr, user_ty: Some(Box::new(*user_ty)), + user_ty_span: cast_ty.span, } } else { cast @@ -784,9 +866,17 @@ impl<'tcx> Cx<'tcx> { debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty); let mirrored = self.mirror_expr(source); if source.is_syntactic_place_expr() { - ExprKind::PlaceTypeAscription { source: mirrored, user_ty } + ExprKind::PlaceTypeAscription { + source: mirrored, + user_ty, + user_ty_span: ty.span, + } } else { - ExprKind::ValueTypeAscription { source: mirrored, user_ty } + ExprKind::ValueTypeAscription { + source: mirrored, + user_ty, + user_ty_span: ty.span, + } } } hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) }, @@ -1008,7 +1098,7 @@ impl<'tcx> Cx<'tcx> { // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for - // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. + // `Deref(Mut)::deref(_mut)` and `Index(Mut)::index(_mut)`. let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else { span_bug!(span, "overloaded_place: receiver is not a reference"); }; diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 5b5f97cb51410..377931e3be730 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -5,10 +5,10 @@ use rustc_data_structures::steal::Steal; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; +use rustc_hir::HirId; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::HirId; use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::thir::*; @@ -182,9 +182,11 @@ impl<'tcx> Cx<'tcx> { let ty = if fn_decl.c_variadic && index == fn_decl.inputs.len() { let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span)); - self.tcx - .type_of(va_list_did) - .instantiate(self.tcx, &[self.tcx.lifetimes.re_erased.into()]) + self.tcx.type_of(va_list_did).instantiate(self.tcx, &[self + .tcx + .lifetimes + .re_erased + .into()]) } else { fn_sig.inputs()[index] }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 4c066a68ef9ff..ae77bce6bb199 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -3,7 +3,7 @@ use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err}; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; @@ -22,7 +22,7 @@ use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; use rustc_span::hygiene::DesugaringKind; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use tracing::instrument; use crate::errors::*; @@ -413,7 +413,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { // Emit lints in the order in which they occur in the file. redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span); for (pat, explanation) in redundant_subpats { - report_unreachable_pattern(cx, arm.arm_data, pat, &explanation) + report_unreachable_pattern(cx, arm.arm_data, pat, &explanation, None) } } } @@ -474,7 +474,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { hir::MatchSource::ForLoopDesugar | hir::MatchSource::Postfix | hir::MatchSource::Normal - | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report), + | hir::MatchSource::FormatArgs => { + let is_match_arm = + matches!(source, hir::MatchSource::Postfix | hir::MatchSource::Normal); + report_arm_reachability(&cx, &report, is_match_arm); + } // Unreachable patterns in try and await expressions occur when one of // the arms are an uninhabited type. Which is OK. hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar(_) => {} @@ -626,7 +630,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { ) -> Result { let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?; // Report if the pattern is unreachable, which can only occur when the type is uninhabited. - report_arm_reachability(&cx, &report); + report_arm_reachability(&cx, &report, false); // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is // irrefutable. Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable }) @@ -916,6 +920,7 @@ fn report_unreachable_pattern<'p, 'tcx>( hir_id: HirId, pat: &DeconstructedPat<'p, 'tcx>, explanation: &RedundancyExplanation<'p, 'tcx>, + whole_arm_span: Option, ) { static CAP_COVERED_BY_MANY: usize = 4; let pat_span = pat.data().span; @@ -928,6 +933,7 @@ fn report_unreachable_pattern<'p, 'tcx>( covered_by_one: None, covered_by_many: None, covered_by_many_n_more_count: 0, + suggest_remove: None, }; match explanation.covered_by.as_slice() { [] => { @@ -935,6 +941,7 @@ fn report_unreachable_pattern<'p, 'tcx>( lint.span = None; // Don't label the pattern itself lint.uninhabited_note = Some(()); // Give a link about empty types lint.matches_no_values = Some(pat_span); + lint.suggest_remove = whole_arm_span; // Suggest to remove the match arm pat.walk(&mut |subpat| { let ty = **subpat.ty(); if cx.is_uninhabited(ty) { @@ -982,10 +989,28 @@ fn report_unreachable_pattern<'p, 'tcx>( } /// Report unreachable arms, if any. -fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) { +fn report_arm_reachability<'p, 'tcx>( + cx: &PatCtxt<'p, 'tcx>, + report: &UsefulnessReport<'p, 'tcx>, + is_match_arm: bool, +) { + let sm = cx.tcx.sess.source_map(); for (arm, is_useful) in report.arm_usefulness.iter() { if let Usefulness::Redundant(explanation) = is_useful { - report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation) + let hir_id = arm.arm_data; + let arm_span = cx.tcx.hir().span(hir_id); + let whole_arm_span = if is_match_arm { + // If the arm is followed by a comma, extend the span to include it. + let with_whitespace = sm.span_extend_while_whitespace(arm_span); + if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) { + Some(arm_span.to(comma)) + } else { + Some(arm_span) + } + } else { + None + }; + report_unreachable_pattern(cx, hir_id, arm.pat, explanation, whole_arm_span) } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 53393046610ac..2c3611afca9a7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -10,8 +10,8 @@ use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree}; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::ObligationCause; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument, trace}; use super::PatCtxt; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d78e1f5da09f0..04e921ecc2e05 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -441,7 +441,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, // Fixed-length array, `[T; len]`. ty::Array(_, len) => { - let len = len.eval_target_usize(self.tcx, self.param_env); + let len = len + .try_to_target_usize(self.tcx) + .expect("expected len of array pat to be definite"); assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatKind::Array { prefix, slice, suffix } } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index ce7774f594882..61317925d09e5 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -292,9 +292,14 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_expr(*source, depth_lvl + 2); print_indented!(self, "}", depth_lvl); } - PointerCoercion { cast, source } => { + PointerCoercion { cast, is_from_as_cast, source } => { print_indented!(self, "Pointer {", depth_lvl); print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1); + print_indented!( + self, + format!("is_from_as_cast: {:?}", is_from_as_cast), + depth_lvl + 1 + ); print_indented!(self, "source:", depth_lvl + 1); self.print_expr(*source, depth_lvl + 2); print_indented!(self, "}", depth_lvl); @@ -454,16 +459,18 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_adt_expr(&**adt_expr, depth_lvl + 1); print_indented!(self, "}", depth_lvl); } - PlaceTypeAscription { source, user_ty } => { + PlaceTypeAscription { source, user_ty, user_ty_span } => { print_indented!(self, "PlaceTypeAscription {", depth_lvl); print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, format!("user_ty_span: {:?}", user_ty_span), depth_lvl + 1); print_indented!(self, "source:", depth_lvl + 1); self.print_expr(*source, depth_lvl + 2); print_indented!(self, "}", depth_lvl); } - ValueTypeAscription { source, user_ty } => { + ValueTypeAscription { source, user_ty, user_ty_span } => { print_indented!(self, "ValueTypeAscription {", depth_lvl); print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, format!("user_ty_span: {:?}", user_ty_span), depth_lvl + 1); print_indented!(self, "source:", depth_lvl + 1); self.print_expr(*source, depth_lvl + 2); print_indented!(self, "}", depth_lvl); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index d7e738b8829e0..f2541c37167f0 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -8,9 +8,9 @@ use rustc_middle::span_bug; use rustc_middle::traits::Reveal; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; -use rustc_span::source_map::Spanned; use rustc_span::DUMMY_SP; -use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; +use rustc_span::source_map::Spanned; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use tracing::{debug, instrument}; /// The value of an inserted drop flag. @@ -155,11 +155,11 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug { } #[derive(Debug)] -struct DropCtxt<'l, 'b, 'tcx, D> +struct DropCtxt<'a, 'b, 'tcx, D> where D: DropElaborator<'b, 'tcx>, { - elaborator: &'l mut D, + elaborator: &'a mut D, source_info: SourceInfo, @@ -192,7 +192,7 @@ pub fn elaborate_drop<'b, 'tcx, D>( DropCtxt { elaborator, source_info, place, path, succ, unwind }.elaborate_drop(bb) } -impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> +impl<'a, 'b, 'tcx, D> DropCtxt<'a, 'b, 'tcx, D> where D: DropElaborator<'b, 'tcx>, 'tcx: 'b, @@ -233,15 +233,12 @@ where .patch_terminator(bb, TerminatorKind::Goto { target: self.succ }); } DropStyle::Static => { - self.elaborator.patch().patch_terminator( - bb, - TerminatorKind::Drop { - place: self.place, - target: self.succ, - unwind: self.unwind.into_action(), - replace: false, - }, - ); + self.elaborator.patch().patch_terminator(bb, TerminatorKind::Drop { + place: self.place, + target: self.succ, + unwind: self.unwind.into_action(), + replace: false, + }); } DropStyle::Conditional => { let drop_bb = self.complete_drop(self.succ, self.unwind); @@ -732,15 +729,12 @@ where }; let loop_block = self.elaborator.patch().new_block(loop_block); - self.elaborator.patch().patch_terminator( - drop_block, - TerminatorKind::Drop { - place: tcx.mk_place_deref(ptr), - target: loop_block, - unwind: unwind.into_action(), - replace: false, - }, - ); + self.elaborator.patch().patch_terminator(drop_block, TerminatorKind::Drop { + place: tcx.mk_place_deref(ptr), + target: loop_block, + unwind: unwind.into_action(), + replace: false, + }); loop_block } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index ba4a7d7651141..88a9a78f8ad62 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -42,14 +42,14 @@ pub trait Direction { ) where A: GenKillAnalysis<'tcx>; - fn visit_results_in_block<'mir, 'tcx, F, R>( - state: &mut F, + fn visit_results_in_block<'mir, 'tcx, D, R>( + state: &mut D, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>; + R: ResultsVisitable<'tcx, Domain = D>; fn join_state_into_successors_of<'tcx, A>( analysis: &mut A, @@ -186,14 +186,14 @@ impl Direction for Backward { analysis.apply_statement_effect(state, statement, location); } - fn visit_results_in_block<'mir, 'tcx, F, R>( - state: &mut F, + fn visit_results_in_block<'mir, 'tcx, D, R>( + state: &mut D, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = D>, { results.reset_to_block_entry(state, block); @@ -444,9 +444,9 @@ impl Direction for Forward { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = F>, { results.reset_to_block_entry(state, block); diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 0bab03b027161..da01a9740943d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -7,17 +7,17 @@ use rustc_data_structures::work_queue::WorkQueue; use rustc_hir::def_id::DefId; use rustc_index::{Idx, IndexVec}; use rustc_middle::bug; -use rustc_middle::mir::{self, create_dump_file, dump_enabled, traversal, BasicBlock}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal}; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::{sym, Symbol}; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_span::symbol::{Symbol, sym}; use tracing::{debug, error}; use {rustc_ast as ast, rustc_graphviz as dot}; use super::fmt::DebugWithContext; use super::{ - graphviz, visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, - GenKillSet, JoinSemiLattice, ResultsCursor, ResultsVisitor, + Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice, + ResultsCursor, ResultsVisitor, graphviz, visit_results, }; use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, @@ -57,7 +57,7 @@ where &mut self, body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, - vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { visit_results(body, blocks, self, vis) } @@ -65,7 +65,7 @@ where pub fn visit_reachable_with<'mir>( &mut self, body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { let blocks = mir::traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) @@ -266,7 +266,7 @@ where A::Domain: DebugWithContext, { use std::fs; - use std::io::{self, Write}; + use std::io::Write; let def_id = body.source.def_id(); let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else { @@ -281,8 +281,7 @@ where if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } - let f = fs::File::create(&path)?; - io::BufWriter::new(f) + fs::File::create_buffered(&path)? } None if dump_enabled(tcx, A::NAME, def_id) => { diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs index 5e4f36e4ae3ae..ed540cd148c45 100644 --- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs +++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs @@ -3,8 +3,8 @@ use std::fmt; -use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_index::Idx; +use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use super::lattice::MaybeReachable; diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 2e860e2d84121..96a70f4fa5b0c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -8,7 +8,7 @@ use std::{io, ops, str}; use regex::Regex; use rustc_graphviz as dot; use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, graphviz_safe_def_name, BasicBlock, Body, Location}; +use rustc_middle::mir::{self, BasicBlock, Body, Location, graphviz_safe_def_name}; use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext}; use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor}; @@ -502,10 +502,10 @@ where r#"{state}"#, colspan = this.style.num_state_columns(), fmt = fmt, - state = dot::escape_html(&format!( - "{:?}", - DebugWithAdapter { this: state, ctxt: analysis } - )), + state = dot::escape_html(&format!("{:?}", DebugWithAdapter { + this: state, + ctxt: analysis + })), ) }) } @@ -544,15 +544,15 @@ where A: Analysis<'tcx>, A::Domain: DebugWithContext, { - type FlowState = A::Domain; + type Domain = A::Domain; - fn visit_block_start(&mut self, state: &Self::FlowState) { + fn visit_block_start(&mut self, state: &Self::Domain) { if A::Direction::IS_FORWARD { self.prev_state.clone_from(state); } } - fn visit_block_end(&mut self, state: &Self::FlowState) { + fn visit_block_end(&mut self, state: &Self::Domain) { if A::Direction::IS_BACKWARD { self.prev_state.clone_from(state); } @@ -561,7 +561,7 @@ where fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -574,7 +574,7 @@ where fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -585,7 +585,7 @@ where fn visit_terminator_before_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { @@ -598,7 +598,7 @@ where fn visit_terminator_after_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 6da3a20dc02c3..d0472e35fe00a 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -32,8 +32,8 @@ use std::cmp::Ordering; -use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_index::Idx; +use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; use rustc_middle::ty::TyCtxt; @@ -49,7 +49,7 @@ pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; pub use self::engine::{Engine, Results}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; -pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor}; +pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds /// operations needed by all of them. diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 52db931b68e1e..1861f4cffc717 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -30,32 +30,26 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { block(4, mir::TerminatorKind::Return); block(1, mir::TerminatorKind::Return); - block( - 2, - mir::TerminatorKind::Call { - func: mir::Operand::Copy(dummy_place.clone()), - args: [].into(), - destination: dummy_place.clone(), - target: Some(mir::START_BLOCK), - unwind: mir::UnwindAction::Continue, - call_source: mir::CallSource::Misc, - fn_span: DUMMY_SP, - }, - ); + block(2, mir::TerminatorKind::Call { + func: mir::Operand::Copy(dummy_place.clone()), + args: [].into(), + destination: dummy_place.clone(), + target: Some(mir::START_BLOCK), + unwind: mir::UnwindAction::Continue, + call_source: mir::CallSource::Misc, + fn_span: DUMMY_SP, + }); block(3, mir::TerminatorKind::Return); block(0, mir::TerminatorKind::Return); - block( - 4, - mir::TerminatorKind::Call { - func: mir::Operand::Copy(dummy_place.clone()), - args: [].into(), - destination: dummy_place.clone(), - target: Some(mir::START_BLOCK), - unwind: mir::UnwindAction::Continue, - call_source: mir::CallSource::Misc, - fn_span: DUMMY_SP, - }, - ); + block(4, mir::TerminatorKind::Call { + func: mir::Operand::Copy(dummy_place.clone()), + args: [].into(), + destination: dummy_place.clone(), + target: Some(mir::START_BLOCK), + unwind: mir::UnwindAction::Continue, + call_source: mir::CallSource::Misc, + fn_span: DUMMY_SP, + }); mir::Body::new_cfg_only(blocks) } diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 8b8a16bda99b1..3d6b008a6846d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results}; /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the /// dataflow state at that location. -pub fn visit_results<'mir, 'tcx, F, R>( +pub fn visit_results<'mir, 'tcx, D, R>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = D>, { - let mut state = results.new_flow_state(body); + let mut state = results.bottom_value(body); #[cfg(debug_assertions)] let reachable_blocks = mir::traversal::reachable_as_bitset(body); @@ -29,16 +29,16 @@ pub fn visit_results<'mir, 'tcx, F, R>( /// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being /// visited. pub trait ResultsVisitor<'mir, 'tcx, R> { - type FlowState; + type Domain; - fn visit_block_start(&mut self, _state: &Self::FlowState) {} + fn visit_block_start(&mut self, _state: &Self::Domain) {} /// Called with the `before_statement_effect` of the given statement applied to `state` but not /// its `statement_effect`. fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, _location: Location, ) { @@ -49,7 +49,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_statement_after_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, _location: Location, ) { @@ -60,7 +60,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) { @@ -73,13 +73,13 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) { } - fn visit_block_end(&mut self, _state: &Self::FlowState) {} + fn visit_block_end(&mut self, _state: &Self::Domain) {} } /// Things that can be visited by a `ResultsVisitor`. @@ -88,40 +88,40 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// simultaneously. pub trait ResultsVisitable<'tcx> { type Direction: Direction; - type FlowState; + type Domain; - /// Creates an empty `FlowState` to hold the transient state for these dataflow results. + /// Creates an empty `Domain` to hold the transient state for these dataflow results. /// - /// The value of the newly created `FlowState` will be overwritten by `reset_to_block_entry` + /// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry` /// before it can be observed by a `ResultsVisitor`. - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState; + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock); + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock); fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ); fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ); @@ -131,21 +131,20 @@ impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> where A: Analysis<'tcx>, { - type FlowState = A::Domain; - + type Domain = A::Domain; type Direction = A::Direction; - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { self.analysis.bottom_value(body) } - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { state.clone_from(self.entry_set_for_block(block)); } fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -154,7 +153,7 @@ where fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -163,7 +162,7 @@ where fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { @@ -172,7 +171,7 @@ where fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index e8e78fb8a89ee..8b082ef2667a3 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -11,7 +11,7 @@ use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; /// At present, this is used as a very limited form of alias analysis. For example, /// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for /// immovable coroutines. -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct MaybeBorrowedLocals; impl MaybeBorrowedLocals { diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index ddfd0739358d1..25e8726cf6162 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -1,7 +1,7 @@ use std::assert_matches::assert_matches; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_index::Idx; +use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_middle::bug; use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges}; use rustc_middle::ty::{self, TyCtxt}; @@ -11,9 +11,9 @@ use crate::elaborate_drops::DropFlagState; use crate::framework::SwitchIntEdgeEffects; use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; use crate::{ - drop_flag_effects, drop_flag_effects_for_function_entry, drop_flag_effects_for_location, - lattice, on_all_children_bits, on_lookup_result_bits, AnalysisDomain, GenKill, GenKillAnalysis, - MaybeReachable, + AnalysisDomain, GenKill, GenKillAnalysis, MaybeReachable, drop_flag_effects, + drop_flag_effects_for_function_entry, drop_flag_effects_for_location, lattice, + on_all_children_bits, on_lookup_result_bits, }; /// `MaybeInitializedPlaces` tracks all places that might be @@ -51,15 +51,15 @@ use crate::{ /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeUninitializedPlaces` yields the set of /// places that would require a dynamic drop-flag at that statement. -pub struct MaybeInitializedPlaces<'a, 'mir, 'tcx> { +pub struct MaybeInitializedPlaces<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, + body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>, skip_unreachable_unwind: bool, } -impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self { +impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self { MaybeInitializedPlaces { tcx, body, move_data, skip_unreachable_unwind: false } } @@ -85,7 +85,7 @@ impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> { } } -impl<'a, 'mir, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'mir, 'tcx> { +impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { self.move_data } @@ -126,17 +126,17 @@ impl<'a, 'mir, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'mir, 'tcx /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeInitializedPlaces` yields the set of /// places that would require a dynamic drop-flag at that statement. -pub struct MaybeUninitializedPlaces<'a, 'mir, 'tcx> { +pub struct MaybeUninitializedPlaces<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, + body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>, mark_inactive_variants_as_uninit: bool, skip_unreachable_unwind: BitSet, } -impl<'a, 'mir, 'tcx> MaybeUninitializedPlaces<'a, 'mir, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self { +impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self { MaybeUninitializedPlaces { tcx, body, @@ -165,7 +165,7 @@ impl<'a, 'mir, 'tcx> MaybeUninitializedPlaces<'a, 'mir, 'tcx> { } } -impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, '_, 'tcx> { +impl<'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { self.move_data } @@ -251,24 +251,24 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { /// c = S; // {a, b, c, d } /// } /// ``` -pub struct EverInitializedPlaces<'a, 'mir, 'tcx> { - body: &'mir Body<'tcx>, +pub struct EverInitializedPlaces<'a, 'tcx> { + body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>, } -impl<'a, 'mir, 'tcx> EverInitializedPlaces<'a, 'mir, 'tcx> { - pub fn new(body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self { +impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { + pub fn new(body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self { EverInitializedPlaces { body, move_data } } } -impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, '_, 'tcx> { +impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { self.move_data } } -impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> { +impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { fn update_bits( trans: &mut impl GenKill, path: MovePathIndex, @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> { } } -impl<'a, 'tcx> MaybeUninitializedPlaces<'a, '_, 'tcx> { +impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { fn update_bits( trans: &mut impl GenKill, path: MovePathIndex, @@ -307,7 +307,7 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = MaybeReachable>; @@ -329,7 +329,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { +impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; fn domain_size(&self, _: &Body<'tcx>) -> usize { @@ -442,7 +442,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = ChunkedBitSet; @@ -466,7 +466,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> { +impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; fn domain_size(&self, _: &Body<'tcx>) -> usize { @@ -643,7 +643,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { /// There can be many more `InitIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = ChunkedBitSet; @@ -662,7 +662,7 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> { +impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { type Idx = InitIndex; fn domain_size(&self, _: &Body<'tcx>) -> usize { diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 24a4b32ceb7c4..1559c131a3783 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -217,7 +217,6 @@ impl DefUse { /// This is basically written for dead store elimination and nothing else. /// /// All of the caveats of `MaybeLiveLocals` apply. -#[derive(Clone, Copy)] pub struct MaybeTransitiveLiveLocals<'a> { always_live: &'a BitSet, } diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index f283660e1e793..9b5bfa9bfa00a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -7,7 +7,7 @@ mod initialized; mod liveness; mod storage_liveness; -pub use self::borrowed_locals::{borrowed_locals, MaybeBorrowedLocals}; +pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals}; pub use self::initialized::{ DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 9f2f0187698a8..34ac5809a2e2b 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -7,7 +7,6 @@ use rustc_middle::mir::*; use super::MaybeBorrowedLocals; use crate::{GenKill, ResultsCursor}; -#[derive(Clone)] pub struct MaybeStorageLive<'a> { always_live_locals: Cow<'a, BitSet>, } @@ -18,7 +17,7 @@ impl<'a> MaybeStorageLive<'a> { } } -impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { +impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { type Domain = BitSet; const NAME: &'static str = "maybe_storage_live"; @@ -40,7 +39,7 @@ impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { } } -impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { +impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { type Idx = Local; fn domain_size(&self, body: &Body<'tcx>) -> usize { @@ -80,7 +79,6 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { } } -#[derive(Clone)] pub struct MaybeStorageDead<'a> { always_live_locals: Cow<'a, BitSet>, } @@ -91,7 +89,7 @@ impl<'a> MaybeStorageDead<'a> { } } -impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { +impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { type Domain = BitSet; const NAME: &'static str = "maybe_storage_dead"; @@ -112,7 +110,7 @@ impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { } } -impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { +impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { type Idx = Local; fn domain_size(&self, body: &Body<'tcx>) -> usize { diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 9385b52103f69..cd926c0764129 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -3,6 +3,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(exact_size_is_empty)] +#![feature(file_buffered)] #![feature(let_chains)] #![feature(try_blocks)] #![warn(unreachable_pub)] @@ -17,9 +18,9 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine, - Forward, GenKill, GenKillAnalysis, JoinSemiLattice, MaybeReachable, Results, ResultsCursor, - ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, + Analysis, AnalysisDomain, Backward, Direction, Engine, Forward, GenKill, GenKillAnalysis, + JoinSemiLattice, MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor, + SwitchIntEdgeEffects, fmt, graphviz, lattice, visit_results, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 14390723ba4b6..3c8be2f73e14a 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; -use smallvec::{smallvec, SmallVec}; +use smallvec::{SmallVec, smallvec}; use tracing::debug; use super::abs_domain::Lift; @@ -16,6 +16,7 @@ use super::{ struct MoveDataBuilder<'a, 'tcx, F> { body: &'a Body<'tcx>, + loc: Location, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, data: MoveData<'tcx>, @@ -56,6 +57,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { MoveDataBuilder { body, + loc: Location::START, tcx, param_env, data: MoveData { @@ -107,7 +109,7 @@ enum MovePathResult { Error, } -impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { +impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { /// This creates a MovePath for a given place, returning an `MovePathError` /// if that place can't be moved from. /// @@ -116,7 +118,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { /// /// Maybe we should have separate "borrowck" and "moveck" modes. fn move_path_for(&mut self, place: Place<'tcx>) -> MovePathResult { - let data = &mut self.builder.data; + let data = &mut self.data; debug!("lookup({:?})", place); let Some(mut base) = data.rev_lookup.find_local(place.local) else { @@ -131,8 +133,8 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { let mut union_path = None; for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) { - let body = self.builder.body; - let tcx = self.builder.tcx; + let body = self.body; + let tcx = self.tcx; let place_ty = place_ref.ty(body, tcx).ty; if place_ty.references_error() { return MovePathResult::Error; @@ -238,7 +240,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ProjectionElem::Downcast(_, _) => (), } let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty; - if !(self.builder.filter)(elem_ty) { + if !(self.filter)(elem_ty) { return MovePathResult::Error; } if union_path.is_none() { @@ -274,7 +276,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. }, tcx, .. - } = self.builder; + } = self; *rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || { new_move_path(move_paths, path_map, init_path_map, Some(base), mk_place(*tcx)) }) @@ -285,9 +287,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { // drop), so this not being a valid move path is OK. let _ = self.move_path_for(place); } -} -impl<'a, 'tcx, F> MoveDataBuilder<'a, 'tcx, F> { fn finalize(self) -> MoveData<'tcx> { debug!("{}", { debug!("moves for {:?}:", self.body.span); @@ -317,12 +317,12 @@ pub(super) fn gather_moves<'tcx>( for (bb, block) in body.basic_blocks.iter_enumerated() { for (i, stmt) in block.statements.iter().enumerate() { - let source = Location { block: bb, statement_index: i }; - builder.gather_statement(source, stmt); + builder.loc = Location { block: bb, statement_index: i }; + builder.gather_statement(stmt); } - let terminator_loc = Location { block: bb, statement_index: block.statements.len() }; - builder.gather_terminator(terminator_loc, block.terminator()); + builder.loc = Location { block: bb, statement_index: block.statements.len() }; + builder.gather_terminator(block.terminator()); } builder.finalize() @@ -345,30 +345,14 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { } } - fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { - debug!("gather_statement({:?}, {:?})", loc, stmt); - (Gatherer { builder: self, loc }).gather_statement(stmt); - } - - fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) { - debug!("gather_terminator({:?}, {:?})", loc, term); - (Gatherer { builder: self, loc }).gather_terminator(term); - } -} - -struct Gatherer<'b, 'a, 'tcx, F> { - builder: &'b mut MoveDataBuilder<'a, 'tcx, F>, - loc: Location, -} - -impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { + debug!("gather_statement({:?}, {:?})", self.loc, stmt); match &stmt.kind { StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => { let local = place.as_local().unwrap(); - assert!(self.builder.body.local_decls[local].is_deref_temp()); + assert!(self.body.local_decls[local].is_deref_temp()); - let rev_lookup = &mut self.builder.data.rev_lookup; + let rev_lookup = &mut self.data.rev_lookup; rev_lookup.un_derefer.insert(local, reffed.as_ref()); let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local; @@ -380,7 +364,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { // Box starts out uninitialized - need to create a separate // move-path for the interior so it will be separate from // the exterior. - self.create_move_path(self.builder.tcx.mk_place_deref(*place)); + self.create_move_path(self.tcx.mk_place_deref(*place)); self.gather_init(place.as_ref(), InitKind::Shallow); } else { self.gather_init(place.as_ref(), InitKind::Deep); @@ -393,7 +377,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { StatementKind::StorageLive(_) => {} StatementKind::StorageDead(local) => { // DerefTemp locals (results of CopyForDeref) don't actually move anything. - if !self.builder.body.local_decls[*local].is_deref_temp() { + if !self.body.local_decls[*local].is_deref_temp() { self.gather_move(Place::from(*local)); } } @@ -443,6 +427,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { } fn gather_terminator(&mut self, term: &Terminator<'tcx>) { + debug!("gather_terminator({:?}, {:?})", self.loc, term); match term.kind { TerminatorKind::Goto { target: _ } | TerminatorKind::FalseEdge { .. } @@ -551,7 +536,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { // `ConstIndex` patterns. This is done to ensure that all move paths // are disjoint, which is expected by drop elaboration. let base_place = - Place { local: place.local, projection: self.builder.tcx.mk_place_elems(base) }; + Place { local: place.local, projection: self.tcx.mk_place_elems(base) }; let base_path = match self.move_path_for(base_place) { MovePathResult::Path(path) => path, MovePathResult::Union(path) => { @@ -562,11 +547,9 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { return; } }; - let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; + let base_ty = base_place.ty(self.body, self.tcx).ty; let len: u64 = match base_ty.kind() { - ty::Array(_, size) => { - size.eval_target_usize(self.builder.tcx, self.builder.param_env) - } + ty::Array(_, size) => size.eval_target_usize(self.tcx, self.param_env), _ => bug!("from_end: false slice pattern of non-array type"), }; for offset in from..to { @@ -587,13 +570,13 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { } fn record_move(&mut self, place: Place<'tcx>, path: MovePathIndex) { - let move_out = self.builder.data.moves.push(MoveOut { path, source: self.loc }); + let move_out = self.data.moves.push(MoveOut { path, source: self.loc }); debug!( "gather_move({:?}, {:?}): adding move {:?} of {:?}", self.loc, place, move_out, path ); - self.builder.data.path_map[path].push(move_out); - self.builder.data.loc_map[self.loc].push(move_out); + self.data.path_map[path].push(move_out); + self.data.loc_map[self.loc].push(move_out); } fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) { @@ -604,13 +587,13 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { // Check if we are assigning into a field of a union, if so, lookup the place // of the union so it is marked as initialized again. if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() { - if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() { + if place_base.ty(self.body, self.tcx).ty.is_union() { place = place_base; } } - if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) { - let init = self.builder.data.inits.push(Init { + if let LookupResult::Exact(path) = self.data.rev_lookup.find(place) { + let init = self.data.inits.push(Init { location: InitLocation::Statement(self.loc), path, kind, @@ -621,8 +604,8 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { self.loc, place, init, path ); - self.builder.data.init_path_map[path].push(init); - self.builder.data.init_loc_map[self.loc].push(init); + self.data.init_path_map[path].push(init); + self.data.init_loc_map[self.loc].push(init); } } } diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 4be7492366ad3..73abb669a1117 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::{self, BasicBlock, Body, Location}; -use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor}; +use crate::framework::{ResultsVisitable, ResultsVisitor, visit_results}; /// Maps between a `Location` and a `PointIndex` (and vice versa). pub struct DenseLocationMap { @@ -102,7 +102,7 @@ pub fn save_as_intervals<'tcx, N, R>( ) -> SparseIntervalMatrix where N: Idx, - R: ResultsVisitable<'tcx, FlowState = BitSet>, + R: ResultsVisitable<'tcx, Domain = BitSet>, { let values = SparseIntervalMatrix::new(elements.num_points()); let mut visitor = Visitor { elements, values }; @@ -124,12 +124,12 @@ impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N> where N: Idx, { - type FlowState = BitSet; + type Domain = BitSet; fn visit_statement_after_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, location: Location, ) { @@ -143,7 +143,7 @@ where fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &'mir mir::Terminator<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 0171cc8591809..75732b19cd0b2 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -1,10 +1,10 @@ use rustc_ast::MetaItem; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, Body, Local, Location, MirPass}; +use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use tracing::{debug, info}; use crate::errors::{ @@ -18,8 +18,6 @@ use crate::impls::{ use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex}; use crate::{Analysis, JoinSemiLattice, ResultsCursor}; -pub struct SanityCheck; - fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option { for attr in tcx.get_attrs(def_id, sym::rustc_mir) { let items = attr.meta_item_list(); @@ -33,53 +31,50 @@ fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option MirPass<'tcx> for SanityCheck { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let def_id = body.source.def_id(); - if !tcx.has_attr(def_id, sym::rustc_mir) { - debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); - return; - } else { - debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); - } +pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id(); + if !tcx.has_attr(def_id, sym::rustc_mir) { + debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); + return; + } else { + debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); + } - let param_env = tcx.param_env(def_id); - let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); + let param_env = tcx.param_env(def_id); + let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); - if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { - let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { + let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) + .into_engine(tcx, body) + .iterate_to_fixpoint(); - sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body)); - } + sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body)); + } - if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() { - let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() { + let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) + .into_engine(tcx, body) + .iterate_to_fixpoint(); - sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body)); - } + sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body)); + } - if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() { - let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() { + let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data) + .into_engine(tcx, body) + .iterate_to_fixpoint(); - sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body)); - } + sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body)); + } - if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() { - let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); + if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() { + let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); - sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body)); - } + sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body)); + } - if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() { - tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation); - } + if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() { + tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation); } } @@ -234,7 +229,7 @@ trait RustcPeekAt<'tcx>: Analysis<'tcx> { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &Self::Domain, + state: &Self::Domain, call: PeekCall, ); } @@ -248,12 +243,12 @@ where &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &Self::Domain, + state: &Self::Domain, call: PeekCall, ) { match self.move_data().rev_lookup.find(place.as_ref()) { LookupResult::Exact(peek_mpi) => { - let bit_state = flow_state.contains(peek_mpi); + let bit_state = state.contains(peek_mpi); debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state); if !bit_state { tcx.dcx().emit_err(PeekBitNotSet { span: call.span }); @@ -272,7 +267,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &BitSet, + state: &BitSet, call: PeekCall, ) { info!(?place, "peek_at"); @@ -281,7 +276,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { return; }; - if !flow_state.contains(local) { + if !state.contains(local) { tcx.dcx().emit_err(PeekBitNotSet { span: call.span }); } } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 2b20a35b61e29..aa09fe1dd45e9 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -39,8 +39,8 @@ use std::ops::Range; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; @@ -923,14 +923,14 @@ impl<'tcx> Map<'tcx> { } } -struct PlaceCollector<'a, 'b, 'tcx> { +struct PlaceCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'b Body<'tcx>, + body: &'a Body<'tcx>, map: &'a mut Map<'tcx>, assignments: FxIndexSet<(PlaceIndex, PlaceIndex)>, } -impl<'tcx> PlaceCollector<'_, '_, 'tcx> { +impl<'tcx> PlaceCollector<'_, 'tcx> { #[tracing::instrument(level = "trace", skip(self))] fn register_place(&mut self, place: Place<'tcx>) -> Option { // Create a place for this projection. @@ -967,7 +967,7 @@ impl<'tcx> PlaceCollector<'_, '_, 'tcx> { } } -impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> { +impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> { #[tracing::instrument(level = "trace", skip(self))] fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, _: Location) { if !ctxt.is_use() { diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index edb6bc4fbea2f..d889bc90c9d74 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -1,9 +1,9 @@ use rustc_ast::InlineAsmOptions; use rustc_middle::mir::*; use rustc_middle::span_bug; -use rustc_middle::ty::{self, layout, TyCtxt}; -use rustc_target::spec::abi::Abi; +use rustc_middle::ty::{self, TyCtxt, layout}; use rustc_target::spec::PanicStrategy; +use rustc_target::spec::abi::Abi; /// A pass that runs which is targeted at ensuring that codegen guarantees about /// unwinding are upheld for compilations of panic=abort programs. @@ -20,9 +20,9 @@ use rustc_target::spec::PanicStrategy; /// This forces all unwinds, in panic=abort mode happening in foreign code, to /// trigger a process abort. #[derive(PartialEq)] -pub struct AbortUnwindingCalls; +pub(super) struct AbortUnwindingCalls; -impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { +impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let def_id = body.source.def_id(); let kind = tcx.def_kind(def_id); @@ -50,9 +50,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { // with a function call, and whose function we're calling may unwind. // This will filter to functions with `extern "C-unwind"` ABIs, for // example. - let mut calls_to_terminate = Vec::new(); - let mut cleanups_to_remove = Vec::new(); - for (id, block) in body.basic_blocks.iter_enumerated() { + for block in body.basic_blocks.as_mut() { if block.is_cleanup { continue; } @@ -61,7 +59,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { let call_can_unwind = match &terminator.kind { TerminatorKind::Call { func, .. } => { - let ty = func.ty(body, tcx); + let ty = func.ty(&body.local_decls, tcx); let sig = ty.fn_sig(tcx); let fn_def_id = match ty.kind() { ty::FnPtr(..) => None, @@ -86,33 +84,22 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { _ => continue, }; - // If this function call can't unwind, then there's no need for it - // to have a landing pad. This means that we can remove any cleanup - // registered for it. if !call_can_unwind { - cleanups_to_remove.push(id); - continue; - } - - // Otherwise if this function can unwind, then if the outer function - // can also unwind there's nothing to do. If the outer function - // can't unwind, however, we need to change the landing pad for this - // function call to one that aborts. - if !body_can_unwind { - calls_to_terminate.push(id); + // If this function call can't unwind, then there's no need for it + // to have a landing pad. This means that we can remove any cleanup + // registered for it. + let cleanup = block.terminator_mut().unwind_mut().unwrap(); + *cleanup = UnwindAction::Unreachable; + } else if !body_can_unwind { + // Otherwise if this function can unwind, then if the outer function + // can also unwind there's nothing to do. If the outer function + // can't unwind, however, we need to change the landing pad for this + // function call to one that aborts. + let cleanup = block.terminator_mut().unwind_mut().unwrap(); + *cleanup = UnwindAction::Terminate(UnwindTerminateReason::Abi); } } - for id in calls_to_terminate { - let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap(); - *cleanup = UnwindAction::Terminate(UnwindTerminateReason::Abi); - } - - for id in cleanups_to_remove { - let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap(); - *cleanup = UnwindAction::Unreachable; - } - // We may have invalidated some `cleanup` blocks so clean those up now. super::simplify::remove_dead_blocks(body); } diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index df5312d155c13..24c955c0c78c6 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -4,11 +4,11 @@ use rustc_middle::ty::TyCtxt; use tracing::debug; #[derive(PartialEq)] -pub enum AddCallGuards { +pub(super) enum AddCallGuards { AllCallEdges, CriticalCallEdges, } -pub use self::AddCallGuards::*; +pub(super) use self::AddCallGuards::*; /** * Breaks outgoing critical edges for call terminators in the MIR. @@ -30,14 +30,8 @@ pub use self::AddCallGuards::*; * */ -impl<'tcx> MirPass<'tcx> for AddCallGuards { +impl<'tcx> crate::MirPass<'tcx> for AddCallGuards { fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - self.add_call_guards(body); - } -} - -impl AddCallGuards { - pub fn add_call_guards(&self, body: &mut Body<'_>) { let mut pred_count: IndexVec<_, _> = body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect(); pred_count[START_BLOCK] += 1; diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index 61a1d8cc90240..559df222a5040 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -35,40 +35,39 @@ use crate::util; /// /// The storage instructions are required to avoid stack space /// blowup. -pub struct AddMovesForPackedDrops; +pub(super) struct AddMovesForPackedDrops; -impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops { +impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span); - add_moves_for_packed_drops(tcx, body); - } -} - -pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let patch = add_moves_for_packed_drops_patch(tcx, body); - patch.apply(body); -} -fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> MirPatch<'tcx> { - let def_id = body.source.def_id(); - let mut patch = MirPatch::new(body); - let param_env = tcx.param_env(def_id); + let def_id = body.source.def_id(); + let mut patch = MirPatch::new(body); + let param_env = tcx.param_env(def_id); - for (bb, data) in body.basic_blocks.iter_enumerated() { - let loc = Location { block: bb, statement_index: data.statements.len() }; - let terminator = data.terminator(); + for (bb, data) in body.basic_blocks.iter_enumerated() { + let loc = Location { block: bb, statement_index: data.statements.len() }; + let terminator = data.terminator(); - match terminator.kind { - TerminatorKind::Drop { place, .. } - if util::is_disaligned(tcx, body, param_env, place) => - { - add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup); + match terminator.kind { + TerminatorKind::Drop { place, .. } + if util::is_disaligned(tcx, body, param_env, place) => + { + add_move_for_packed_drop( + tcx, + body, + &mut patch, + terminator, + loc, + data.is_cleanup, + ); + } + _ => {} } - _ => {} } - } - patch + patch.apply(body); + } } fn add_move_for_packed_drop<'tcx>( @@ -86,7 +85,7 @@ fn add_move_for_packed_drop<'tcx>( let source_info = terminator.source_info; let ty = place.ty(body, tcx).ty; - let temp = patch.new_temp(ty, terminator.source_info.span); + let temp = patch.new_temp(ty, source_info.span); let storage_dead_block = patch.new_block(BasicBlockData { statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }], @@ -96,13 +95,10 @@ fn add_move_for_packed_drop<'tcx>( patch.add_statement(loc, StatementKind::StorageLive(temp)); patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); - patch.patch_terminator( - loc.block, - TerminatorKind::Drop { - place: Place::from(temp), - target: storage_dead_block, - unwind, - replace, - }, - ); + patch.patch_terminator(loc.block, TerminatorKind::Drop { + place: Place::from(temp), + target: storage_dead_block, + unwind, + replace, + }); } diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 79bc21cab147e..53176eec9bcb9 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -8,7 +8,7 @@ use rustc_hir::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; -pub struct AddRetag; +pub(super) struct AddRetag; /// Determine whether this type may contain a reference (or box), and thus needs retagging. /// We will only recurse `depth` times into Tuples/ADTs to bound the cost of this. @@ -48,7 +48,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b } } -impl<'tcx> MirPass<'tcx> for AddRetag { +impl<'tcx> crate::MirPass<'tcx> for AddRetag { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.opts.unstable_opts.mir_emit_retag } @@ -60,7 +60,9 @@ impl<'tcx> MirPass<'tcx> for AddRetag { let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &body.local_decls; let needs_retag = |place: &Place<'tcx>| { - !place.is_indirect_first_projection() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway + // We're not really interested in stores to "outside" locations, they are hard to keep + // track of anyway. + !place.is_indirect_first_projection() && may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx) && !local_decls[place.local].is_deref_temp() }; @@ -109,13 +111,10 @@ impl<'tcx> MirPass<'tcx> for AddRetag { .collect::>(); // Now we go over the returns we collected to retag the return values. for (source_info, dest_place, dest_block) in returns { - basic_blocks[dest_block].statements.insert( - 0, - Statement { - source_info, - kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)), - }, - ); + basic_blocks[dest_block].statements.insert(0, Statement { + source_info, + kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)), + }); } // PART 3 @@ -129,9 +128,9 @@ impl<'tcx> MirPass<'tcx> for AddRetag { StatementKind::Assign(box (ref place, ref rvalue)) => { let add_retag = match rvalue { // Ptr-creating operations already do their own internal retagging, no - // need to also add a retag statement. - // *Except* if we are deref'ing a Box, because those get desugared to directly working - // with the inner raw pointer! That's relevant for `RawPtr` as Miri otherwise makes it + // need to also add a retag statement. *Except* if we are deref'ing a + // Box, because those get desugared to directly working with the inner + // raw pointer! That's relevant for `RawPtr` as Miri otherwise makes it // a NOP when the original pointer is already raw. Rvalue::RawPtr(_mutbl, place) => { // Using `is_box_global` here is a bit sketchy: if this code is @@ -170,13 +169,10 @@ impl<'tcx> MirPass<'tcx> for AddRetag { }; // Insert a retag after the statement. let source_info = block_data.statements[i].source_info; - block_data.statements.insert( - i + 1, - Statement { - source_info, - kind: StatementKind::Retag(retag_kind, Box::new(place)), - }, - ); + block_data.statements.insert(i + 1, Statement { + source_info, + kind: StatementKind::Retag(retag_kind, Box::new(place)), + }); } } } diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index 04204c68f7b76..e585e338613d8 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -1,15 +1,14 @@ -use rustc_index::IndexVec; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -pub struct Subtyper; +pub(super) struct Subtyper; -pub struct SubTypeChecker<'a, 'tcx> { +struct SubTypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, patcher: MirPatch<'tcx>, - local_decls: &'a IndexVec>, + local_decls: &'a LocalDecls<'tcx>, } impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { @@ -52,18 +51,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { // // gets transformed to // let temp: rval_ty = rval; // let place: place_ty = temp as place_ty; -pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let patch = MirPatch::new(body); - let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls }; - - for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { - checker.visit_basic_block_data(bb, data); - } - checker.patcher.apply(body); -} - -impl<'tcx> MirPass<'tcx> for Subtyper { +impl<'tcx> crate::MirPass<'tcx> for Subtyper { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - subtype_finder(tcx, body); + let patch = MirPatch::new(body); + let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls }; + + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + checker.visit_basic_block_data(bb, data); + } + checker.patcher.apply(body); } } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index ad362f22ce197..a9600f77c0b6e 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -7,9 +7,9 @@ use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_session::Session; use tracing::{debug, trace}; -pub struct CheckAlignment; +pub(super) struct CheckAlignment; -impl<'tcx> MirPass<'tcx> for CheckAlignment { +impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { fn is_enabled(&self, sess: &Session) -> bool { // FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows if sess.target.llvm_target == "i686-pc-windows-msvc" { @@ -62,14 +62,14 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { } } -struct PointerFinder<'tcx, 'a> { +struct PointerFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a mut LocalDecls<'tcx>, param_env: ParamEnv<'tcx>, pointers: Vec<(Place<'tcx>, Ty<'tcx>)>, } -impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { // We want to only check reads and writes to Places, so we specifically exclude // Borrow and RawBorrow. diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 1f615c9d8d1a2..7968b666dff2f 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -3,14 +3,14 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::CONST_ITEM_MUTATION; -use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_span::def_id::DefId; -use crate::{errors, MirLint}; +use crate::errors; -pub struct CheckConstItemMutation; +pub(super) struct CheckConstItemMutation; -impl<'tcx> MirLint<'tcx> for CheckConstItemMutation { +impl<'tcx> crate::MirLint<'tcx> for CheckConstItemMutation { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let mut checker = ConstMutationChecker { body, tcx, target_local: None }; checker.visit_body(body); @@ -95,19 +95,19 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { // Check for assignment to fields of a constant // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error, // so emitting a lint would be redundant. - if !lhs.projection.is_empty() { - if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) - && let Some((lint_root, span, item)) = - self.should_lint_const_item_usage(lhs, def_id, loc) - { - self.tcx.emit_node_span_lint( - CONST_ITEM_MUTATION, - lint_root, - span, - errors::ConstMutate::Modify { konst: item }, - ); - } + if !lhs.projection.is_empty() + && let Some(def_id) = self.is_const_item_without_destructor(lhs.local) + && let Some((lint_root, span, item)) = + self.should_lint_const_item_usage(lhs, def_id, loc) + { + self.tcx.emit_node_span_lint( + CONST_ITEM_MUTATION, + lint_root, + span, + errors::ConstMutate::Modify { konst: item }, + ); } + // We are looking for MIR of the form: // // ``` @@ -123,6 +123,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { self.super_statement(stmt, loc); self.target_local = None; } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue { let local = place.local; diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 9902002580aed..1922d4fef25de 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -3,11 +3,11 @@ use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt}; -use crate::{errors, util, MirLint}; +use crate::{errors, util}; -pub struct CheckPackedRef; +pub(super) struct CheckPackedRef; -impl<'tcx> MirLint<'tcx> for CheckPackedRef { +impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let param_env = tcx.param_env(body.source.def_id()); let source_info = SourceInfo::outermost(body.span); @@ -37,24 +37,17 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - if context.is_borrow() { - if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { - let def_id = self.body.source.instance.def_id(); - if let Some(impl_def_id) = self.tcx.impl_of_method(def_id) - && self.tcx.is_builtin_derived(impl_def_id) - { - // If we ever reach here it means that the generated derive - // code is somehow doing an unaligned reference, which it - // shouldn't do. - span_bug!( - self.source_info.span, - "builtin derive created an unaligned reference" - ); - } else { - self.tcx - .dcx() - .emit_err(errors::UnalignedPackedRef { span: self.source_info.span }); - } + if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.param_env, *place) { + let def_id = self.body.source.instance.def_id(); + if let Some(impl_def_id) = self.tcx.impl_of_method(def_id) + && self.tcx.is_builtin_derived(impl_def_id) + { + // If we ever reach here it means that the generated derive + // code is somehow doing an unaligned reference, which it + // shouldn't do. + span_bug!(self.source_info.span, "builtin derive created an unaligned reference"); + } else { + self.tcx.dcx().emit_err(errors::UnalignedPackedRef { span: self.source_info.span }); } } } diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 08c9f9f08e6b2..6a22a58470c95 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -18,14 +18,12 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{Body, BorrowKind, CastKind, Rvalue, StatementKind, TerminatorKind}; -use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::adjustment::PointerCoercion; -use crate::MirPass; - -pub struct CleanupPostBorrowck; +pub(super) struct CleanupPostBorrowck; -impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck { +impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck { fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { for basic_block in body.basic_blocks.as_mut() { for statement in basic_block.statements.iter_mut() { @@ -44,6 +42,7 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck { ref mut cast_kind @ CastKind::PointerCoercion( PointerCoercion::ArrayToPointer | PointerCoercion::MutToConstPointer, + _, ), .., ), diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 5c267f853783f..7d6ae9843b15f 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -1,5 +1,5 @@ -use rustc_index::bit_set::BitSet; use rustc_index::IndexSlice; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; @@ -17,9 +17,9 @@ use crate::ssa::SsaLocals; /// where each of the locals is only assigned once. /// /// We want to replace all those locals by `_a`, either copied or moved. -pub struct CopyProp; +pub(super) struct CopyProp; -impl<'tcx> MirPass<'tcx> for CopyProp { +impl<'tcx> crate::MirPass<'tcx> for CopyProp { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 1 } @@ -27,37 +27,34 @@ impl<'tcx> MirPass<'tcx> for CopyProp { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - propagate_ssa(tcx, body); - } -} -fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let ssa = SsaLocals::new(tcx, body, param_env); - let fully_moved = fully_moved_locals(&ssa, body); - debug!(?fully_moved); + let fully_moved = fully_moved_locals(&ssa, body); + debug!(?fully_moved); - let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size()); - for (local, &head) in ssa.copy_classes().iter_enumerated() { - if local != head { - storage_to_remove.insert(head); + let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size()); + for (local, &head) in ssa.copy_classes().iter_enumerated() { + if local != head { + storage_to_remove.insert(head); + } } - } - let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h); + let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h); - Replacer { - tcx, - copy_classes: ssa.copy_classes(), - fully_moved, - borrowed_locals: ssa.borrowed_locals(), - storage_to_remove, - } - .visit_body_preserves_cfg(body); + Replacer { + tcx, + copy_classes: ssa.copy_classes(), + fully_moved, + borrowed_locals: ssa.borrowed_locals(), + storage_to_remove, + } + .visit_body_preserves_cfg(body); - if any_replacement { - crate::simplify::remove_unused_definitions(body); + if any_replacement { + crate::simplify::remove_unused_definitions(body); + } } } @@ -140,7 +137,8 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { if let Operand::Move(place) = *operand - // A move out of a projection of a copy is equivalent to a copy of the original projection. + // A move out of a projection of a copy is equivalent to a copy of the original + // projection. && !place.is_indirect_first_projection() && !self.fully_moved.contains(place.local) { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 8051fca9e7c9d..8f032728f6be0 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -53,7 +53,7 @@ mod by_move_body; use std::{iter, ops}; -pub use by_move_body::coroutine_by_move_body_def_id; +pub(super) use by_move_body::coroutine_by_move_body_def_id; use rustc_data_structures::fx::FxHashSet; use rustc_errors::pluralize; use rustc_hir as hir; @@ -63,16 +63,18 @@ use rustc_index::bit_set::{BitMatrix, BitSet, GrowableBitSet}; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, InstanceKind, Ty, TyCtxt}; +use rustc_middle::ty::{ + self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, +}; use rustc_middle::{bug, span_bug}; +use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::{ MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, }; use rustc_mir_dataflow::storage::always_storage_live_locals; -use rustc_mir_dataflow::Analysis; +use rustc_span::Span; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::sym; -use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::spec::PanicStrategy; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -83,7 +85,7 @@ use tracing::{debug, instrument, trace}; use crate::deref_separator::deref_finder; use crate::{abort_unwinding_calls, errors, pass_manager as pm, simplify}; -pub struct StateTransform; +pub(super) struct StateTransform; struct RenameLocalVisitor<'tcx> { from: Local, @@ -113,47 +115,18 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> { } } -struct DerefArgVisitor<'tcx> { +struct SelfArgVisitor<'tcx> { tcx: TyCtxt<'tcx>, + new_base: Place<'tcx>, } -impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - assert_ne!(*local, SELF_ARG); - } - - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.local == SELF_ARG { - replace_base( - place, - Place { - local: SELF_ARG, - projection: self.tcx().mk_place_elems(&[ProjectionElem::Deref]), - }, - self.tcx, - ); - } else { - self.visit_local(&mut place.local, context, location); - - for elem in place.projection.iter() { - if let PlaceElem::Index(local) = elem { - assert_ne!(local, SELF_ARG); - } - } - } +impl<'tcx> SelfArgVisitor<'tcx> { + fn new(tcx: TyCtxt<'tcx>, elem: ProjectionElem>) -> Self { + Self { tcx, new_base: Place { local: SELF_ARG, projection: tcx.mk_place_elems(&[elem]) } } } } -struct PinArgVisitor<'tcx> { - ref_coroutine_ty: Ty<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { +impl<'tcx> MutVisitor<'tcx> for SelfArgVisitor<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -164,17 +137,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { if place.local == SELF_ARG { - replace_base( - place, - Place { - local: SELF_ARG, - projection: self.tcx().mk_place_elems(&[ProjectionElem::Field( - FieldIdx::ZERO, - self.ref_coroutine_ty, - )]), - }, - self.tcx, - ); + replace_base(place, self.new_base, self.tcx); } else { self.visit_local(&mut place.local, context, location); @@ -198,15 +161,6 @@ fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtx const SELF_ARG: Local = Local::from_u32(1); -/// Coroutine has not been resumed yet. -const UNRESUMED: usize = CoroutineArgs::UNRESUMED; -/// Coroutine has returned / is completed. -const RETURNED: usize = CoroutineArgs::RETURNED; -/// Coroutine has panicked and is poisoned. -const POISONED: usize = CoroutineArgs::POISONED; -/// Number of reserved variants of coroutine state. -const RESERVED_VARIANTS: usize = CoroutineArgs::RESERVED_VARIANTS; - /// A `yield` point in the coroutine. struct SuspensionPoint<'tcx> { /// State discriminant used when suspending or resuming at this point. @@ -261,14 +215,10 @@ impl<'tcx> TransformVisitor<'tcx> { // `gen` continues return `None` CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); - Rvalue::Aggregate( - Box::new(AggregateKind::Adt( - option_def_id, - VariantIdx::ZERO, - self.tcx.mk_args(&[self.old_yield_ty.into()]), - None, - None, - )), + make_aggregate_adt( + option_def_id, + VariantIdx::ZERO, + self.tcx.mk_args(&[self.old_yield_ty.into()]), IndexVec::new(), ) } @@ -317,64 +267,28 @@ impl<'tcx> TransformVisitor<'tcx> { is_return: bool, statements: &mut Vec>, ) { + const ZERO: VariantIdx = VariantIdx::ZERO; + const ONE: VariantIdx = VariantIdx::from_usize(1); let rvalue = match self.coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, None); let args = self.tcx.mk_args(&[self.old_ret_ty.into()]); - if is_return { - // Poll::Ready(val) - Rvalue::Aggregate( - Box::new(AggregateKind::Adt( - poll_def_id, - VariantIdx::ZERO, - args, - None, - None, - )), - IndexVec::from_raw(vec![val]), - ) + let (variant_idx, operands) = if is_return { + (ZERO, IndexVec::from_raw(vec![val])) // Poll::Ready(val) } else { - // Poll::Pending - Rvalue::Aggregate( - Box::new(AggregateKind::Adt( - poll_def_id, - VariantIdx::from_usize(1), - args, - None, - None, - )), - IndexVec::new(), - ) - } + (ONE, IndexVec::new()) // Poll::Pending + }; + make_aggregate_adt(poll_def_id, variant_idx, args, operands) } CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); let args = self.tcx.mk_args(&[self.old_yield_ty.into()]); - if is_return { - // None - Rvalue::Aggregate( - Box::new(AggregateKind::Adt( - option_def_id, - VariantIdx::ZERO, - args, - None, - None, - )), - IndexVec::new(), - ) + let (variant_idx, operands) = if is_return { + (ZERO, IndexVec::new()) // None } else { - // Some(val) - Rvalue::Aggregate( - Box::new(AggregateKind::Adt( - option_def_id, - VariantIdx::from_usize(1), - args, - None, - None, - )), - IndexVec::from_raw(vec![val]), - ) - } + (ONE, IndexVec::from_raw(vec![val])) // Some(val) + }; + make_aggregate_adt(option_def_id, variant_idx, args, operands) } CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => { if is_return { @@ -400,31 +314,17 @@ impl<'tcx> TransformVisitor<'tcx> { let coroutine_state_def_id = self.tcx.require_lang_item(LangItem::CoroutineState, None); let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]); - if is_return { - // CoroutineState::Complete(val) - Rvalue::Aggregate( - Box::new(AggregateKind::Adt( - coroutine_state_def_id, - VariantIdx::from_usize(1), - args, - None, - None, - )), - IndexVec::from_raw(vec![val]), - ) + let variant_idx = if is_return { + ONE // CoroutineState::Complete(val) } else { - // CoroutineState::Yielded(val) - Rvalue::Aggregate( - Box::new(AggregateKind::Adt( - coroutine_state_def_id, - VariantIdx::ZERO, - args, - None, - None, - )), - IndexVec::from_raw(vec![val]), - ) - } + ZERO // CoroutineState::Yielded(val) + }; + make_aggregate_adt( + coroutine_state_def_id, + variant_idx, + args, + IndexVec::from_raw(vec![val]), + ) } }; @@ -517,7 +417,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { self.make_state(v, source_info, is_return, &mut data.statements); let state = if let Some((resume, mut resume_arg)) = resume { // Yield - let state = RESERVED_VARIANTS + self.suspension_points.len(); + let state = CoroutineArgs::RESERVED_VARIANTS + self.suspension_points.len(); // The resume arg target location might itself be remapped if its base local is // live across a yield. @@ -550,7 +450,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { VariantIdx::new(state) } else { // Return - VariantIdx::new(RETURNED) // state for returned + VariantIdx::new(CoroutineArgs::RETURNED) // state for returned }; data.statements.push(self.set_discr(state, source_info)); data.terminator_mut().kind = TerminatorKind::Return; @@ -560,6 +460,15 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { } } +fn make_aggregate_adt<'tcx>( + def_id: DefId, + variant_idx: VariantIdx, + args: GenericArgsRef<'tcx>, + operands: IndexVec>, +) -> Rvalue<'tcx> { + Rvalue::Aggregate(Box::new(AggregateKind::Adt(def_id, variant_idx, args, None, None)), operands) +} + fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let coroutine_ty = body.local_decls.raw[1].ty; @@ -569,7 +478,7 @@ fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Bo body.local_decls.raw[1].ty = ref_coroutine_ty; // Add a deref to accesses of the coroutine state - DerefArgVisitor { tcx }.visit_body(body); + SelfArgVisitor::new(tcx, ProjectionElem::Deref).visit_body(body); } fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -584,7 +493,8 @@ fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body body.local_decls.raw[1].ty = pin_ref_coroutine_ty; // Add the Pin field access to accesses of the coroutine state - PinArgVisitor { ref_coroutine_ty, tcx }.visit_body(body); + SelfArgVisitor::new(tcx, ProjectionElem::Field(FieldIdx::ZERO, ref_coroutine_ty)) + .visit_body(body); } /// Allocates a new local and replaces all references of `local` with it. Returns the new local. @@ -651,8 +561,6 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let local = eliminate_get_context_call(&mut body[bb]); replace_resume_ty_local(tcx, body, local, context_mut_ref); } - } else { - continue; } } TerminatorKind::Yield { resume_arg, .. } => { @@ -665,24 +573,23 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local { let terminator = bb_data.terminator.take().unwrap(); - if let TerminatorKind::Call { args, destination, target, .. } = terminator.kind { - let [arg] = *Box::try_from(args).unwrap(); - let local = arg.node.place().unwrap().local; - - let arg = Rvalue::Use(arg.node); - let assign = Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new((destination, arg))), - }; - bb_data.statements.push(assign); - bb_data.terminator = Some(Terminator { - source_info: terminator.source_info, - kind: TerminatorKind::Goto { target: target.unwrap() }, - }); - local - } else { + let TerminatorKind::Call { args, destination, target, .. } = terminator.kind else { bug!(); - } + }; + let [arg] = *Box::try_from(args).unwrap(); + let local = arg.node.place().unwrap().local; + + let arg = Rvalue::Use(arg.node); + let assign = Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new((destination, arg))), + }; + bb_data.statements.push(assign); + bb_data.terminator = Some(Terminator { + source_info: terminator.source_info, + kind: TerminatorKind::Goto { target: target.unwrap() }, + }); + local } #[cfg_attr(not(debug_assertions), allow(unused))] @@ -965,9 +872,9 @@ fn compute_storage_conflicts<'mir, 'tcx>( storage_conflicts } -struct StorageConflictVisitor<'mir, 'tcx, 's> { - body: &'mir Body<'tcx>, - saved_locals: &'s CoroutineSavedLocals, +struct StorageConflictVisitor<'a, 'tcx> { + body: &'a Body<'tcx>, + saved_locals: &'a CoroutineSavedLocals, // FIXME(tmandry): Consider using sparse bitsets here once we have good // benchmarks for coroutines. local_conflicts: BitMatrix, @@ -975,16 +882,16 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> { eligible_storage_live: BitSet, } -impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> - for StorageConflictVisitor<'mir, 'tcx, '_> +impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> + for StorageConflictVisitor<'a, 'tcx> { - type FlowState = BitSet; + type Domain = BitSet; fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, - _statement: &'mir Statement<'tcx>, + state: &Self::Domain, + _statement: &'a Statement<'tcx>, loc: Location, ) { self.apply_state(state, loc); @@ -993,22 +900,22 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, - _terminator: &'mir Terminator<'tcx>, + state: &Self::Domain, + _terminator: &'a Terminator<'tcx>, loc: Location, ) { self.apply_state(state, loc); } } -impl StorageConflictVisitor<'_, '_, '_> { - fn apply_state(&mut self, flow_state: &BitSet, loc: Location) { +impl StorageConflictVisitor<'_, '_> { + fn apply_state(&mut self, state: &BitSet, loc: Location) { // Ignore unreachable blocks. if let TerminatorKind::Unreachable = self.body.basic_blocks[loc.block].terminator().kind { return; } - self.eligible_storage_live.clone_from(flow_state); + self.eligible_storage_live.clone_from(state); self.eligible_storage_live.intersect(&**self.saved_locals); for local in self.eligible_storage_live.iter() { @@ -1085,10 +992,11 @@ fn compute_layout<'tcx>( // Build the coroutine variant field list. // Create a map from local indices to coroutine struct indices. let mut variant_fields: IndexVec> = - iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect(); + iter::repeat(IndexVec::new()).take(CoroutineArgs::RESERVED_VARIANTS).collect(); let mut remap = IndexVec::from_elem_n(None, saved_locals.domain_size()); for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() { - let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx); + let variant_index = + VariantIdx::from(CoroutineArgs::RESERVED_VARIANTS + suspension_point_idx); let mut fields = IndexVec::new(); for (idx, saved_local) in live_locals.iter().enumerate() { fields.push(saved_local); @@ -1146,14 +1054,11 @@ fn insert_switch<'tcx>( let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), targets: switch_targets }; let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().raw.insert( - 0, - BasicBlockData { - statements: vec![assign], - terminator: Some(Terminator { source_info, kind: switch }), - is_cleanup: false, - }, - ); + body.basic_blocks_mut().raw.insert(0, BasicBlockData { + statements: vec![assign], + terminator: Some(Terminator { source_info, kind: switch }), + is_cleanup: false, + }); let blocks = body.basic_blocks_mut().iter_mut(); @@ -1164,7 +1069,7 @@ fn insert_switch<'tcx>( fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { use rustc_middle::mir::patch::MirPatch; - use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, Unwind}; + use rustc_mir_dataflow::elaborate_drops::{Unwind, elaborate_drop}; use crate::shim::DropShimElaborator; @@ -1183,12 +1088,10 @@ fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { source_info, kind: TerminatorKind::Drop { place, target, unwind, replace: _ }, } => { - if let Some(local) = place.as_local() { - if local == SELF_ARG { - (target, unwind, source_info) - } else { - continue; - } + if let Some(local) = place.as_local() + && local == SELF_ARG + { + (target, unwind, source_info) } else { continue; } @@ -1237,7 +1140,7 @@ fn create_coroutine_drop_shim<'tcx>( let mut cases = create_cases(&mut body, transform, Operation::Drop); - cases.insert(0, (UNRESUMED, drop_clean)); + cases.insert(0, (CoroutineArgs::UNRESUMED, drop_clean)); // The returned state and the poisoned state fall through to the default // case which is just to return @@ -1293,7 +1196,7 @@ fn insert_panic_block<'tcx>( message: AssertMessage<'tcx>, ) -> BasicBlock { let assert_block = BasicBlock::new(body.basic_blocks.len()); - let term = TerminatorKind::Assert { + let kind = TerminatorKind::Assert { cond: Operand::Constant(Box::new(ConstOperand { span: body.span, user_ty: None, @@ -1305,14 +1208,7 @@ fn insert_panic_block<'tcx>( unwind: UnwindAction::Continue, }; - let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { source_info, kind: term }), - is_cleanup: false, - }); - - assert_block + insert_term_block(body, kind) } fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { @@ -1387,7 +1283,9 @@ fn create_coroutine_resume_function<'tcx>( if can_unwind { let source_info = SourceInfo::outermost(body.span); let poison_block = body.basic_blocks_mut().push(BasicBlockData { - statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)], + statements: vec![ + transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info), + ], terminator: Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }), is_cleanup: true, }); @@ -1419,13 +1317,16 @@ fn create_coroutine_resume_function<'tcx>( use rustc_middle::mir::AssertKind::{ResumedAfterPanic, ResumedAfterReturn}; // Jump to the entry point on the unresumed - cases.insert(0, (UNRESUMED, START_BLOCK)); + cases.insert(0, (CoroutineArgs::UNRESUMED, START_BLOCK)); // Panic when resumed on the returned or poisoned state if can_unwind { cases.insert( 1, - (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(transform.coroutine_kind))), + ( + CoroutineArgs::POISONED, + insert_panic_block(tcx, body, ResumedAfterPanic(transform.coroutine_kind)), + ), ); } @@ -1440,7 +1341,7 @@ fn create_coroutine_resume_function<'tcx>( transform.insert_none_ret_block(body) } }; - cases.insert(1, (RETURNED, block)); + cases.insert(1, (CoroutineArgs::RETURNED, block)); } insert_switch(body, cases, &transform, TerminatorKind::Unreachable); @@ -1624,7 +1525,7 @@ fn check_field_tys_sized<'tcx>( } } -impl<'tcx> MirPass<'tcx> for StateTransform { +impl<'tcx> crate::MirPass<'tcx> for StateTransform { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let Some(old_yield_ty) = body.yield_ty() else { // This only applies to coroutines @@ -1701,16 +1602,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // (which is now a generator interior). let source_info = SourceInfo::outermost(body.span); let stmts = &mut body.basic_blocks_mut()[START_BLOCK].statements; - stmts.insert( - 0, - Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - old_resume_local.into(), - Rvalue::Use(Operand::Move(resume_local.into())), - ))), - }, - ); + stmts.insert(0, Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + old_resume_local.into(), + Rvalue::Use(Operand::Move(resume_local.into())), + ))), + }); let always_live_locals = always_storage_live_locals(body); @@ -1947,18 +1845,12 @@ fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &CoroutineLayout<'tcx>, bo continue; }; - check_must_not_suspend_ty( - tcx, - decl.ty, - hir_id, - param_env, - SuspendCheckData { - source_span: decl.source_info.span, - yield_span: yield_source_info.span, - plural_len: 1, - ..Default::default() - }, - ); + check_must_not_suspend_ty(tcx, decl.ty, hir_id, param_env, SuspendCheckData { + source_span: decl.source_info.span, + yield_span: yield_source_info.span, + plural_len: 1, + ..Default::default() + }); } } } @@ -1998,13 +1890,10 @@ fn check_must_not_suspend_ty<'tcx>( ty::Adt(_, args) if ty.is_box() => { let boxed_ty = args.type_at(0); let allocator_ty = args.type_at(1); - check_must_not_suspend_ty( - tcx, - boxed_ty, - hir_id, - param_env, - SuspendCheckData { descr_pre: &format!("{}boxed ", data.descr_pre), ..data }, - ) || check_must_not_suspend_ty( + check_must_not_suspend_ty(tcx, boxed_ty, hir_id, param_env, SuspendCheckData { + descr_pre: &format!("{}boxed ", data.descr_pre), + ..data + }) || check_must_not_suspend_ty( tcx, allocator_ty, hir_id, @@ -2023,12 +1912,10 @@ fn check_must_not_suspend_ty<'tcx>( { let def_id = poly_trait_predicate.trait_ref.def_id; let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix); - if check_must_not_suspend_def( - tcx, - def_id, - hir_id, - SuspendCheckData { descr_pre, ..data }, - ) { + if check_must_not_suspend_def(tcx, def_id, hir_id, SuspendCheckData { + descr_pre, + ..data + }) { has_emitted = true; break; } @@ -2042,12 +1929,10 @@ fn check_must_not_suspend_ty<'tcx>( if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { let def_id = trait_ref.def_id; let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post); - if check_must_not_suspend_def( - tcx, - def_id, - hir_id, - SuspendCheckData { descr_post, ..data }, - ) { + if check_must_not_suspend_def(tcx, def_id, hir_id, SuspendCheckData { + descr_post, + ..data + }) { has_emitted = true; break; } @@ -2059,13 +1944,10 @@ fn check_must_not_suspend_ty<'tcx>( let mut has_emitted = false; for (i, ty) in fields.iter().enumerate() { let descr_post = &format!(" in tuple element {i}"); - if check_must_not_suspend_ty( - tcx, - ty, - hir_id, - param_env, - SuspendCheckData { descr_post, ..data }, - ) { + if check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData { + descr_post, + ..data + }) { has_emitted = true; } } @@ -2073,29 +1955,20 @@ fn check_must_not_suspend_ty<'tcx>( } ty::Array(ty, len) => { let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); - check_must_not_suspend_ty( - tcx, - ty, - hir_id, - param_env, - SuspendCheckData { - descr_pre, - plural_len: len.try_eval_target_usize(tcx, param_env).unwrap_or(0) as usize + 1, - ..data - }, - ) + check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData { + descr_pre, + plural_len: len.try_eval_target_usize(tcx, param_env).unwrap_or(0) as usize + 1, + ..data + }) } // If drop tracking is enabled, we want to look through references, since the referent // may not be considered live across the await point. ty::Ref(_region, ty, _mutability) => { let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix); - check_must_not_suspend_ty( - tcx, - ty, - hir_id, - param_env, - SuspendCheckData { descr_pre, ..data }, - ) + check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData { + descr_pre, + ..data + }) } _ => false, } diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index ebe8d2eff4ff3..65442877d2dd5 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -82,12 +82,17 @@ use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::kw; use rustc_target::abi::{FieldIdx, VariantIdx}; -pub fn coroutine_by_move_body_def_id<'tcx>( +pub(crate) fn coroutine_by_move_body_def_id<'tcx>( tcx: TyCtxt<'tcx>, coroutine_def_id: LocalDefId, ) -> DefId { let body = tcx.mir_built(coroutine_def_id).borrow(); + // If the typeck results are tainted, no need to make a by-ref body. + if body.tainted_by_errors.is_some() { + return coroutine_def_id.to_def_id(); + } + let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) = tcx.coroutine_kind(coroutine_def_id) else { @@ -98,7 +103,9 @@ pub fn coroutine_by_move_body_def_id<'tcx>( // the MIR body will be constructed well. let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; - let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; + let ty::Coroutine(_, args) = *coroutine_ty.kind() else { + bug!("tried to create by-move body of non-coroutine receiver"); + }; let args = args.as_coroutine(); let coroutine_kind = args.kind_ty().to_opt_closure_kind().unwrap(); @@ -107,7 +114,7 @@ pub fn coroutine_by_move_body_def_id<'tcx>( let ty::CoroutineClosure(_, parent_args) = *tcx.type_of(parent_def_id).instantiate_identity().kind() else { - bug!(); + bug!("coroutine's parent was not a coroutine-closure"); }; if parent_args.references_error() { return coroutine_def_id.to_def_id(); @@ -133,10 +140,10 @@ pub fn coroutine_by_move_body_def_id<'tcx>( // If the parent capture is by-ref, then we need to apply an additional // deref before applying any further projections to this place. if parent_capture.is_by_ref() { - child_precise_captures.insert( - 0, - Projection { ty: parent_capture.place.ty(), kind: ProjectionKind::Deref }, - ); + child_precise_captures.insert(0, Projection { + ty: parent_capture.place.ty(), + kind: ProjectionKind::Deref, + }); } // If the child capture is by-ref, then we need to apply a "ref" // projection (i.e. `&`) at the end. But wait! We don't have that @@ -207,11 +214,12 @@ pub fn coroutine_by_move_body_def_id<'tcx>( let mut by_move_body = body.clone(); MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); - dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(())); - let body_def = tcx.create_def(coroutine_def_id, kw::Empty, DefKind::SyntheticCoroutineBody); + // This will always be `{closure#1}`, since the original coroutine is `{closure#0}`. + let body_def = tcx.create_def(parent_def_id, kw::Empty, DefKind::SyntheticCoroutineBody); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); + dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); // Inherited from the by-ref coroutine. body_def.codegen_fn_attrs(tcx.codegen_fn_attrs(coroutine_def_id).clone()); diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index a1c1422912ee3..59b403538a33d 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -12,7 +12,7 @@ const CONST_SWITCH_BONUS: usize = 10; /// Verify that the callee body is compatible with the caller. #[derive(Clone)] -pub(crate) struct CostChecker<'b, 'tcx> { +pub(super) struct CostChecker<'b, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, penalty: usize, @@ -22,7 +22,7 @@ pub(crate) struct CostChecker<'b, 'tcx> { } impl<'b, 'tcx> CostChecker<'b, 'tcx> { - pub fn new( + pub(super) fn new( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, instance: Option>, @@ -36,7 +36,7 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> { /// Needed because the `CostChecker` is used sometimes for just blocks, /// and even the full `Inline` doesn't call `visit_body`, so there's nowhere /// to put this logic in the visitor. - pub fn add_function_level_costs(&mut self) { + pub(super) fn add_function_level_costs(&mut self) { fn is_call_like(bbd: &BasicBlockData<'_>) -> bool { use TerminatorKind::*; match bbd.terminator().kind { @@ -64,7 +64,7 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> { } } - pub fn cost(&self) -> usize { + pub(super) fn cost(&self) -> usize { usize::saturating_sub(self.penalty, self.bonus) } diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index ea1c0d2df4517..ef4031c5c034f 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -74,12 +74,11 @@ pub(super) struct CoverageCounters { } impl CoverageCounters { - /// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or - /// indirectly associated with coverage spans, and accumulates additional `Expression`s - /// representing intermediate values. + /// Ensures that each BCB node needing a counter has one, by creating physical + /// counters or counter expressions for nodes and edges as required. pub(super) fn make_bcb_counters( basic_coverage_blocks: &CoverageGraph, - bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, + bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool, ) -> Self { let num_bcbs = basic_coverage_blocks.num_nodes(); @@ -91,17 +90,38 @@ impl CoverageCounters { expressions_memo: FxHashMap::default(), }; - MakeBcbCounters::new(&mut this, basic_coverage_blocks) - .make_bcb_counters(bcb_has_coverage_spans); + MakeBcbCounters::new(&mut this, basic_coverage_blocks).make_bcb_counters(bcb_needs_counter); this } - fn make_counter(&mut self, site: CounterIncrementSite) -> BcbCounter { + /// Shared helper used by [`Self::make_phys_node_counter`] and + /// [`Self::make_phys_edge_counter`]. Don't call this directly. + fn make_counter_inner(&mut self, site: CounterIncrementSite) -> BcbCounter { let id = self.counter_increment_sites.push(site); BcbCounter::Counter { id } } + /// Creates a new physical counter attached a BCB node. + /// The node must not already have a counter. + fn make_phys_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { + let counter = self.make_counter_inner(CounterIncrementSite::Node { bcb }); + debug!(?bcb, ?counter, "node gets a physical counter"); + self.set_bcb_counter(bcb, counter) + } + + /// Creates a new physical counter attached to a BCB edge. + /// The edge must not already have a counter. + fn make_phys_edge_counter( + &mut self, + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, + ) -> BcbCounter { + let counter = self.make_counter_inner(CounterIncrementSite::Edge { from_bcb, to_bcb }); + debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter"); + self.set_bcb_edge_counter(from_bcb, to_bcb, counter) + } + fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter { let new_expr = BcbExpression { lhs, op, rhs }; *self @@ -157,12 +177,14 @@ impl CoverageCounters { BcbCounter::Expression { id } } - /// Variant of `make_expression` that makes `lhs` optional and assumes [`Op::Add`]. + /// Creates a counter that is the sum of the given counters. /// - /// This is useful when using [`Iterator::fold`] to build an arbitrary-length sum. - fn make_sum_expression(&mut self, lhs: Option, rhs: BcbCounter) -> BcbCounter { - let Some(lhs) = lhs else { return rhs }; - self.make_expression(lhs, Op::Add, rhs) + /// Returns `None` if the given list of counters was empty. + fn make_sum(&mut self, counters: &[BcbCounter]) -> Option { + counters + .iter() + .copied() + .reduce(|accum, counter| self.make_expression(accum, Op::Add, counter)) } pub(super) fn num_counters(&self) -> usize { @@ -241,10 +263,7 @@ impl CoverageCounters { } } -/// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be -/// injected with coverage spans. `Expressions` have no runtime overhead, so if a viable expression -/// (adding or subtracting two other counters or expressions) can compute the same result as an -/// embedded counter, an `Expression` should be used. +/// Helper struct that allows counter creation to inspect the BCB graph. struct MakeBcbCounters<'a> { coverage_counters: &'a mut CoverageCounters, basic_coverage_blocks: &'a CoverageGraph, @@ -258,36 +277,21 @@ impl<'a> MakeBcbCounters<'a> { Self { coverage_counters, basic_coverage_blocks } } - /// If two `BasicCoverageBlock`s branch from another `BasicCoverageBlock`, one of the branches - /// can be counted by `Expression` by subtracting the other branch from the branching - /// block. Otherwise, the `BasicCoverageBlock` executed the least should have the `Counter`. - /// One way to predict which branch executes the least is by considering loops. A loop is exited - /// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost - /// always executed less than the branch that does not exit the loop. - fn make_bcb_counters(&mut self, bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool) { + fn make_bcb_counters(&mut self, bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool) { debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock"); - // Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated - // coverage span, add a counter. If the `BasicCoverageBlock` branches, add a counter or - // expression to each branch `BasicCoverageBlock` (if the branch BCB has only one incoming - // edge) or edge from the branching BCB to the branch BCB (if the branch BCB has multiple - // incoming edges). + // Traverse the coverage graph, ensuring that every node that needs a + // coverage counter has one. // - // The `TraverseCoverageGraphWithLoops` traversal ensures that, when a loop is encountered, - // all `BasicCoverageBlock` nodes in the loop are visited before visiting any node outside - // the loop. The `traversal` state includes a `context_stack`, providing a way to know if - // the current BCB is in one or more nested loops or not. + // The traversal tries to ensure that, when a loop is encountered, all + // nodes within the loop are visited before visiting any nodes outside + // the loop. It also keeps track of which loop(s) the traversal is + // currently inside. let mut traversal = TraverseCoverageGraphWithLoops::new(self.basic_coverage_blocks); while let Some(bcb) = traversal.next() { - if bcb_has_coverage_spans(bcb) { - debug!("{:?} has at least one coverage span. Get or make its counter", bcb); - self.make_node_and_branch_counters(&traversal, bcb); - } else { - debug!( - "{:?} does not have any coverage spans. A counter will only be added if \ - and when a covered BCB has an expression dependency.", - bcb, - ); + let _span = debug_span!("traversal", ?bcb).entered(); + if bcb_needs_counter(bcb) { + self.make_node_counter_and_out_edge_counters(&traversal, bcb); } } @@ -298,146 +302,133 @@ impl<'a> MakeBcbCounters<'a> { ); } - fn make_node_and_branch_counters( + /// Make sure the given node has a node counter, and then make sure each of + /// its out-edges has an edge counter (if appropriate). + #[instrument(level = "debug", skip(self, traversal))] + fn make_node_counter_and_out_edge_counters( &mut self, traversal: &TraverseCoverageGraphWithLoops<'_>, from_bcb: BasicCoverageBlock, ) { // First, ensure that this node has a counter of some kind. - // We might also use its term later to compute one of the branch counters. - let from_bcb_operand = self.get_or_make_counter_operand(from_bcb); - - let branch_target_bcbs = self.basic_coverage_blocks.successors[from_bcb].as_slice(); - - // If this node doesn't have multiple out-edges, or all of its out-edges - // already have counters, then we don't need to create edge counters. - let needs_branch_counters = branch_target_bcbs.len() > 1 - && branch_target_bcbs - .iter() - .any(|&to_bcb| self.branch_has_no_counter(from_bcb, to_bcb)); - if !needs_branch_counters { + // We might also use that counter to compute one of the out-edge counters. + let node_counter = self.get_or_make_node_counter(from_bcb); + + let successors = self.basic_coverage_blocks.successors[from_bcb].as_slice(); + + // If this node's out-edges won't sum to the node's counter, + // then there's no reason to create edge counters here. + if !self.basic_coverage_blocks[from_bcb].is_out_summable { return; } - debug!( - "{from_bcb:?} has some branch(es) without counters:\n {}", - branch_target_bcbs - .iter() - .map(|&to_bcb| { - format!("{from_bcb:?}->{to_bcb:?}: {:?}", self.branch_counter(from_bcb, to_bcb)) - }) - .collect::>() - .join("\n "), - ); - - // Of the branch edges that don't have counters yet, one can be given an expression - // (computed from the other edges) instead of a dedicated counter. - let expression_to_bcb = self.choose_preferred_expression_branch(traversal, from_bcb); + // Determine the set of out-edges that don't yet have edge counters. + let candidate_successors = self.basic_coverage_blocks.successors[from_bcb] + .iter() + .copied() + .filter(|&to_bcb| self.edge_has_no_counter(from_bcb, to_bcb)) + .collect::>(); + debug!(?candidate_successors); + + // If there are out-edges without counters, choose one to be given an expression + // (computed from this node and the other out-edges) instead of a physical counter. + let Some(expression_to_bcb) = + self.choose_out_edge_for_expression(traversal, &candidate_successors) + else { + return; + }; - // For each branch arm other than the one that was chosen to get an expression, + // For each out-edge other than the one that was chosen to get an expression, // ensure that it has a counter (existing counter/expression or a new counter), - // and accumulate the corresponding terms into a single sum term. - let sum_of_all_other_branches: BcbCounter = { - let _span = debug_span!("sum_of_all_other_branches", ?expression_to_bcb).entered(); - branch_target_bcbs - .iter() - .copied() - // Skip the chosen branch, since we'll calculate it from the other branches. - .filter(|&to_bcb| to_bcb != expression_to_bcb) - .fold(None, |accum, to_bcb| { - let _span = debug_span!("to_bcb", ?accum, ?to_bcb).entered(); - let branch_counter = self.get_or_make_edge_counter_operand(from_bcb, to_bcb); - Some(self.coverage_counters.make_sum_expression(accum, branch_counter)) - }) - .expect("there must be at least one other branch") + // and accumulate the corresponding counters into a single sum expression. + let other_out_edge_counters = successors + .iter() + .copied() + // Skip the chosen edge, since we'll calculate its count from this sum. + .filter(|&to_bcb| to_bcb != expression_to_bcb) + .map(|to_bcb| self.get_or_make_edge_counter(from_bcb, to_bcb)) + .collect::>(); + let Some(sum_of_all_other_out_edges) = + self.coverage_counters.make_sum(&other_out_edge_counters) + else { + return; }; - // For the branch that was chosen to get an expression, create that expression - // by taking the count of the node we're branching from, and subtracting the - // sum of all the other branches. - debug!( - "Making an expression for the selected expression_branch: \ - {expression_to_bcb:?} (expression_branch predecessors: {:?})", - self.bcb_predecessors(expression_to_bcb), - ); + // Now create an expression for the chosen edge, by taking the counter + // for its source node and subtracting the sum of its sibling out-edges. let expression = self.coverage_counters.make_expression( - from_bcb_operand, + node_counter, Op::Subtract, - sum_of_all_other_branches, + sum_of_all_other_out_edges, ); + debug!("{expression_to_bcb:?} gets an expression: {expression:?}"); - if self.basic_coverage_blocks.bcb_has_multiple_in_edges(expression_to_bcb) { - self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); - } else { + if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(expression_to_bcb) { + // This edge normally wouldn't get its own counter, so attach the expression + // to its target node instead, so that `edge_has_no_counter` can see it. + assert_eq!(sole_pred, from_bcb); self.coverage_counters.set_bcb_counter(expression_to_bcb, expression); + } else { + self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); } } #[instrument(level = "debug", skip(self))] - fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { + fn get_or_make_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { // If the BCB already has a counter, return it. if let Some(counter_kind) = self.coverage_counters.bcb_counters[bcb] { debug!("{bcb:?} already has a counter: {counter_kind:?}"); return counter_kind; } - // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`). - // Also, a BCB that loops back to itself gets a simple `Counter`. This may indicate the - // program results in a tight infinite loop, but it should still compile. - let one_path_to_target = !self.basic_coverage_blocks.bcb_has_multiple_in_edges(bcb); - if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) { - let counter_kind = - self.coverage_counters.make_counter(CounterIncrementSite::Node { bcb }); - if one_path_to_target { - debug!("{bcb:?} gets a new counter: {counter_kind:?}"); - } else { - debug!( - "{bcb:?} has itself as its own predecessor. It can't be part of its own \ - Expression sum, so it will get its own new counter: {counter_kind:?}. \ - (Note, the compiled code will generate an infinite loop.)", - ); - } - return self.coverage_counters.set_bcb_counter(bcb, counter_kind); + let predecessors = self.basic_coverage_blocks.predecessors[bcb].as_slice(); + + // Handle cases where we can't compute a node's count from its in-edges: + // - START_BCB has no in-edges, so taking the sum would panic (or be wrong). + // - For nodes with one in-edge, or that directly loop to themselves, + // trying to get the in-edge counts would require this node's counter, + // leading to infinite recursion. + if predecessors.len() <= 1 || predecessors.contains(&bcb) { + debug!(?bcb, ?predecessors, "node has <=1 predecessors or is its own predecessor"); + return self.coverage_counters.make_phys_node_counter(bcb); } // A BCB with multiple incoming edges can compute its count by ensuring that counters // exist for each of those edges, and then adding them up to get a total count. - let sum_of_in_edges: BcbCounter = { - let _span = debug_span!("sum_of_in_edges", ?bcb).entered(); - // We avoid calling `self.bcb_predecessors` here so that we can - // call methods on `&mut self` inside the fold. - self.basic_coverage_blocks.predecessors[bcb] - .iter() - .copied() - .fold(None, |accum, from_bcb| { - let _span = debug_span!("from_bcb", ?accum, ?from_bcb).entered(); - let edge_counter = self.get_or_make_edge_counter_operand(from_bcb, bcb); - Some(self.coverage_counters.make_sum_expression(accum, edge_counter)) - }) - .expect("there must be at least one in-edge") - }; + let in_edge_counters = predecessors + .iter() + .copied() + .map(|from_bcb| self.get_or_make_edge_counter(from_bcb, bcb)) + .collect::>(); + let sum_of_in_edges: BcbCounter = self + .coverage_counters + .make_sum(&in_edge_counters) + .expect("there must be at least one in-edge"); debug!("{bcb:?} gets a new counter (sum of predecessor counters): {sum_of_in_edges:?}"); self.coverage_counters.set_bcb_counter(bcb, sum_of_in_edges) } #[instrument(level = "debug", skip(self))] - fn get_or_make_edge_counter_operand( + fn get_or_make_edge_counter( &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, ) -> BcbCounter { - // If the target BCB has only one in-edge (i.e. this one), then create - // a node counter instead, since it will have the same value. - if !self.basic_coverage_blocks.bcb_has_multiple_in_edges(to_bcb) { - assert_eq!([from_bcb].as_slice(), self.basic_coverage_blocks.predecessors[to_bcb]); - return self.get_or_make_counter_operand(to_bcb); + // If the target node has exactly one in-edge (i.e. this one), then just + // use the node's counter, since it will have the same value. + if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) { + assert_eq!(sole_pred, from_bcb); + // This call must take care not to invoke `get_or_make_edge` for + // this edge, since that would result in infinite recursion! + return self.get_or_make_node_counter(to_bcb); } - // If the source BCB has only one successor (assumed to be the given target), an edge - // counter is unnecessary. Just get or make a counter for the source BCB. - if self.bcb_successors(from_bcb).len() == 1 { - return self.get_or_make_counter_operand(from_bcb); + // If the source node has exactly one out-edge (i.e. this one) and would have + // the same execution count as that edge, then just use the node's counter. + if let Some(simple_succ) = self.basic_coverage_blocks.simple_successor(from_bcb) { + assert_eq!(simple_succ, to_bcb); + return self.get_or_make_node_counter(from_bcb); } // If the edge already has a counter, return it. @@ -449,121 +440,81 @@ impl<'a> MakeBcbCounters<'a> { } // Make a new counter to count this edge. - let counter_kind = - self.coverage_counters.make_counter(CounterIncrementSite::Edge { from_bcb, to_bcb }); - debug!("Edge {from_bcb:?}->{to_bcb:?} gets a new counter: {counter_kind:?}"); - self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter_kind) + self.coverage_counters.make_phys_edge_counter(from_bcb, to_bcb) } - /// Select a branch for the expression, either the recommended `reloop_branch`, or if none was - /// found, select any branch. - fn choose_preferred_expression_branch( + /// Given a set of candidate out-edges (represented by their successor node), + /// choose one to be given a counter expression instead of a physical counter. + fn choose_out_edge_for_expression( &self, traversal: &TraverseCoverageGraphWithLoops<'_>, - from_bcb: BasicCoverageBlock, - ) -> BasicCoverageBlock { - let good_reloop_branch = self.find_good_reloop_branch(traversal, from_bcb); - if let Some(reloop_target) = good_reloop_branch { - assert!(self.branch_has_no_counter(from_bcb, reloop_target)); + candidate_successors: &[BasicCoverageBlock], + ) -> Option { + // Try to find a candidate that leads back to the top of a loop, + // because reloop edges tend to be executed more times than loop-exit edges. + if let Some(reloop_target) = self.find_good_reloop_edge(traversal, &candidate_successors) { debug!("Selecting reloop target {reloop_target:?} to get an expression"); - reloop_target - } else { - let &branch_without_counter = self - .bcb_successors(from_bcb) - .iter() - .find(|&&to_bcb| self.branch_has_no_counter(from_bcb, to_bcb)) - .expect( - "needs_branch_counters was `true` so there should be at least one \ - branch", - ); - debug!( - "Selecting any branch={:?} that still needs a counter, to get the \ - `Expression` because there was no `reloop_branch`, or it already had a \ - counter", - branch_without_counter - ); - branch_without_counter + return Some(reloop_target); } + + // We couldn't identify a "good" edge, so just choose an arbitrary one. + let arbitrary_target = candidate_successors.first().copied()?; + debug!(?arbitrary_target, "selecting arbitrary out-edge to get an expression"); + Some(arbitrary_target) } - /// Tries to find a branch that leads back to the top of a loop, and that - /// doesn't already have a counter. Such branches are good candidates to - /// be given an expression (instead of a physical counter), because they - /// will tend to be executed more times than a loop-exit branch. - fn find_good_reloop_branch( + /// Given a set of candidate out-edges (represented by their successor node), + /// tries to find one that leads back to the top of a loop. + /// + /// Reloop edges are good candidates for counter expressions, because they + /// will tend to be executed more times than a loop-exit edge, so it's nice + /// for them to be able to avoid a physical counter increment. + fn find_good_reloop_edge( &self, traversal: &TraverseCoverageGraphWithLoops<'_>, - from_bcb: BasicCoverageBlock, + candidate_successors: &[BasicCoverageBlock], ) -> Option { - let branch_target_bcbs = self.bcb_successors(from_bcb); + // If there are no candidates, avoid iterating over the loop stack. + if candidate_successors.is_empty() { + return None; + } // Consider each loop on the current traversal context stack, top-down. for reloop_bcbs in traversal.reloop_bcbs_per_loop() { - let mut all_branches_exit_this_loop = true; - - // Try to find a branch that doesn't exit this loop and doesn't - // already have a counter. - for &branch_target_bcb in branch_target_bcbs { - // A branch is a reloop branch if it dominates any BCB that has - // an edge back to the loop header. (Other branches are exits.) - let is_reloop_branch = reloop_bcbs.iter().any(|&reloop_bcb| { - self.basic_coverage_blocks.dominates(branch_target_bcb, reloop_bcb) + // Try to find a candidate edge that doesn't exit this loop. + for &target_bcb in candidate_successors { + // An edge is a reloop edge if its target dominates any BCB that has + // an edge back to the loop header. (Otherwise it's an exit edge.) + let is_reloop_edge = reloop_bcbs.iter().any(|&reloop_bcb| { + self.basic_coverage_blocks.dominates(target_bcb, reloop_bcb) }); - - if is_reloop_branch { - all_branches_exit_this_loop = false; - if self.branch_has_no_counter(from_bcb, branch_target_bcb) { - // We found a good branch to be given an expression. - return Some(branch_target_bcb); - } - // Keep looking for another reloop branch without a counter. - } else { - // This branch exits the loop. + if is_reloop_edge { + // We found a good out-edge to be given an expression. + return Some(target_bcb); } } - if !all_branches_exit_this_loop { - // We found one or more reloop branches, but all of them already - // have counters. Let the caller choose one of the exit branches. - debug!("All reloop branches had counters; skip checking the other loops"); - return None; - } - - // All of the branches exit this loop, so keep looking for a good - // reloop branch for one of the outer loops. + // All of the candidate edges exit this loop, so keep looking + // for a good reloop edge for one of the outer loops. } None } #[inline] - fn bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock] { - &self.basic_coverage_blocks.predecessors[bcb] - } - - #[inline] - fn bcb_successors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock] { - &self.basic_coverage_blocks.successors[bcb] - } - - #[inline] - fn branch_has_no_counter( + fn edge_has_no_counter( &self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, ) -> bool { - self.branch_counter(from_bcb, to_bcb).is_none() - } + let edge_counter = + if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) { + assert_eq!(sole_pred, from_bcb); + self.coverage_counters.bcb_counters[to_bcb] + } else { + self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)).copied() + }; - fn branch_counter( - &self, - from_bcb: BasicCoverageBlock, - to_bcb: BasicCoverageBlock, - ) -> Option<&BcbCounter> { - if self.basic_coverage_blocks.bcb_has_multiple_in_edges(to_bcb) { - self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) - } else { - self.coverage_counters.bcb_counters[to_bcb].as_ref() - } + edge_counter.is_none() } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 0d874a6c8bab8..d839f46cfbd55 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -6,8 +6,8 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{self, Dominators}; use rustc_data_structures::graph::{self, DirectedGraph, StartNode}; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind}; use tracing::debug; @@ -87,7 +87,11 @@ impl CoverageGraph { for &bb in basic_blocks.iter() { bb_to_bcb[bb] = Some(bcb); } - let bcb_data = BasicCoverageBlockData::from(basic_blocks); + + let is_out_summable = basic_blocks.last().map_or(false, |&bb| { + bcb_filtered_successors(mir_body[bb].terminator()).is_out_summable() + }); + let bcb_data = BasicCoverageBlockData { basic_blocks, is_out_summable }; debug!("adding bcb{}: {:?}", bcb.index(), bcb_data); bcbs.push(bcb_data); }; @@ -161,23 +165,33 @@ impl CoverageGraph { self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b) } - /// Returns true if the given node has 2 or more in-edges, i.e. 2 or more - /// predecessors. - /// - /// This property is interesting to code that assigns counters to nodes and - /// edges, because if a node _doesn't_ have multiple in-edges, then there's - /// no benefit in having a separate counter for its in-edge, because it - /// would have the same value as the node's own counter. - /// - /// FIXME: That assumption might not be true for [`TerminatorKind::Yield`]? - #[inline(always)] - pub(crate) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool { - // Even though bcb0 conceptually has an extra virtual in-edge due to - // being the entry point, we've already asserted that it has no _other_ - // in-edges, so there's no possibility of it having _multiple_ in-edges. - // (And since its virtual in-edge doesn't exist in the graph, that edge - // can't have a separate counter anyway.) - self.predecessors[bcb].len() > 1 + /// Returns the source of this node's sole in-edge, if it has exactly one. + /// That edge can be assumed to have the same execution count as the node + /// itself (in the absence of panics). + pub(crate) fn sole_predecessor( + &self, + to_bcb: BasicCoverageBlock, + ) -> Option { + // Unlike `simple_successor`, there is no need for extra checks here. + if let &[from_bcb] = self.predecessors[to_bcb].as_slice() { Some(from_bcb) } else { None } + } + + /// Returns the target of this node's sole out-edge, if it has exactly + /// one, but only if that edge can be assumed to have the same execution + /// count as the node itself (in the absence of panics). + pub(crate) fn simple_successor( + &self, + from_bcb: BasicCoverageBlock, + ) -> Option { + // If a node's count is the sum of its out-edges, and it has exactly + // one out-edge, then that edge has the same count as the node. + if self.bcbs[from_bcb].is_out_summable + && let &[to_bcb] = self.successors[from_bcb].as_slice() + { + Some(to_bcb) + } else { + None + } } } @@ -266,14 +280,16 @@ rustc_index::newtype_index! { #[derive(Debug, Clone)] pub(crate) struct BasicCoverageBlockData { pub(crate) basic_blocks: Vec, + + /// If true, this node's execution count can be assumed to be the sum of the + /// execution counts of all of its **out-edges** (assuming no panics). + /// + /// Notably, this is false for a node ending with [`TerminatorKind::Yield`], + /// because the yielding coroutine might not be resumed. + pub(crate) is_out_summable: bool, } impl BasicCoverageBlockData { - fn from(basic_blocks: Vec) -> Self { - assert!(basic_blocks.len() > 0); - Self { basic_blocks } - } - #[inline(always)] pub(crate) fn leader_bb(&self) -> BasicBlock { self.basic_blocks[0] @@ -295,6 +311,9 @@ enum CoverageSuccessors<'a> { Chainable(BasicBlock), /// The block cannot be combined into the same BCB as its successor(s). NotChainable(&'a [BasicBlock]), + /// Yield terminators are not chainable, and their execution count can also + /// differ from the execution count of their out-edge. + Yield(BasicBlock), } impl CoverageSuccessors<'_> { @@ -302,6 +321,17 @@ impl CoverageSuccessors<'_> { match self { Self::Chainable(_) => true, Self::NotChainable(_) => false, + Self::Yield(_) => false, + } + } + + /// Returns true if the terminator itself is assumed to have the same + /// execution count as the sum of its out-edges (assuming no panics). + fn is_out_summable(&self) -> bool { + match self { + Self::Chainable(_) => true, + Self::NotChainable(_) => true, + Self::Yield(_) => false, } } } @@ -312,7 +342,9 @@ impl IntoIterator for CoverageSuccessors<'_> { fn into_iter(self) -> Self::IntoIter { match self { - Self::Chainable(bb) => Some(bb).into_iter().chain((&[]).iter().copied()), + Self::Chainable(bb) | Self::Yield(bb) => { + Some(bb).into_iter().chain((&[]).iter().copied()) + } Self::NotChainable(bbs) => None.into_iter().chain(bbs.iter().copied()), } } @@ -331,7 +363,7 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera // A yield terminator has exactly 1 successor, but should not be chained, // because its resume edge has a different execution count. - Yield { ref resume, .. } => CoverageSuccessors::NotChainable(std::slice::from_ref(resume)), + Yield { resume, .. } => CoverageSuccessors::Yield(resume), // These terminators have exactly one coverage-relevant successor, // and can be chained into it. @@ -341,15 +373,15 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera | FalseUnwind { real_target: target, .. } | Goto { target } => CoverageSuccessors::Chainable(target), - // A call terminator can normally be chained, except when they have no - // successor because they are known to diverge. + // A call terminator can normally be chained, except when it has no + // successor because it is known to diverge. Call { target: maybe_target, .. } => match maybe_target { Some(target) => CoverageSuccessors::Chainable(target), None => CoverageSuccessors::NotChainable(&[]), }, - // An inline asm terminator can normally be chained, except when it diverges or uses asm - // goto. + // An inline asm terminator can normally be chained, except when it + // diverges or uses asm goto. InlineAsm { ref targets, .. } => { if let [target] = targets[..] { CoverageSuccessors::Chainable(target) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 2ac08ea85d253..ec5ba354805f1 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -1,8 +1,8 @@ use std::collections::BTreeSet; use rustc_data_structures::graph::DirectedGraph; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::coverage::{ BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind, }; @@ -10,10 +10,10 @@ use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; +use crate::coverage::ExtractedHirInfo; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; use crate::coverage::spans::extract_refined_covspans; use crate::coverage::unexpand::unexpand_into_body_span; -use crate::coverage::ExtractedHirInfo; /// Associates an ordinary executable code span with its corresponding BCB. #[derive(Debug)] diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index bba354d29363d..104f340c8d63f 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -1,4 +1,4 @@ -pub mod query; +pub(super) mod query; mod counters; mod graph; @@ -9,7 +9,7 @@ mod tests; mod unexpand; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::mir::coverage::{ @@ -28,14 +28,13 @@ use tracing::{debug, debug_span, instrument, trace}; use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; use crate::coverage::graph::CoverageGraph; use crate::coverage::mappings::ExtractedMappings; -use crate::MirPass; /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen /// to construct the coverage map. -pub struct InstrumentCoverage; +pub(super) struct InstrumentCoverage; -impl<'tcx> MirPass<'tcx> for InstrumentCoverage { +impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.instrument_coverage() } @@ -148,8 +147,8 @@ fn create_mappings<'tcx>( let source_file = source_map.lookup_source_file(body_span.lo()); - use rustc_session::config::RemapPathScopeComponents; use rustc_session::RemapFileNameExt; + use rustc_session::config::RemapPathScopeComponents; let file_name = Symbol::intern( &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), ); @@ -280,7 +279,8 @@ fn inject_mcdc_statements<'tcx>( basic_coverage_blocks: &CoverageGraph, extracted_mappings: &ExtractedMappings, ) { - // Inject test vector update first because `inject_statement` always insert new statement at head. + // Inject test vector update first because `inject_statement` always insert new statement at + // head. for &mappings::MCDCDecision { span: _, ref end_bcbs, diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index fcc774503f45a..da7d20cf19a68 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -3,14 +3,14 @@ use std::collections::VecDeque; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; -use rustc_span::Span; +use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; use tracing::{debug, debug_span, instrument}; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::spans::from_mir::{ - extract_covspans_from_mir, ExtractedCovspans, Hole, SpanFromMir, + ExtractedCovspans, Hole, SpanFromMir, extract_covspans_from_mir, }; -use crate::coverage::{mappings, ExtractedHirInfo}; +use crate::coverage::{ExtractedHirInfo, mappings}; mod from_mir; @@ -25,7 +25,7 @@ pub(super) fn extract_refined_covspans( // First, perform the passes that need macro information. covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); - remove_unwanted_macro_spans(&mut covspans); + remove_unwanted_expansion_spans(&mut covspans); split_visible_macro_spans(&mut covspans); // We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`. @@ -76,18 +76,24 @@ pub(super) fn extract_refined_covspans( /// invocation, which is unhelpful. Keeping only the first such span seems to /// give better mappings, so remove the others. /// +/// Similarly, `await` expands to a branch on the discriminant of `Poll`, which +/// leads to incorrect coverage if the `Future` is immediately ready (#98712). +/// /// (The input spans should be sorted in BCB dominator order, so that the /// retained "first" span is likely to dominate the others.) -fn remove_unwanted_macro_spans(covspans: &mut Vec) { - let mut seen_macro_spans = FxHashSet::default(); +fn remove_unwanted_expansion_spans(covspans: &mut Vec) { + let mut deduplicated_spans = FxHashSet::default(); + covspans.retain(|covspan| { - // Ignore (retain) non-macro-expansion spans. - if covspan.visible_macro.is_none() { - return true; + match covspan.expn_kind { + // Retain only the first await-related or macro-expanded covspan with this span. + Some(ExpnKind::Desugaring(kind)) if kind == DesugaringKind::Await => { + deduplicated_spans.insert(covspan.span) + } + Some(ExpnKind::Macro(MacroKind::Bang, _)) => deduplicated_spans.insert(covspan.span), + // Ignore (retain) other spans. + _ => true, } - - // Retain only the first macro-expanded covspan with this span. - seen_macro_spans.insert(covspan.span) }); } @@ -99,7 +105,9 @@ fn split_visible_macro_spans(covspans: &mut Vec) { let mut extra_spans = vec![]; covspans.retain(|covspan| { - let Some(visible_macro) = covspan.visible_macro else { return true }; + let Some(ExpnKind::Macro(MacroKind::Bang, visible_macro)) = covspan.expn_kind else { + return true; + }; let split_len = visible_macro.as_str().len() as u32 + 1; let (before, after) = covspan.span.split_at(split_len); @@ -111,8 +119,8 @@ fn split_visible_macro_spans(covspans: &mut Vec) { return true; } - extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb)); - extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb)); + extra_spans.push(SpanFromMir::new(before, covspan.expn_kind.clone(), covspan.bcb)); + extra_spans.push(SpanFromMir::new(after, covspan.expn_kind.clone(), covspan.bcb)); false // Discard the original covspan that we just split. }); diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 32bd25bf4b966..875db23ce0969 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -3,14 +3,14 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{ self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_span::{Span, Symbol}; +use rustc_span::{ExpnKind, Span}; +use crate::coverage::ExtractedHirInfo; use crate::coverage::graph::{ BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, }; use crate::coverage::spans::Covspan; -use crate::coverage::unexpand::unexpand_into_body_span_with_visible_macro; -use crate::coverage::ExtractedHirInfo; +use crate::coverage::unexpand::unexpand_into_body_span_with_expn_kind; pub(crate) struct ExtractedCovspans { pub(crate) covspans: Vec, @@ -60,7 +60,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let data = &mir_body[bb]; let unexpand = move |expn_span| { - unexpand_into_body_span_with_visible_macro(expn_span, body_span) + unexpand_into_body_span_with_expn_kind(expn_span, body_span) // Discard any spans that fill the entire body, because they tend // to represent compiler-inserted code, e.g. implicitly returning `()`. .filter(|(span, _)| !span.source_equal(body_span)) @@ -68,9 +68,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let mut extract_statement_span = |statement| { let expn_span = filtered_statement_span(statement)?; - let (span, visible_macro) = unexpand(expn_span)?; + let (span, expn_kind) = unexpand(expn_span)?; - initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb)); + initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb)); Some(()) }; for statement in data.statements.iter() { @@ -79,9 +79,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let mut extract_terminator_span = |terminator| { let expn_span = filtered_terminator_span(terminator)?; - let (span, visible_macro) = unexpand(expn_span)?; + let (span, expn_kind) = unexpand(expn_span)?; - initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb)); + initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb)); Some(()) }; extract_terminator_span(data.terminator()); @@ -214,7 +214,7 @@ pub(crate) struct SpanFromMir { /// With the exception of `fn_sig_span`, this should always be contained /// within `body_span`. pub(crate) span: Span, - pub(crate) visible_macro: Option, + pub(crate) expn_kind: Option, pub(crate) bcb: BasicCoverageBlock, } @@ -223,12 +223,12 @@ impl SpanFromMir { Self::new(fn_sig_span, None, START_BCB) } - pub(crate) fn new(span: Span, visible_macro: Option, bcb: BasicCoverageBlock) -> Self { - Self { span, visible_macro, bcb } + pub(crate) fn new(span: Span, expn_kind: Option, bcb: BasicCoverageBlock) -> Self { + Self { span, expn_kind, bcb } } pub(crate) fn into_covspan(self) -> Covspan { - let Self { span, visible_macro: _, bcb } = self; + let Self { span, expn_kind: _, bcb } = self; Covspan { span, bcb } } } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index a4db11bb2c160..233ca9981c50c 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -29,7 +29,7 @@ use rustc_data_structures::graph::{DirectedGraph, Successors}; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::*; use rustc_middle::{bug, ty}; -use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; +use rustc_span::{BytePos, DUMMY_SP, Pos, Span}; use super::graph::{self, BasicCoverageBlock}; @@ -129,18 +129,15 @@ impl<'tcx> MockBlocks<'tcx> { } fn call(&mut self, some_from_block: Option) -> BasicBlock { - self.add_block_from( - some_from_block, - TerminatorKind::Call { - func: Operand::Copy(self.dummy_place.clone()), - args: [].into(), - destination: self.dummy_place.clone(), - target: Some(TEMP_BLOCK), - unwind: UnwindAction::Continue, - call_source: CallSource::Misc, - fn_span: DUMMY_SP, - }, - ) + self.add_block_from(some_from_block, TerminatorKind::Call { + func: Operand::Copy(self.dummy_place.clone()), + args: [].into(), + destination: self.dummy_place.clone(), + target: Some(TEMP_BLOCK), + unwind: UnwindAction::Continue, + call_source: CallSource::Misc, + fn_span: DUMMY_SP, + }) } fn goto(&mut self, some_from_block: Option) -> BasicBlock { diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs index 8cde291b9073e..cb8615447362b 100644 --- a/compiler/rustc_mir_transform/src/coverage/unexpand.rs +++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs @@ -1,4 +1,4 @@ -use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; +use rustc_span::{ExpnKind, Span}; /// Walks through the expansion ancestors of `original_span` to find a span that /// is contained in `body_span` and has the same [syntax context] as `body_span`. @@ -13,20 +13,15 @@ pub(crate) fn unexpand_into_body_span(original_span: Span, body_span: Span) -> O /// /// If the returned span represents a bang-macro invocation (e.g. `foo!(..)`), /// the returned symbol will be the name of that macro (e.g. `foo`). -pub(crate) fn unexpand_into_body_span_with_visible_macro( +pub(crate) fn unexpand_into_body_span_with_expn_kind( original_span: Span, body_span: Span, -) -> Option<(Span, Option)> { +) -> Option<(Span, Option)> { let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; - let visible_macro = prev - .map(|prev| match prev.ctxt().outer_expn_data().kind { - ExpnKind::Macro(MacroKind::Bang, name) => Some(name), - _ => None, - }) - .flatten(); + let expn_kind = prev.map(|prev| prev.ctxt().outer_expn_data().kind); - Some((span, visible_macro)) + Some((span, expn_kind)) } /// Walks through the expansion ancestors of `original_span` to find a span that diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 50aaed090f6b8..42cbece32d8c9 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -10,7 +10,7 @@ use rustc_span::sym; use crate::{inline, pass_manager as pm}; -pub fn provide(providers: &mut Providers) { +pub(super) fn provide(providers: &mut Providers) { providers.cross_crate_inlinable = cross_crate_inlinable; } @@ -24,7 +24,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // This just reproduces the logic from Instance::requires_inline. match tcx.def_kind(def_id) { - DefKind::Ctor(..) | DefKind::Closure => return true, + DefKind::Ctor(..) | DefKind::Closure | DefKind::SyntheticCoroutineBody => return true, DefKind::Fn | DefKind::AssocFn => {} _ => return false, } diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs index bf522fd5ef4ec..bd58b1b668997 100644 --- a/compiler/rustc_mir_transform/src/ctfe_limit.rs +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -8,11 +8,9 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use tracing::instrument; -use crate::MirPass; +pub(super) struct CtfeLimit; -pub struct CtfeLimit; - -impl<'tcx> MirPass<'tcx> for CtfeLimit { +impl<'tcx> crate::MirPass<'tcx> for CtfeLimit { #[instrument(skip(self, _tcx, body))] fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let doms = body.basic_blocks.dominators(); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index b16d25c93bb96..88dc8e74a8c29 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -2,7 +2,7 @@ //! //! Currently, this pass only propagates scalar values. -use rustc_const_eval::const_eval::{throw_machine_stop_str, DummyMachine}; +use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str}; use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; @@ -18,7 +18,7 @@ use rustc_mir_dataflow::value_analysis::{ }; use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; use rustc_span::DUMMY_SP; -use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT}; +use rustc_target::abi::{Abi, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use tracing::{debug, debug_span, instrument}; // These constants are somewhat random guesses and have not been optimized. @@ -26,9 +26,9 @@ use tracing::{debug, debug_span, instrument}; const BLOCK_LIMIT: usize = 100; const PLACE_LIMIT: usize = 100; -pub struct DataflowConstProp; +pub(super) struct DataflowConstProp; -impl<'tcx> MirPass<'tcx> for DataflowConstProp { +impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 3 } @@ -189,7 +189,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } Rvalue::Cast( - CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), + CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _), operand, _, ) => { @@ -332,7 +332,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { + fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); Self { map, @@ -554,13 +554,13 @@ impl<'tcx> Patch<'tcx> { } } -struct Collector<'tcx, 'locals> { +struct Collector<'a, 'tcx> { patch: Patch<'tcx>, - local_decls: &'locals LocalDecls<'tcx>, + local_decls: &'a LocalDecls<'tcx>, } -impl<'tcx, 'locals> Collector<'tcx, 'locals> { - pub(crate) fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self { +impl<'a, 'tcx> Collector<'a, 'tcx> { + pub(crate) fn new(tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>) -> Self { Self { patch: Patch::new(tcx), local_decls } } @@ -647,7 +647,8 @@ fn try_write_constant<'tcx>( ty::FnDef(..) => {} // Those are scalars, must be handled above. - ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => throw_machine_stop_str!("primitive type with provenance"), + ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => + throw_machine_stop_str!("primitive type with provenance"), ty::Tuple(elem_tys) => { for (i, elem) in elem_tys.iter().enumerate() { @@ -721,15 +722,15 @@ fn try_write_constant<'tcx>( impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper>>> - for Collector<'tcx, '_> + for Collector<'_, 'tcx> { - type FlowState = State>; + type Domain = State>; #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper>>, - state: &Self::FlowState, + state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, ) { @@ -751,7 +752,7 @@ impl<'mir, 'tcx> fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper>>, - state: &Self::FlowState, + state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, ) { @@ -776,7 +777,7 @@ impl<'mir, 'tcx> fn visit_terminator_before_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper>>, - state: &Self::FlowState, + state: &Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, ) { @@ -838,14 +839,14 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> { } } -struct OperandCollector<'tcx, 'map, 'locals, 'a> { +struct OperandCollector<'a, 'b, 'tcx> { state: &'a State>, - visitor: &'a mut Collector<'tcx, 'locals>, - ecx: &'map mut InterpCx<'tcx, DummyMachine>, - map: &'map Map<'tcx>, + visitor: &'a mut Collector<'b, 'tcx>, + ecx: &'a mut InterpCx<'tcx, DummyMachine>, + map: &'a Map<'tcx>, } -impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { +impl<'tcx> Visitor<'tcx> for OperandCollector<'_, '_, 'tcx> { fn visit_projection_elem( &mut self, _: PlaceRef<'tcx>, diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index f473073083af4..edffe6ce78f67 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -16,11 +16,11 @@ use rustc_middle::bug; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::debuginfo::debuginfo_locals; use rustc_mir_dataflow::impls::{ - borrowed_locals, LivenessTransferFunction, MaybeTransitiveLiveLocals, + LivenessTransferFunction, MaybeTransitiveLiveLocals, borrowed_locals, }; -use rustc_mir_dataflow::Analysis; use crate::util::is_within_packed; @@ -28,11 +28,11 @@ use crate::util::is_within_packed; /// /// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It /// can be generated via the [`borrowed_locals`] function. -pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let borrowed_locals = borrowed_locals(body); // If the user requests complete debuginfo, mark the locals that appear in it as live, so - // we don't remove assignements to them. + // we don't remove assignments to them. let mut always_live = debuginfo_locals(body); always_live.union(&borrowed_locals); @@ -127,12 +127,12 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } } -pub enum DeadStoreElimination { +pub(super) enum DeadStoreElimination { Initial, Final, } -impl<'tcx> MirPass<'tcx> for DeadStoreElimination { +impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination { fn name(&self) -> &'static str { match self { DeadStoreElimination::Initial => "DeadStoreElimination-initial", diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index 71af099199ea9..753bae8e15688 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Location, Operand, Place, Terminator, TerminatorKind, RETURN_PLACE}; +use rustc_middle::mir::{Body, Location, Operand, Place, RETURN_PLACE, Terminator, TerminatorKind}; use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt}; use rustc_session::config::OptLevel; @@ -42,9 +42,9 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly { } PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) => { // Whether mutating though a `&raw const` is allowed is still undecided, so we - // disable any sketchy `readonly` optimizations for now. - // But we only need to do this if the pointer would point into the argument. - // IOW: for indirect places, like `&raw (*local).field`, this surely cannot mutate `local`. + // disable any sketchy `readonly` optimizations for now. But we only need to do + // this if the pointer would point into the argument. IOW: for indirect places, + // like `&raw (*local).field`, this surely cannot mutate `local`. !place.is_indirect() } PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => { @@ -150,7 +150,7 @@ fn type_will_always_be_passed_directly(ty: Ty<'_>) -> bool { /// body of the function instead of just the signature. These can be useful for optimization /// purposes on a best-effort basis. We compute them here and store them into the crate metadata so /// dependent crates can use them. -pub fn deduced_param_attrs<'tcx>( +pub(super) fn deduced_param_attrs<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> &'tcx [DeducedParamAttrs] { @@ -168,17 +168,16 @@ pub fn deduced_param_attrs<'tcx>( // Codegen won't use this information for anything if all the function parameters are passed // directly. Detect that and bail, for compilation speed. let fn_ty = tcx.type_of(def_id).instantiate_identity(); - if matches!(fn_ty.kind(), ty::FnDef(..)) { - if fn_ty + if matches!(fn_ty.kind(), ty::FnDef(..)) + && fn_ty .fn_sig(tcx) .inputs() .skip_binder() .iter() .cloned() .all(type_will_always_be_passed_directly) - { - return &[]; - } + { + return &[]; } // Don't deduce any attributes for functions that have no MIR. diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index b38f4a4a823b1..26b28c8c4870e 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -13,9 +13,9 @@ use tracing::debug; use super::simplify::simplify_cfg; -pub struct DeduplicateBlocks; +pub(super) struct DeduplicateBlocks; -impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { +impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 4 } @@ -69,8 +69,8 @@ fn find_duplicates(body: &Body<'_>) -> FxHashMap { // For example, if bb1, bb2 and bb3 are duplicates, we will first insert bb3 in same_hashes. // Then we will see that bb2 is a duplicate of bb3, // and insert bb2 with the replacement bb3 in the duplicates list. - // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the duplicates list - // with replacement bb3. + // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the + // duplicates list with replacement bb3. // When the duplicates are removed, we will end up with only bb3. for (bb, bbd) in body.basic_blocks.iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup) { // Basic blocks can get really big, so to avoid checking for duplicates in basic blocks @@ -98,14 +98,15 @@ fn find_duplicates(body: &Body<'_>) -> FxHashMap { duplicates } -struct BasicBlockHashable<'tcx, 'a> { +struct BasicBlockHashable<'a, 'tcx> { basic_block_data: &'a BasicBlockData<'tcx>, } impl Hash for BasicBlockHashable<'_, '_> { fn hash(&self, state: &mut H) { hash_statements(state, self.basic_block_data.statements.iter()); - // Note that since we only hash the kind, we lose span information if we deduplicate the blocks + // Note that since we only hash the kind, we lose span information if we deduplicate the + // blocks. self.basic_block_data.terminator().kind.hash(state); } } diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index 0e2fccc85dacd..ad7ccef4976aa 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -1,16 +1,15 @@ -use rustc_index::IndexVec; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; use rustc_middle::mir::visit::{MutVisitor, PlaceContext}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -pub struct Derefer; +pub(super) struct Derefer; -pub struct DerefChecker<'a, 'tcx> { +struct DerefChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, patcher: MirPatch<'tcx>, - local_decls: &'a IndexVec>, + local_decls: &'a LocalDecls<'tcx>, } impl<'a, 'tcx> MutVisitor<'tcx> for DerefChecker<'a, 'tcx> { @@ -67,7 +66,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DerefChecker<'a, 'tcx> { } } -pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +pub(super) fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let patch = MirPatch::new(body); let mut checker = DerefChecker { tcx, patcher: patch, local_decls: &body.local_decls }; @@ -78,7 +77,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { checker.patcher.apply(body); } -impl<'tcx> MirPass<'tcx> for Derefer { +impl<'tcx> crate::MirPass<'tcx> for Derefer { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { deref_finder(tcx, body); } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index a530dccf96b27..ad83c0295baec 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -38,7 +38,7 @@ //! not contain any indirection through a pointer or any indexing projections. //! //! * `p` and `q` must have the **same type**. If we replace a local with a subtype or supertype, -//! we may end up with a differnet vtable for that local. See the `subtyping-impacts-selection` +//! we may end up with a different vtable for that local. See the `subtyping-impacts-selection` //! tests for an example where that causes issues. //! //! * We need to make sure that the goal of "merging the memory" is actually structurally possible @@ -137,20 +137,18 @@ use rustc_index::interval::SparseIntervalMatrix; use rustc_middle::bug; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::{ - dump_mir, traversal, Body, HasLocalDecls, InlineAsmOperand, Local, LocalKind, Location, - Operand, PassWhere, Place, Rvalue, Statement, StatementKind, TerminatorKind, + Body, HasLocalDecls, InlineAsmOperand, Local, LocalKind, Location, Operand, PassWhere, Place, + Rvalue, Statement, StatementKind, TerminatorKind, dump_mir, traversal, }; use rustc_middle::ty::TyCtxt; -use rustc_mir_dataflow::impls::MaybeLiveLocals; -use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex}; use rustc_mir_dataflow::Analysis; +use rustc_mir_dataflow::impls::MaybeLiveLocals; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex, save_as_intervals}; use tracing::{debug, trace}; -use crate::MirPass; +pub(super) struct DestinationPropagation; -pub struct DestinationPropagation; - -impl<'tcx> MirPass<'tcx> for DestinationPropagation { +impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { // For now, only run at MIR opt level 3. Two things need to be changed before this can be // turned on by default: @@ -165,7 +163,8 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let def_id = body.source.def_id(); - let mut allocations = Allocations::default(); + let mut candidates = Candidates::default(); + let mut write_info = WriteInfo::default(); trace!(func = ?tcx.def_path_str(def_id)); let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body); @@ -193,12 +192,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { loop { // PERF: Can we do something smarter than recalculating the candidates and liveness // results? - let mut candidates = find_candidates( - body, - &borrowed, - &mut allocations.candidates, - &mut allocations.candidates_reverse, - ); + candidates.reset_and_find(body, &borrowed); trace!(?candidates); dest_prop_mir_dump(tcx, body, &points, &live, round_count); @@ -206,7 +200,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { &mut candidates, &points, &live, - &mut allocations.write_info, + &mut write_info, body, ); @@ -248,27 +242,15 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { } round_count += 1; - apply_merges(body, tcx, &merges, &merged_locals); + apply_merges(body, tcx, merges, merged_locals); } trace!(round_count); } } -/// Container for the various allocations that we need. -/// -/// We store these here and hand out `&mut` access to them, instead of dropping and recreating them -/// frequently. Everything with a `&'alloc` lifetime points into here. -#[derive(Default)] -struct Allocations { - candidates: FxIndexMap>, - candidates_reverse: FxIndexMap>, - write_info: WriteInfo, - // PERF: Do this for `MaybeLiveLocals` allocations too. -} - -#[derive(Debug)] -struct Candidates<'alloc> { +#[derive(Debug, Default)] +struct Candidates { /// The set of candidates we are considering in this optimization. /// /// We will always merge the key into at most one of its values. @@ -283,11 +265,12 @@ struct Candidates<'alloc> { /// /// We will still report that we would like to merge `_1` and `_2` in an attempt to allow us to /// remove that assignment. - c: &'alloc mut FxIndexMap>, + c: FxIndexMap>, + /// A reverse index of the `c` set; if the `c` set contains `a => Place { local: b, proj }`, /// then this contains `b => a`. // PERF: Possibly these should be `SmallVec`s? - reverse: &'alloc mut FxIndexMap>, + reverse: FxIndexMap>, } ////////////////////////////////////////////////////////// @@ -298,20 +281,20 @@ struct Candidates<'alloc> { fn apply_merges<'tcx>( body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, - merges: &FxIndexMap, - merged_locals: &BitSet, + merges: FxIndexMap, + merged_locals: BitSet, ) { let mut merger = Merger { tcx, merges, merged_locals }; merger.visit_body_preserves_cfg(body); } -struct Merger<'a, 'tcx> { +struct Merger<'tcx> { tcx: TyCtxt<'tcx>, - merges: &'a FxIndexMap, - merged_locals: &'a BitSet, + merges: FxIndexMap, + merged_locals: BitSet, } -impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> { +impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -360,19 +343,40 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> { // // This section enforces bullet point 2 -struct FilterInformation<'a, 'body, 'alloc, 'tcx> { - body: &'body Body<'tcx>, +struct FilterInformation<'a, 'tcx> { + body: &'a Body<'tcx>, points: &'a DenseLocationMap, live: &'a SparseIntervalMatrix, - candidates: &'a mut Candidates<'alloc>, - write_info: &'alloc mut WriteInfo, + candidates: &'a mut Candidates, + write_info: &'a mut WriteInfo, at: Location, } // We first implement some utility functions which we will expose removing candidates according to // different needs. Throughout the liveness filtering, the `candidates` are only ever accessed // through these methods, and not directly. -impl<'alloc> Candidates<'alloc> { +impl Candidates { + /// Collects the candidates for merging. + /// + /// This is responsible for enforcing the first and third bullet point. + fn reset_and_find<'tcx>(&mut self, body: &Body<'tcx>, borrowed: &BitSet) { + self.c.clear(); + self.reverse.clear(); + let mut visitor = FindAssignments { body, candidates: &mut self.c, borrowed }; + visitor.visit_body(body); + // Deduplicate candidates. + for (_, cands) in self.c.iter_mut() { + cands.sort(); + cands.dedup(); + } + // Generate the reverse map. + for (src, cands) in self.c.iter() { + for dest in cands.iter().copied() { + self.reverse.entry(dest).or_default().push(*src); + } + } + } + /// Just `Vec::retain`, but the condition is inverted and we add debugging output fn vec_filter_candidates( src: Local, @@ -447,7 +451,7 @@ enum CandidateFilter { Remove, } -impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { +impl<'a, 'tcx> FilterInformation<'a, 'tcx> { /// Filters the set of candidates to remove those that conflict. /// /// The steps we take are exactly those that are outlined at the top of the file. For each @@ -465,12 +469,12 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { /// before the statement/terminator will correctly report locals that are read in the /// statement/terminator to be live. We are additionally conservative by treating all written to /// locals as also being read from. - fn filter_liveness<'b>( - candidates: &mut Candidates<'alloc>, + fn filter_liveness( + candidates: &mut Candidates, points: &DenseLocationMap, live: &SparseIntervalMatrix, - write_info_alloc: &'alloc mut WriteInfo, - body: &'b Body<'tcx>, + write_info: &mut WriteInfo, + body: &Body<'tcx>, ) { let mut this = FilterInformation { body, @@ -479,7 +483,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { candidates, // We don't actually store anything at this scope, we just keep things here to be able // to reuse the allocation. - write_info: write_info_alloc, + write_info, // Doesn't matter what we put here, will be overwritten before being used at: Location::START, }; @@ -736,40 +740,13 @@ fn places_to_candidate_pair<'tcx>( Some((a, b)) } -/// Collects the candidates for merging -/// -/// This is responsible for enforcing the first and third bullet point. -fn find_candidates<'alloc, 'tcx>( - body: &Body<'tcx>, - borrowed: &BitSet, - candidates: &'alloc mut FxIndexMap>, - candidates_reverse: &'alloc mut FxIndexMap>, -) -> Candidates<'alloc> { - candidates.clear(); - candidates_reverse.clear(); - let mut visitor = FindAssignments { body, candidates, borrowed }; - visitor.visit_body(body); - // Deduplicate candidates - for (_, cands) in candidates.iter_mut() { - cands.sort(); - cands.dedup(); - } - // Generate the reverse map - for (src, cands) in candidates.iter() { - for dest in cands.iter().copied() { - candidates_reverse.entry(dest).or_default().push(*src); - } - } - Candidates { c: candidates, reverse: candidates_reverse } -} - -struct FindAssignments<'a, 'alloc, 'tcx> { +struct FindAssignments<'a, 'tcx> { body: &'a Body<'tcx>, - candidates: &'alloc mut FxIndexMap>, + candidates: &'a mut FxIndexMap>, borrowed: &'a BitSet, } -impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> { +impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { if let StatementKind::Assign(box ( lhs, @@ -821,9 +798,9 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool { ///////////////////////////////////////////////////////// // MIR Dump -fn dest_prop_mir_dump<'body, 'tcx>( +fn dest_prop_mir_dump<'tcx>( tcx: TyCtxt<'tcx>, - body: &'body Body<'tcx>, + body: &Body<'tcx>, points: &DenseLocationMap, live: &SparseIntervalMatrix, round: usize, diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs index 29db45f94506f..5dd84975b88ed 100644 --- a/compiler/rustc_mir_transform/src/dump_mir.rs +++ b/compiler/rustc_mir_transform/src/dump_mir.rs @@ -3,15 +3,13 @@ use std::fs::File; use std::io; -use rustc_middle::mir::{write_mir_pretty, Body}; +use rustc_middle::mir::{Body, write_mir_pretty}; use rustc_middle::ty::TyCtxt; use rustc_session::config::{OutFileName, OutputType}; -use crate::MirPass; +pub(super) struct Marker(pub &'static str); -pub struct Marker(pub &'static str); - -impl<'tcx> MirPass<'tcx> for Marker { +impl<'tcx> crate::MirPass<'tcx> for Marker { fn name(&self) -> &'static str { self.0 } @@ -26,7 +24,7 @@ pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> { write_mir_pretty(tcx, None, &mut f)?; } OutFileName::Real(path) => { - let mut f = io::BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; write_mir_pretty(tcx, None, &mut f)?; if tcx.sess.opts.json_artifact_notifications { tcx.dcx().emit_artifact_notification(&path, "mir"); diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 67b81efd61475..704ed508b22a8 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -90,9 +90,9 @@ use super::simplify::simplify_cfg; /// | ... | /// ================= /// ``` -pub struct EarlyOtherwiseBranch; +pub(super) struct EarlyOtherwiseBranch; -impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { +impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 2 } @@ -261,8 +261,8 @@ fn evaluate_candidate<'tcx>( // }; // ``` // - // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an - // invalid value, which is UB. + // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant + // of an invalid value, which is UB. // In order to fix this, **we would either need to show that the discriminant computation of // `place` is computed in all branches**. // FIXME(#95162) For the moment, we adopt a conservative approach and @@ -310,42 +310,28 @@ fn verify_candidate_branch<'tcx>( ) -> bool { // In order for the optimization to be correct, the branch must... // ...have exactly one statement - let [statement] = branch.statements.as_slice() else { - return false; - }; - // ...assign the discriminant of `place` in that statement - let StatementKind::Assign(boxed) = &statement.kind else { return false }; - let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { return false }; - if *from_place != place { - return false; - } - // ...make that assignment to a local - if discr_place.projection.len() != 0 { - return false; - } - // ...terminate on a `SwitchInt` that invalidates that local - let TerminatorKind::SwitchInt { discr: switch_op, targets, .. } = &branch.terminator().kind - else { - return false; - }; - if *switch_op != Operand::Move(*discr_place) { - return false; - } - // ...fall through to `destination` if the switch misses - if destination != targets.otherwise() { - return false; - } - // ...have a branch for value `value` - let mut iter = targets.iter(); - let Some((target_value, _)) = iter.next() else { - return false; - }; - if target_value != value { - return false; - } - // ...and have no more branches - if let Some(_) = iter.next() { - return false; + if let [statement] = branch.statements.as_slice() + // ...assign the discriminant of `place` in that statement + && let StatementKind::Assign(boxed) = &statement.kind + && let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed + && *from_place == place + // ...make that assignment to a local + && discr_place.projection.is_empty() + // ...terminate on a `SwitchInt` that invalidates that local + && let TerminatorKind::SwitchInt { discr: switch_op, targets, .. } = + &branch.terminator().kind + && *switch_op == Operand::Move(*discr_place) + // ...fall through to `destination` if the switch misses + && destination == targets.otherwise() + // ...have a branch for value `value` + && let mut iter = targets.iter() + && let Some((target_value, _)) = iter.next() + && target_value == value + // ...and have no more branches + && iter.next().is_none() + { + true + } else { + false } - true } diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index e5778f8a05d2e..57f7a9ef7f5fc 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{Ty, TyCtxt}; use rustc_target::abi::FieldIdx; /// Constructs the types used when accessing a Box's pointer -pub fn build_ptr_tys<'tcx>( +fn build_ptr_tys<'tcx>( tcx: TyCtxt<'tcx>, pointee: Ty<'tcx>, unique_did: DefId, @@ -26,7 +26,7 @@ pub fn build_ptr_tys<'tcx>( } /// Constructs the projection needed to access a Box's pointer -pub fn build_projection<'tcx>( +pub(super) fn build_projection<'tcx>( unique_ty: Ty<'tcx>, nonnull_ty: Ty<'tcx>, ptr_ty: Ty<'tcx>, @@ -38,7 +38,7 @@ pub fn build_projection<'tcx>( ] } -struct ElaborateBoxDerefVisitor<'tcx, 'a> { +struct ElaborateBoxDerefVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, unique_did: DefId, nonnull_did: DefId, @@ -46,7 +46,7 @@ struct ElaborateBoxDerefVisitor<'tcx, 'a> { patch: MirPatch<'tcx>, } -impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { +impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -62,11 +62,13 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { let base_ty = self.local_decls[place.local].ty; // Derefer ensures that derefs are always the first projection - if place.projection.first() == Some(&PlaceElem::Deref) && base_ty.is_box() { + if let Some(PlaceElem::Deref) = place.projection.first() + && let Some(boxed_ty) = base_ty.boxed_ty() + { let source_info = self.local_decls[place.local].source_info; let (unique_ty, nonnull_ty, ptr_ty) = - build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did); + build_ptr_tys(tcx, boxed_ty, self.unique_did, self.nonnull_did); let ptr_local = self.patch.new_temp(ptr_ty, source_info.span); @@ -86,66 +88,65 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { } } -pub struct ElaborateBoxDerefs; +pub(super) struct ElaborateBoxDerefs; -impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { +impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if let Some(def_id) = tcx.lang_items().owned_box() { - let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did; + // If box is not present, this pass doesn't need to do anything. + let Some(def_id) = tcx.lang_items().owned_box() else { return }; - let Some(nonnull_def) = tcx.type_of(unique_did).instantiate_identity().ty_adt_def() - else { - span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique") - }; + let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did; - let nonnull_did = nonnull_def.non_enum_variant().fields[FieldIdx::ZERO].did; + let Some(nonnull_def) = tcx.type_of(unique_did).instantiate_identity().ty_adt_def() else { + span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique") + }; - let patch = MirPatch::new(body); + let nonnull_did = nonnull_def.non_enum_variant().fields[FieldIdx::ZERO].did; - let local_decls = &mut body.local_decls; + let patch = MirPatch::new(body); - let mut visitor = - ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; + let local_decls = &mut body.local_decls; - for (block, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { - visitor.visit_basic_block_data(block, data); - } + let mut visitor = + ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; - visitor.patch.apply(body); + for (block, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(block, data); + } - for debug_info in body.var_debug_info.iter_mut() { - if let VarDebugInfoContents::Place(place) = &mut debug_info.value { - let mut new_projections: Option> = None; + visitor.patch.apply(body); - for (base, elem) in place.iter_projections() { - let base_ty = base.ty(&body.local_decls, tcx).ty; + for debug_info in body.var_debug_info.iter_mut() { + if let VarDebugInfoContents::Place(place) = &mut debug_info.value { + let mut new_projections: Option> = None; - if elem == PlaceElem::Deref && base_ty.is_box() { - // Clone the projections before us, since now we need to mutate them. - let new_projections = - new_projections.get_or_insert_with(|| base.projection.to_vec()); + for (base, elem) in place.iter_projections() { + let base_ty = base.ty(&body.local_decls, tcx).ty; - let (unique_ty, nonnull_ty, ptr_ty) = - build_ptr_tys(tcx, base_ty.boxed_ty(), unique_did, nonnull_did); + if let PlaceElem::Deref = elem + && let Some(boxed_ty) = base_ty.boxed_ty() + { + // Clone the projections before us, since now we need to mutate them. + let new_projections = + new_projections.get_or_insert_with(|| base.projection.to_vec()); - new_projections.extend_from_slice(&build_projection( - unique_ty, nonnull_ty, ptr_ty, - )); - new_projections.push(PlaceElem::Deref); - } else if let Some(new_projections) = new_projections.as_mut() { - // Keep building up our projections list once we've started it. - new_projections.push(elem); - } - } + let (unique_ty, nonnull_ty, ptr_ty) = + build_ptr_tys(tcx, boxed_ty, unique_did, nonnull_did); - // Store the mutated projections if we actually changed something. - if let Some(new_projections) = new_projections { - place.projection = tcx.mk_place_elems(&new_projections); + new_projections + .extend_from_slice(&build_projection(unique_ty, nonnull_ty, ptr_ty)); + new_projections.push(PlaceElem::Deref); + } else if let Some(new_projections) = new_projections.as_mut() { + // Keep building up our projections list once we've started it. + new_projections.push(elem); } } + + // Store the mutated projections if we actually changed something. + if let Some(new_projections) = new_projections { + place.projection = tcx.mk_place_elems(&new_projections); + } } - } else { - // box is not present, this pass doesn't need to do anything } } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index d0809d9388def..c35aec42408ca 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -1,17 +1,17 @@ use std::fmt; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::elaborate_drops::{ - elaborate_drop, DropElaborator, DropFlagMode, DropFlagState, DropStyle, Unwind, + DropElaborator, DropFlagMode, DropFlagState, DropStyle, Unwind, elaborate_drop, }; use rustc_mir_dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use rustc_mir_dataflow::{ - on_all_children_bits, on_lookup_result_bits, Analysis, MoveDataParamEnv, ResultsCursor, + Analysis, MoveDataParamEnv, ResultsCursor, on_all_children_bits, on_lookup_result_bits, }; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; @@ -20,8 +20,8 @@ use tracing::{debug, instrument}; use crate::deref_separator::deref_finder; /// During MIR building, Drop terminators are inserted in every place where a drop may occur. -/// However, in this phase, the presence of these terminators does not guarantee that a destructor will run, -/// as the target of the drop may be uninitialized. +/// However, in this phase, the presence of these terminators does not guarantee that a destructor +/// will run, as the target of the drop may be uninitialized. /// In general, the compiler cannot determine at compile time whether a destructor will run or not. /// /// At a high level, this pass refines Drop to only run the destructor if the @@ -30,10 +30,10 @@ use crate::deref_separator::deref_finder; /// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or /// "drop shim" for the type of the dropped place. /// -/// This pass relies on dropped places having an associated move path, which is then used to determine -/// the initialization status of the place and its descendants. -/// It's worth noting that a MIR containing a Drop without an associated move path is probably ill formed, -/// as it would allow running a destructor on a place behind a reference: +/// This pass relies on dropped places having an associated move path, which is then used to +/// determine the initialization status of the place and its descendants. +/// It's worth noting that a MIR containing a Drop without an associated move path is probably ill +/// formed, as it would allow running a destructor on a place behind a reference: /// /// ```text /// fn drop_term(t: &mut T) { @@ -47,9 +47,9 @@ use crate::deref_separator::deref_finder; /// } /// } /// ``` -pub struct ElaborateDrops; +pub(super) struct ElaborateDrops; -impl<'tcx> MirPass<'tcx> for ElaborateDrops { +impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); @@ -98,9 +98,9 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { /// Records unwind edges which are known to be unreachable, because they are in `drop` terminators /// that can't drop anything. #[instrument(level = "trace", skip(body, flow_inits), ret)] -fn compute_dead_unwinds<'mir, 'tcx>( - body: &'mir Body<'tcx>, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>, +fn compute_dead_unwinds<'a, 'tcx>( + body: &'a Body<'tcx>, + flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, ) -> BitSet { // We only need to do this pass once, because unwind edges can only // reach cleanup blocks, which can't have unwind edges themselves. @@ -121,12 +121,12 @@ fn compute_dead_unwinds<'mir, 'tcx>( dead_unwinds } -struct InitializationData<'a, 'mir, 'tcx> { - inits: ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'a, 'mir, 'tcx>>, - uninits: ResultsCursor<'mir, 'tcx, MaybeUninitializedPlaces<'a, 'mir, 'tcx>>, +struct InitializationData<'a, 'tcx> { + inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + uninits: ResultsCursor<'a, 'tcx, MaybeUninitializedPlaces<'a, 'tcx>>, } -impl InitializationData<'_, '_, '_> { +impl InitializationData<'_, '_> { fn seek_before(&mut self, loc: Location) { self.inits.seek_before_primary_effect(loc); self.uninits.seek_before_primary_effect(loc); @@ -137,45 +137,35 @@ impl InitializationData<'_, '_, '_> { } } -struct Elaborator<'a, 'b, 'mir, 'tcx> { - ctxt: &'a mut ElaborateDropsCtxt<'b, 'mir, 'tcx>, -} - -impl fmt::Debug for Elaborator<'_, '_, '_, '_> { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, '_, 'tcx> { +impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> { type Path = MovePathIndex; fn patch(&mut self) -> &mut MirPatch<'tcx> { - &mut self.ctxt.patch + &mut self.patch } fn body(&self) -> &'a Body<'tcx> { - self.ctxt.body + self.body } fn tcx(&self) -> TyCtxt<'tcx> { - self.ctxt.tcx + self.tcx } fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.ctxt.param_env() + self.param_env() } #[instrument(level = "debug", skip(self), ret)] fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { let ((maybe_live, maybe_dead), multipart) = match mode { - DropFlagMode::Shallow => (self.ctxt.init_data.maybe_live_dead(path), false), + DropFlagMode::Shallow => (self.init_data.maybe_live_dead(path), false), DropFlagMode::Deep => { let mut some_live = false; let mut some_dead = false; let mut children_count = 0; - on_all_children_bits(self.ctxt.move_data(), path, |child| { - let (live, dead) = self.ctxt.init_data.maybe_live_dead(child); + on_all_children_bits(self.move_data(), path, |child| { + let (live, dead) = self.init_data.maybe_live_dead(child); debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); some_live |= live; some_dead |= dead; @@ -195,25 +185,25 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, '_, 'tcx> { fn clear_drop_flag(&mut self, loc: Location, path: Self::Path, mode: DropFlagMode) { match mode { DropFlagMode::Shallow => { - self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent); + self.set_drop_flag(loc, path, DropFlagState::Absent); } DropFlagMode::Deep => { - on_all_children_bits(self.ctxt.move_data(), path, |child| { - self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent) + on_all_children_bits(self.move_data(), path, |child| { + self.set_drop_flag(loc, child, DropFlagState::Absent) }); } } } fn field_subpath(&self, path: Self::Path, field: FieldIdx) -> Option { - rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + rustc_mir_dataflow::move_path_children_matching(self.move_data(), path, |e| match e { ProjectionElem::Field(idx, _) => idx == field, _ => false, }) } fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option { - rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + rustc_mir_dataflow::move_path_children_matching(self.move_data(), path, |e| match e { ProjectionElem::ConstantIndex { offset, min_length, from_end } => { debug_assert!(size == min_length, "min_length should be exact for arrays"); assert!(!from_end, "from_end should not be used for array element ConstantIndex"); @@ -224,34 +214,40 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, '_, 'tcx> { } fn deref_subpath(&self, path: Self::Path) -> Option { - rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| { + rustc_mir_dataflow::move_path_children_matching(self.move_data(), path, |e| { e == ProjectionElem::Deref }) } fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option { - rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + rustc_mir_dataflow::move_path_children_matching(self.move_data(), path, |e| match e { ProjectionElem::Downcast(_, idx) => idx == variant, _ => false, }) } fn get_drop_flag(&mut self, path: Self::Path) -> Option> { - self.ctxt.drop_flag(path).map(Operand::Copy) + self.drop_flag(path).map(Operand::Copy) } } -struct ElaborateDropsCtxt<'a, 'mir, 'tcx> { +struct ElaborateDropsCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, + body: &'a Body<'tcx>, env: &'a MoveDataParamEnv<'tcx>, - init_data: InitializationData<'a, 'mir, 'tcx>, + init_data: InitializationData<'a, 'tcx>, drop_flags: IndexVec>, patch: MirPatch<'tcx>, } -impl<'b, 'mir, 'tcx> ElaborateDropsCtxt<'b, 'mir, 'tcx> { - fn move_data(&self) -> &'b MoveData<'tcx> { +impl fmt::Debug for ElaborateDropsCtxt<'_, '_> { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { + fn move_data(&self) -> &'a MoveData<'tcx> { &self.env.move_data } @@ -370,15 +366,7 @@ impl<'b, 'mir, 'tcx> ElaborateDropsCtxt<'b, 'mir, 'tcx> { } }; self.init_data.seek_before(self.body.terminator_loc(bb)); - elaborate_drop( - &mut Elaborator { ctxt: self }, - terminator.source_info, - place, - path, - target, - unwind, - bb, - ) + elaborate_drop(self, terminator.source_info, place, path, target, unwind, bb) } LookupResult::Parent(None) => {} LookupResult::Parent(Some(_)) => { @@ -389,8 +377,8 @@ impl<'b, 'mir, 'tcx> ElaborateDropsCtxt<'b, 'mir, 'tcx> { ); } // A drop and replace behind a pointer/array/whatever. - // The borrow checker requires that these locations are initialized before the assignment, - // so we just leave an unconditional drop. + // The borrow checker requires that these locations are initialized before the + // assignment, so we just leave an unconditional drop. assert!(!data.is_cleanup); } } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 2703dc57cdad9..84d44c2ab4c41 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -4,8 +4,8 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::AssertKind; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{self, Lint}; -use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_span::def_id::DefId; use crate::fluent_generated as fluent; @@ -64,7 +64,7 @@ impl<'a, P: std::fmt::Debug> LintDiagnostic<'a, ()> for AssertLint

{ } impl AssertLintKind { - pub fn lint(&self) -> &'static Lint { + pub(crate) fn lint(&self) -> &'static Lint { match self { AssertLintKind::ArithmeticOverflow => lint::builtin::ARITHMETIC_OVERFLOW, AssertLintKind::UnconditionalPanic => lint::builtin::UNCONDITIONAL_PANIC, @@ -89,7 +89,7 @@ pub(crate) struct FnItemRef { pub ident: String, } -pub(crate) struct MustNotSupend<'tcx, 'a> { +pub(crate) struct MustNotSupend<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, pub yield_sp: Span, pub reason: Option, diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 81875e3d01246..99892a1296be4 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -1,11 +1,11 @@ -use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{LOCAL_CRATE, LocalDefId}; use rustc_middle::mir::*; use rustc_middle::query::{LocalCrate, Providers}; -use rustc_middle::ty::{self, layout, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, layout}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::FFI_UNWIND_CALLS; -use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; +use rustc_target::spec::abi::Abi; use tracing::debug; use crate::errors; @@ -60,8 +60,9 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let fn_def_id = match ty.kind() { ty::FnPtr(..) => None, &ty::FnDef(def_id, _) => { - // Rust calls cannot themselves create foreign unwinds (even if they use a non-Rust ABI). - // So the leak of the foreign unwind into Rust can only be elsewhere, not here. + // Rust calls cannot themselves create foreign unwinds (even if they use a non-Rust + // ABI). So the leak of the foreign unwind into Rust can only be elsewhere, not + // here. if !tcx.is_foreign_item(def_id) { continue; } @@ -85,12 +86,10 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let span = terminator.source_info.span; let foreign = fn_def_id.is_some(); - tcx.emit_node_span_lint( - FFI_UNWIND_CALLS, - lint_root, + tcx.emit_node_span_lint(FFI_UNWIND_CALLS, lint_root, span, errors::FfiUnwindCall { span, - errors::FfiUnwindCall { span, foreign }, - ); + foreign, + }); tainted = true; } diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index b7873e73c18c7..e55aeeac6e069 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -4,16 +4,16 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt}; use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; +use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_span::Span; use rustc_target::spec::abi::Abi; -use crate::{errors, MirLint}; +use crate::errors; -pub struct FunctionItemReferences; +pub(super) struct FunctionItemReferences; -impl<'tcx> MirLint<'tcx> for FunctionItemReferences { +impl<'tcx> crate::MirLint<'tcx> for FunctionItemReferences { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let mut checker = FunctionItemRefChecker { tcx, body }; checker.visit_body(body); @@ -92,8 +92,8 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { { let mut span = self.nth_arg_span(args, arg_num); if span.from_expansion() { - // The operand's ctxt wouldn't display the lint since it's inside a macro so - // we have to use the callsite's ctxt. + // The operand's ctxt wouldn't display the lint since it's + // inside a macro so we have to use the callsite's ctxt. let callsite_ctxt = span.source_callsite().ctxt(); span = span.with_ctxt(callsite_ctxt); } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index fb9baeeb3ed88..f735d08fca573 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -87,31 +87,31 @@ use std::borrow::Cow; use either::Either; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ - intern_const_alloc_for_constprop, ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, - Projectable, Scalar, + ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar, + intern_const_alloc_for_constprop, }; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::graph::dominators::Dominators; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; -use rustc_index::{newtype_index, IndexVec}; +use rustc_index::{IndexVec, newtype_index}; use rustc_middle::bug; use rustc_middle::mir::interpret::GlobalAlloc; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::def_id::DefId; use rustc_span::DUMMY_SP; -use rustc_target::abi::{self, Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT}; +use rustc_span::def_id::DefId; +use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use smallvec::SmallVec; use tracing::{debug, instrument, trace}; use crate::ssa::{AssignedValue, SsaLocals}; -pub struct GVN; +pub(super) struct GVN; -impl<'tcx> MirPass<'tcx> for GVN { +impl<'tcx> crate::MirPass<'tcx> for GVN { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 2 } @@ -119,53 +119,50 @@ impl<'tcx> MirPass<'tcx> for GVN { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - propagate_ssa(tcx, body); - } -} -fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); - // Clone dominators as we need them while mutating the body. - let dominators = body.basic_blocks.dominators().clone(); - - let mut state = VnState::new(tcx, body, param_env, &ssa, &dominators, &body.local_decls); - ssa.for_each_assignment_mut( - body.basic_blocks.as_mut_preserves_cfg(), - |local, value, location| { - let value = match value { - // We do not know anything of this assigned value. - AssignedValue::Arg | AssignedValue::Terminator => None, - // Try to get some insight. - AssignedValue::Rvalue(rvalue) => { - let value = state.simplify_rvalue(rvalue, location); - // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as - // reusable if we have an exact type match. - if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) { - return; + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let ssa = SsaLocals::new(tcx, body, param_env); + // Clone dominators because we need them while mutating the body. + let dominators = body.basic_blocks.dominators().clone(); + + let mut state = VnState::new(tcx, body, param_env, &ssa, dominators, &body.local_decls); + ssa.for_each_assignment_mut( + body.basic_blocks.as_mut_preserves_cfg(), + |local, value, location| { + let value = match value { + // We do not know anything of this assigned value. + AssignedValue::Arg | AssignedValue::Terminator => None, + // Try to get some insight. + AssignedValue::Rvalue(rvalue) => { + let value = state.simplify_rvalue(rvalue, location); + // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark + // `local` as reusable if we have an exact type match. + if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) { + return; + } + value } - value - } - }; - // `next_opaque` is `Some`, so `new_opaque` must return `Some`. - let value = value.or_else(|| state.new_opaque()).unwrap(); - state.assign(local, value); - }, - ); - - // Stop creating opaques during replacement as it is useless. - state.next_opaque = None; - - let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); - for bb in reverse_postorder { - let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; - state.visit_basic_block_data(bb, data); - } + }; + // `next_opaque` is `Some`, so `new_opaque` must return `Some`. + let value = value.or_else(|| state.new_opaque()).unwrap(); + state.assign(local, value); + }, + ); + + // Stop creating opaques during replacement as it is useless. + state.next_opaque = None; + + let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); + for bb in reverse_postorder { + let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; + state.visit_basic_block_data(bb, data); + } - // For each local that is reused (`y` above), we remove its storage statements do avoid any - // difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage - // statements. - StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body); + // For each local that is reused (`y` above), we remove its storage statements do avoid any + // difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage + // statements. + StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body); + } } newtype_index! { @@ -261,7 +258,7 @@ struct VnState<'body, 'tcx> { /// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop. feature_unsized_locals: bool, ssa: &'body SsaLocals, - dominators: &'body Dominators, + dominators: Dominators, reused_locals: BitSet, } @@ -271,7 +268,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>, ssa: &'body SsaLocals, - dominators: &'body Dominators, + dominators: Dominators, local_decls: &'body LocalDecls<'tcx>, ) -> Self { // Compute a rough estimate of the number of values in the body from the number of @@ -480,7 +477,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let pointer = self.evaluated[local].as_ref()?; let mut mplace = self.ecx.deref_pointer(pointer).ok()?; for proj in place.projection.iter().skip(1) { - // We have no call stack to associate a local with a value, so we cannot interpret indexing. + // We have no call stack to associate a local with a value, so we cannot + // interpret indexing. if matches!(proj, ProjectionElem::Index(_)) { return None; } @@ -578,7 +576,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } value.offset(Size::ZERO, to, &self.ecx).ok()? } - CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) => { + CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => { let src = self.evaluated[value].as_ref()?; let to = self.ecx.layout_of(to).ok()?; let dest = self.ecx.allocate(to, MemoryKind::Stack).ok()?; @@ -595,7 +593,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ret = self.ecx.ptr_to_ptr(&src, to).ok()?; ret.into() } - CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer) => { + CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => { let src = self.evaluated[value].as_ref()?; let src = self.ecx.read_immediate(src).ok()?; let to = self.ecx.layout_of(to).ok()?; @@ -877,6 +875,95 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { None } + fn try_as_place_elem( + &mut self, + proj: ProjectionElem>, + loc: Location, + ) -> Option> { + Some(match proj { + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Field(idx, ty) => ProjectionElem::Field(idx, ty), + ProjectionElem::Index(idx) => { + let Some(local) = self.try_as_local(idx, loc) else { + return None; + }; + self.reused_locals.insert(local); + ProjectionElem::Index(local) + } + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + ProjectionElem::ConstantIndex { offset, min_length, from_end } + } + ProjectionElem::Subslice { from, to, from_end } => { + ProjectionElem::Subslice { from, to, from_end } + } + ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx), + ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx), + ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx), + }) + } + + fn simplify_aggregate_to_copy( + &mut self, + rvalue: &mut Rvalue<'tcx>, + location: Location, + fields: &[VnIndex], + variant_index: VariantIdx, + ) -> Option { + let Some(&first_field) = fields.first() else { + return None; + }; + let Value::Projection(copy_from_value, _) = *self.get(first_field) else { + return None; + }; + // All fields must correspond one-to-one and come from the same aggregate value. + if fields.iter().enumerate().any(|(index, &v)| { + if let Value::Projection(pointer, ProjectionElem::Field(from_index, _)) = *self.get(v) + && copy_from_value == pointer + && from_index.index() == index + { + return false; + } + true + }) { + return None; + } + + let mut copy_from_local_value = copy_from_value; + if let Value::Projection(pointer, proj) = *self.get(copy_from_value) + && let ProjectionElem::Downcast(_, read_variant) = proj + { + if variant_index == read_variant { + // When copying a variant, there is no need to downcast. + copy_from_local_value = pointer; + } else { + // The copied variant must be identical. + return None; + } + } + + let tcx = self.tcx; + let mut projection = SmallVec::<[PlaceElem<'tcx>; 1]>::new(); + loop { + if let Some(local) = self.try_as_local(copy_from_local_value, location) { + projection.reverse(); + let place = Place { local, projection: tcx.mk_place_elems(projection.as_slice()) }; + if rvalue.ty(self.local_decls, tcx) == place.ty(self.local_decls, tcx).ty { + self.reused_locals.insert(local); + *rvalue = Rvalue::Use(Operand::Copy(place)); + return Some(copy_from_value); + } + return None; + } else if let Value::Projection(pointer, proj) = *self.get(copy_from_local_value) + && let Some(proj) = self.try_as_place_elem(proj, location) + { + projection.push(proj); + copy_from_local_value = pointer; + } else { + return None; + } + } + } + fn simplify_aggregate( &mut self, rvalue: &mut Rvalue<'tcx>, @@ -973,6 +1060,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } + if let AggregateTy::Def(_, _) = ty + && let Some(value) = + self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index) + { + return Some(value); + } + Some(self.insert(Value::Aggregate(ty, variant_index, fields))) } @@ -1044,7 +1138,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ( UnOp::PtrMetadata, Value::Cast { - kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), + kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _), from, to, .. @@ -1239,8 +1333,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { to: Ty<'tcx>, location: Location, ) -> Option { - use rustc_middle::ty::adjustment::PointerCoercion::*; use CastKind::*; + use rustc_middle::ty::adjustment::PointerCoercion::*; let mut from = operand.ty(self.local_decls, self.tcx); let mut value = self.simplify_operand(operand, location)?; @@ -1248,7 +1342,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return Some(value); } - if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_)) = kind { + if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind { // Each reification of a generic fn may get a different pointer. // Do not try to merge them. return self.new_opaque(); @@ -1335,7 +1429,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // We have an unsizing cast, which assigns the length to fat pointer metadata. if let Value::Cast { kind, from, to, .. } = self.get(inner) - && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind + && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind && let Some(from) = from.builtin_deref(true) && let ty::Array(_, len) = from.kind() && let Some(to) = to.builtin_deref(true) @@ -1382,7 +1476,8 @@ fn op_to_prop_const<'tcx>( return Some(ConstValue::ZeroSized); } - // Do not synthetize too large constants. Codegen will just memcpy them, which we'd like to avoid. + // Do not synthetize too large constants. Codegen will just memcpy them, which we'd like to + // avoid. if !matches!(op.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { return None; } @@ -1486,12 +1581,12 @@ impl<'tcx> VnState<'_, 'tcx> { } /// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`, - /// return it. + /// return it. If you used this local, add it to `reused_locals` to remove storage statements. fn try_as_local(&mut self, index: VnIndex, loc: Location) -> Option { let other = self.rev_locals.get(index)?; other .iter() - .find(|&&other| self.ssa.assignment_dominates(self.dominators, other, loc)) + .find(|&&other| self.ssa.assignment_dominates(&self.dominators, other, loc)) .copied() } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 4482801826ab0..c9f24764cc2a1 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -6,8 +6,8 @@ use std::ops::{Range, RangeFrom}; use rustc_attr::InlineAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_index::bit_set::BitSet; use rustc_index::Idx; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; @@ -32,9 +32,11 @@ pub(crate) mod cycle; const TOP_DOWN_DEPTH_LIMIT: usize = 5; +// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden +// by custom rustc drivers, running all the steps by themselves. See #114628. pub struct Inline; -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] struct CallSite<'tcx> { callee: Instance<'tcx>, fn_sig: ty::PolyFnSig<'tcx>, @@ -42,7 +44,7 @@ struct CallSite<'tcx> { source_info: SourceInfo, } -impl<'tcx> MirPass<'tcx> for Inline { +impl<'tcx> crate::MirPass<'tcx> for Inline { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined // MIR correctly when Modified Condition/Decision Coverage is enabled. @@ -156,7 +158,6 @@ impl<'tcx> Inliner<'tcx> { match self.try_inlining(caller_body, &callsite) { Err(reason) => { debug!("not-inlined {} [{}]", callsite.callee, reason); - continue; } Ok(new_blocks) => { debug!("inlined {}", callsite.callee); @@ -356,16 +357,6 @@ impl<'tcx> Inliner<'tcx> { } if callee_def_id.is_local() { - // Avoid a cycle here by only using `instance_mir` only if we have - // a lower `DefPathHash` than the callee. This ensures that the callee will - // not inline us. This trick even works with incremental compilation, - // since `DefPathHash` is stable. - if self.tcx.def_path_hash(caller_def_id).local_hash() - < self.tcx.def_path_hash(callee_def_id).local_hash() - { - return Ok(()); - } - // If we know for sure that the function we're calling will itself try to // call us, then we avoid inlining that function. if self.tcx.mir_callgraph_reachable((callee, caller_def_id.expect_local())) { @@ -567,7 +558,8 @@ impl<'tcx> Inliner<'tcx> { // if the no-attribute function ends up with the same instruction set anyway. return Err("Cannot move inline-asm across instruction sets"); } else if let TerminatorKind::TailCall { .. } = term.kind { - // FIXME(explicit_tail_calls): figure out how exactly functions containing tail calls can be inlined (and if they even should) + // FIXME(explicit_tail_calls): figure out how exactly functions containing tail + // calls can be inlined (and if they even should) return Err("can't inline functions with tail calls"); } else { work_list.extend(term.successors()) @@ -638,7 +630,7 @@ impl<'tcx> Inliner<'tcx> { ); let dest_ty = dest.ty(caller_body, self.tcx); let temp = - Place::from(self.new_call_temp(caller_body, &callsite, dest_ty, return_block)); + Place::from(self.new_call_temp(caller_body, callsite, dest_ty, return_block)); caller_body[callsite.block].statements.push(Statement { source_info: callsite.source_info, kind: StatementKind::Assign(Box::new((temp, dest))), @@ -657,7 +649,7 @@ impl<'tcx> Inliner<'tcx> { true, self.new_call_temp( caller_body, - &callsite, + callsite, destination.ty(caller_body, self.tcx).ty, return_block, ), @@ -665,7 +657,7 @@ impl<'tcx> Inliner<'tcx> { }; // Copy the arguments if needed. - let args = self.make_call_args(args, &callsite, caller_body, &callee_body, return_block); + let args = self.make_call_args(args, callsite, caller_body, &callee_body, return_block); let mut integrator = Integrator { args: &args, @@ -893,13 +885,10 @@ impl<'tcx> Inliner<'tcx> { }); if let Some(block) = return_block { - caller_body[block].statements.insert( - 0, - Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageDead(local), - }, - ); + caller_body[block].statements.insert(0, Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageDead(local), + }); } local diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 3ec553d0ba0c5..8bcc91b448858 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -5,7 +5,7 @@ use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::*; use rustc_middle::ty::layout::ValidityRequirement; -use rustc_middle::ty::{self, layout, GenericArgsRef, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, layout}; use rustc_span::sym; use rustc_span::symbol::Symbol; use rustc_target::spec::abi::Abi; @@ -13,24 +13,18 @@ use rustc_target::spec::abi::Abi; use crate::simplify::simplify_duplicate_switch_targets; use crate::take_array; -pub enum InstSimplify { +pub(super) enum InstSimplify { BeforeInline, AfterSimplifyCfg, } -impl InstSimplify { - pub fn name(&self) -> &'static str { +impl<'tcx> crate::MirPass<'tcx> for InstSimplify { + fn name(&self) -> &'static str { match self { InstSimplify::BeforeInline => "InstSimplify-before-inline", InstSimplify::AfterSimplifyCfg => "InstSimplify-after-simplifycfg", } } -} - -impl<'tcx> MirPass<'tcx> for InstSimplify { - fn name(&self) -> &'static str { - self.name() - } fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() > 0 @@ -69,13 +63,13 @@ impl<'tcx> MirPass<'tcx> for InstSimplify { } } -struct InstSimplifyContext<'tcx, 'a> { +struct InstSimplifyContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, param_env: ParamEnv<'tcx>, } -impl<'tcx> InstSimplifyContext<'tcx, '_> { +impl<'tcx> InstSimplifyContext<'_, 'tcx> { fn should_simplify(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool { self.should_simplify_custom(source_info, "Rvalue", rvalue) } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 435b6a0116348..9d85b5ba5a71c 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -39,8 +39,8 @@ use rustc_arena::DroplessArena; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; use rustc_data_structures::fx::FxHashSet; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::Visitor; @@ -55,13 +55,13 @@ use tracing::{debug, instrument, trace}; use crate::cost_checker::CostChecker; -pub struct JumpThreading; +pub(super) struct JumpThreading; const MAX_BACKTRACK: usize = 5; const MAX_COST: usize = 100; const MAX_PLACES: usize = 100; -impl<'tcx> MirPass<'tcx> for JumpThreading { +impl<'tcx> crate::MirPass<'tcx> for JumpThreading { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 2 } @@ -78,18 +78,16 @@ impl<'tcx> MirPass<'tcx> for JumpThreading { } let param_env = tcx.param_env_reveal_all_normalized(def_id); - let map = Map::new(tcx, body, Some(MAX_PLACES)); - let loop_headers = loop_headers(body); - let arena = DroplessArena::default(); + let arena = &DroplessArena::default(); let mut finder = TOFinder { tcx, param_env, ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), body, - arena: &arena, - map: &map, - loop_headers: &loop_headers, + arena, + map: Map::new(tcx, body, Some(MAX_PLACES)), + loop_headers: loop_headers(body), opportunities: Vec::new(), }; @@ -105,7 +103,7 @@ impl<'tcx> MirPass<'tcx> for JumpThreading { // Verify that we do not thread through a loop header. for to in opportunities.iter() { - assert!(to.chain.iter().all(|&block| !loop_headers.contains(block))); + assert!(to.chain.iter().all(|&block| !finder.loop_headers.contains(block))); } OpportunitySet::new(body, opportunities).apply(body); } @@ -119,13 +117,13 @@ struct ThreadingOpportunity { target: BasicBlock, } -struct TOFinder<'tcx, 'a> { +struct TOFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, body: &'a Body<'tcx>, - map: &'a Map<'tcx>, - loop_headers: &'a BitSet, + map: Map<'tcx>, + loop_headers: BitSet, /// We use an arena to avoid cloning the slices when cloning `state`. arena: &'a DroplessArena, opportunities: Vec, @@ -185,7 +183,7 @@ impl<'a> ConditionSet<'a> { } } -impl<'tcx, 'a> TOFinder<'tcx, 'a> { +impl<'a, 'tcx> TOFinder<'a, 'tcx> { fn is_empty(&self, state: &State>) -> bool { state.all_bottom() } @@ -223,7 +221,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { })) }; let conds = ConditionSet(conds); - state.insert_value_idx(discr, conds, self.map); + state.insert_value_idx(discr, conds, &self.map); self.find_opportunity(bb, state, cost, 0); } @@ -264,7 +262,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // _1 = 5 // Whatever happens here, it won't change the result of a `SwitchInt`. // _1 = 6 if let Some((lhs, tail)) = self.mutated_statement(stmt) { - state.flood_with_tail_elem(lhs.as_ref(), tail, self.map, ConditionSet::BOTTOM); + state.flood_with_tail_elem(lhs.as_ref(), tail, &self.map, ConditionSet::BOTTOM); } } @@ -370,7 +368,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) }; - if let Some(conditions) = state.try_get_idx(lhs, self.map) + if let Some(conditions) = state.try_get_idx(lhs, &self.map) && let Immediate::Scalar(Scalar::Int(int)) = *rhs { conditions.iter_matches(int).for_each(register_opportunity); @@ -406,7 +404,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { } }, &mut |place, op| { - if let Some(conditions) = state.try_get_idx(place, self.map) + if let Some(conditions) = state.try_get_idx(place, &self.map) && let Ok(imm) = self.ecx.read_immediate_raw(op) && let Some(imm) = imm.right() && let Immediate::Scalar(Scalar::Int(int)) = *imm @@ -441,7 +439,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // Transfer the conditions on the copied rhs. Operand::Move(rhs) | Operand::Copy(rhs) => { let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; - state.insert_place_idx(rhs, lhs, self.map); + state.insert_place_idx(rhs, lhs, &self.map); } } } @@ -461,7 +459,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { Rvalue::CopyForDeref(rhs) => self.process_operand(bb, lhs, &Operand::Copy(*rhs), state), Rvalue::Discriminant(rhs) => { let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return }; - state.insert_place_idx(rhs, lhs, self.map); + state.insert_place_idx(rhs, lhs, &self.map); } // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Rvalue::Aggregate(box ref kind, ref operands) => { @@ -492,10 +490,10 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { } // Transfer the conditions on the copy rhs, after inversing polarity. Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { - let Some(conditions) = state.try_get_idx(lhs, self.map) else { return }; + let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; let Some(place) = self.map.find(place.as_ref()) else { return }; let conds = conditions.map(self.arena, Condition::inv); - state.insert_value_idx(place, conds, self.map); + state.insert_value_idx(place, conds, &self.map); } // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. // Create a condition on `rhs ?= B`. @@ -504,7 +502,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { box (Operand::Move(place) | Operand::Copy(place), Operand::Constant(value)) | box (Operand::Constant(value), Operand::Move(place) | Operand::Copy(place)), ) => { - let Some(conditions) = state.try_get_idx(lhs, self.map) else { return }; + let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; let Some(place) = self.map.find(place.as_ref()) else { return }; let equals = match op { BinOp::Eq => ScalarInt::TRUE, @@ -528,7 +526,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne }, ..c }); - state.insert_value_idx(place, conds, self.map); + state.insert_value_idx(place, conds, &self.map); } _ => {} @@ -583,7 +581,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( Operand::Copy(place) | Operand::Move(place), )) => { - let Some(conditions) = state.try_get(place.as_ref(), self.map) else { return }; + let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { return }; conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity); } StatementKind::Assign(box (lhs_place, rhs)) => { @@ -631,7 +629,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // We can recurse through this terminator. let mut state = state(); if let Some(place_to_flood) = place_to_flood { - state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::BOTTOM); + state.flood_with(place_to_flood.as_ref(), &self.map, ConditionSet::BOTTOM); } self.find_opportunity(bb, state, cost.clone(), depth + 1); } @@ -650,7 +648,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { let Some(discr) = discr.place() else { return }; let discr_ty = discr.ty(self.body, self.tcx).ty; let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; - let Some(conditions) = state.try_get(discr.as_ref(), self.map) else { return }; + let Some(conditions) = state.try_get(discr.as_ref(), &self.map) else { return }; if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) { let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 443d97d004e16..783e7aabe8543 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -1,20 +1,18 @@ -//! A lint that checks for known panics like -//! overflows, division by zero, -//! out-of-bound access etc. -//! Uses const propagation to determine the -//! values of operands during checks. +//! A lint that checks for known panics like overflows, division by zero, +//! out-of-bound access etc. Uses const propagation to determine the values of +//! operands during checks. use std::fmt::Debug; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ - format_interp_error, ImmTy, InterpCx, InterpResult, Projectable, Scalar, + ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, }; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def::DefKind; use rustc_hir::HirId; -use rustc_index::bit_set::BitSet; +use rustc_hir::def::DefKind; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -25,11 +23,10 @@ use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, Va use tracing::{debug, instrument, trace}; use crate::errors::{AssertLint, AssertLintKind}; -use crate::MirLint; -pub struct KnownPanicsLint; +pub(super) struct KnownPanicsLint; -impl<'tcx> MirLint<'tcx> for KnownPanicsLint { +impl<'tcx> crate::MirLint<'tcx> for KnownPanicsLint { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { if body.tainted_by_errors.is_some() { return; @@ -299,12 +296,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let source_info = self.body.source_info(location); if let Some(lint_root) = self.lint_root(*source_info) { let span = source_info.span; - self.tcx.emit_node_span_lint( - lint_kind.lint(), - lint_root, + self.tcx.emit_node_span_lint(lint_kind.lint(), lint_root, span, AssertLint { span, - AssertLint { span, assert_kind, lint_kind }, - ); + assert_kind, + lint_kind, + }); } } @@ -381,19 +377,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if let (Some(l), Some(r)) = (l, r) && l.layout.ty.is_integral() && op.is_overflowing() - { - if self.use_ecx(|this| { + && self.use_ecx(|this| { let (_res, overflow) = this.ecx.binary_op(op, &l, &r)?.to_scalar_pair(); overflow.to_bool() - })? { - self.report_assert_as_lint( - location, - AssertLintKind::ArithmeticOverflow, - AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), - ); - return None; - } + })? + { + self.report_assert_as_lint( + location, + AssertLintKind::ArithmeticOverflow, + AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), + ); + return None; } + Some(()) } @@ -563,7 +559,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let val = self.use_ecx(|this| this.ecx.binary_op(bin_op, &left, &right))?; if matches!(val.layout.abi, Abi::ScalarPair(..)) { - // FIXME `Value` should properly support pairs in `Immediate`... but currently it does not. + // FIXME `Value` should properly support pairs in `Immediate`... but currently + // it does not. let (val, overflow) = val.to_pair(&self.ecx); Value::Aggregate { variant: VariantIdx::ZERO, @@ -853,7 +850,7 @@ const MAX_ALLOC_LIMIT: u64 = 1024; /// The mode that `ConstProp` is allowed to run in for a given `Local`. #[derive(Clone, Copy, Debug, PartialEq)] -pub enum ConstPropMode { +enum ConstPropMode { /// The `Local` can be propagated into and reads of this `Local` can also be propagated. FullConstProp, /// The `Local` can only be propagated into and from its own block. @@ -865,7 +862,7 @@ pub enum ConstPropMode { /// A visitor that determines locals in a MIR body /// that can be const propagated -pub struct CanConstProp { +struct CanConstProp { can_const_prop: IndexVec, // False at the beginning. Once set, no more assignments are allowed to that local. found_assignment: BitSet, @@ -873,7 +870,7 @@ pub struct CanConstProp { impl CanConstProp { /// Returns true if `local` can be propagated - pub fn check<'tcx>( + fn check<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, body: &Body<'tcx>, @@ -914,7 +911,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) { use rustc_middle::mir::visit::PlaceContext::*; - // Dereferencing just read the addess of `place.local`. + // Dereferencing just read the address of `place.local`. if place.projection.first() == Some(&PlaceElem::Deref) { context = NonMutatingUse(NonMutatingUseContext::Copy); } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index cbc3169f2f10a..3e263aa406774 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -16,28 +16,190 @@ use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants}; /// Large([u32; 1024]), /// } /// ``` -/// Instead of emitting moves of the large variant, -/// Perform a memcpy instead. +/// Instead of emitting moves of the large variant, perform a memcpy instead. /// Based off of [this HackMD](https://hackmd.io/@ft4bxUsFT5CEUBmRKYHr7w/rJM8BBPzD). /// /// In summary, what this does is at runtime determine which enum variant is active, /// and instead of copying all the bytes of the largest possible variant, /// copy only the bytes for the currently active variant. -pub struct EnumSizeOpt { +pub(super) struct EnumSizeOpt { pub(crate) discrepancy: u64, } -impl<'tcx> MirPass<'tcx> for EnumSizeOpt { +impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { fn is_enabled(&self, sess: &Session) -> bool { // There are some differences in behavior on wasm and ARM that are not properly // understood, so we conservatively treat this optimization as unsound: // https://github.com/rust-lang/rust/pull/85158#issuecomment-1101836457 sess.opts.unstable_opts.unsound_mir_opts || sess.mir_opt_level() >= 3 } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // NOTE: This pass may produce different MIR based on the alignment of the target // platform, but it will still be valid. - self.optim(tcx, body); + + let mut alloc_cache = FxHashMap::default(); + let body_did = body.source.def_id(); + let param_env = tcx.param_env_reveal_all_normalized(body_did); + + let blocks = body.basic_blocks.as_mut(); + let local_decls = &mut body.local_decls; + + for bb in blocks { + bb.expand_statements(|st| { + let StatementKind::Assign(box ( + lhs, + Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), + )) = &st.kind + else { + return None; + }; + + let ty = lhs.ty(local_decls, tcx).ty; + + let (adt_def, num_variants, alloc_id) = + self.candidate(tcx, param_env, ty, &mut alloc_cache)?; + + let source_info = st.source_info; + let span = source_info.span; + + let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64); + let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span)); + let store_live = + Statement { source_info, kind: StatementKind::StorageLive(size_array_local) }; + + let place = Place::from(size_array_local); + let constant_vals = ConstOperand { + span, + user_ty: None, + const_: Const::Val( + ConstValue::Indirect { alloc_id, offset: Size::ZERO }, + tmp_ty, + ), + }; + let rval = Rvalue::Use(Operand::Constant(Box::new(constant_vals))); + let const_assign = + Statement { source_info, kind: StatementKind::Assign(Box::new((place, rval))) }; + + let discr_place = Place::from( + local_decls.push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)), + ); + let store_discr = Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + discr_place, + Rvalue::Discriminant(*rhs), + ))), + }; + + let discr_cast_place = + Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span))); + let cast_discr = Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + discr_cast_place, + Rvalue::Cast( + CastKind::IntToInt, + Operand::Copy(discr_place), + tcx.types.usize, + ), + ))), + }; + + let size_place = + Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span))); + let store_size = Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + size_place, + Rvalue::Use(Operand::Copy(Place { + local: size_array_local, + projection: tcx + .mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]), + })), + ))), + }; + + let dst = + Place::from(local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span))); + let dst_ptr = Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + dst, + Rvalue::RawPtr(Mutability::Mut, *lhs), + ))), + }; + + let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8); + let dst_cast_place = + Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span))); + let dst_cast = Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + dst_cast_place, + Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty), + ))), + }; + + let src = + Place::from(local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span))); + let src_ptr = Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + src, + Rvalue::RawPtr(Mutability::Not, *rhs), + ))), + }; + + let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8); + let src_cast_place = + Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span))); + let src_cast = Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + src_cast_place, + Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty), + ))), + }; + + let deinit_old = + Statement { source_info, kind: StatementKind::Deinit(Box::new(dst)) }; + + let copy_bytes = Statement { + source_info, + kind: StatementKind::Intrinsic(Box::new( + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src: Operand::Copy(src_cast_place), + dst: Operand::Copy(dst_cast_place), + count: Operand::Copy(size_place), + }), + )), + }; + + let store_dead = + Statement { source_info, kind: StatementKind::StorageDead(size_array_local) }; + + let iter = [ + store_live, + const_assign, + store_discr, + cast_discr, + store_size, + dst_ptr, + dst_cast, + src_ptr, + src_cast, + deinit_old, + copy_bytes, + store_dead, + ] + .into_iter(); + + st.make_nop(); + + Some(iter) + }); + } } } @@ -82,6 +244,8 @@ impl EnumSizeOpt { let ptr_sized_int = data_layout.ptr_sized_integer(); let target_bytes = ptr_sized_int.size().bytes() as usize; let mut data = vec![0; target_bytes * num_discrs]; + + // We use a macro because `$bytes` can be u32 or u64. macro_rules! encode_store { ($curr_idx: expr, $endian: expr, $bytes: expr) => { let bytes = match $endian { @@ -116,184 +280,4 @@ impl EnumSizeOpt { let alloc = tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc)); Some((*adt_def, num_discrs, *alloc_cache.entry(ty).or_insert(alloc))) } - fn optim<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mut alloc_cache = FxHashMap::default(); - let body_did = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(body_did); - - let blocks = body.basic_blocks.as_mut(); - let local_decls = &mut body.local_decls; - - for bb in blocks { - bb.expand_statements(|st| { - if let StatementKind::Assign(box ( - lhs, - Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), - )) = &st.kind - { - let ty = lhs.ty(local_decls, tcx).ty; - - let source_info = st.source_info; - let span = source_info.span; - - let (adt_def, num_variants, alloc_id) = - self.candidate(tcx, param_env, ty, &mut alloc_cache)?; - - let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64); - - let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span)); - let store_live = Statement { - source_info, - kind: StatementKind::StorageLive(size_array_local), - }; - - let place = Place::from(size_array_local); - let constant_vals = ConstOperand { - span, - user_ty: None, - const_: Const::Val( - ConstValue::Indirect { alloc_id, offset: Size::ZERO }, - tmp_ty, - ), - }; - let rval = Rvalue::Use(Operand::Constant(Box::new(constant_vals))); - - let const_assign = Statement { - source_info, - kind: StatementKind::Assign(Box::new((place, rval))), - }; - - let discr_place = Place::from( - local_decls - .push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)), - ); - - let store_discr = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - discr_place, - Rvalue::Discriminant(*rhs), - ))), - }; - - let discr_cast_place = - Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span))); - - let cast_discr = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - discr_cast_place, - Rvalue::Cast( - CastKind::IntToInt, - Operand::Copy(discr_place), - tcx.types.usize, - ), - ))), - }; - - let size_place = - Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span))); - - let store_size = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - size_place, - Rvalue::Use(Operand::Copy(Place { - local: size_array_local, - projection: tcx - .mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]), - })), - ))), - }; - - let dst = Place::from( - local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span)), - ); - - let dst_ptr = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - dst, - Rvalue::RawPtr(Mutability::Mut, *lhs), - ))), - }; - - let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8); - let dst_cast_place = - Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span))); - - let dst_cast = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - dst_cast_place, - Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty), - ))), - }; - - let src = Place::from( - local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span)), - ); - - let src_ptr = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - src, - Rvalue::RawPtr(Mutability::Not, *rhs), - ))), - }; - - let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8); - let src_cast_place = - Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span))); - - let src_cast = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - src_cast_place, - Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty), - ))), - }; - - let deinit_old = - Statement { source_info, kind: StatementKind::Deinit(Box::new(dst)) }; - - let copy_bytes = Statement { - source_info, - kind: StatementKind::Intrinsic(Box::new( - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - src: Operand::Copy(src_cast_place), - dst: Operand::Copy(dst_cast_place), - count: Operand::Copy(size_place), - }), - )), - }; - - let store_dead = Statement { - source_info, - kind: StatementKind::StorageDead(size_array_local), - }; - let iter = [ - store_live, - const_assign, - store_discr, - cast_discr, - store_size, - dst_ptr, - dst_cast, - src_ptr, - src_cast, - deinit_old, - copy_bytes, - store_dead, - ] - .into_iter(); - - st.make_nop(); - Some(iter) - } else { - None - } - }); - } - } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 7a531977267e8..4c090665992bd 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -3,45 +3,45 @@ #![feature(box_patterns)] #![feature(const_type_name)] #![feature(cow_is_borrowed)] -#![feature(decl_macro)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(never_type)] -#![feature(option_get_or_insert_default)] #![feature(round_char_boundary)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![warn(unreachable_pub)] // tidy-alphabetical-end use hir::ConstContext; use required_consts::RequiredConstsVisitor; +use rustc_const_eval::check_consts::{self, ConstCx}; use rustc_const_eval::util; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::steal::Steal; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, Visitor}; use rustc_index::IndexVec; use rustc_middle::mir::{ AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl, - MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, - Statement, StatementKind, TerminatorKind, START_BLOCK, + MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, START_BLOCK, + SourceInfo, Statement, StatementKind, TerminatorKind, }; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::util::Providers; use rustc_middle::{bug, query, span_bug}; use rustc_span::source_map::Spanned; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{DUMMY_SP, sym}; use rustc_trait_selection::traits; use tracing::{debug, trace}; #[macro_use] mod pass_manager; -use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel}; +use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel}; mod abort_unwinding_calls; mod add_call_guards; @@ -73,6 +73,8 @@ mod errors; mod ffi_unwind_calls; mod function_item_references; mod gvn; +// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden +// by custom rustc drivers, running all the steps by themselves. See #114628. pub mod inline; mod instsimplify; mod jump_threading; @@ -85,6 +87,7 @@ mod match_branches; mod mentioned_items; mod multiple_return_terminators; mod nrvo; +mod post_drop_elaboration; mod prettify; mod promote_consts; mod ref_prop; @@ -96,6 +99,7 @@ mod remove_unneeded_drops; mod remove_zsts; mod required_consts; mod reveal_all; +mod sanity_check; mod shim; mod ssa; // This pass is public to allow external drivers to perform MIR cleanup @@ -108,9 +112,6 @@ mod unreachable_enum_branching; mod unreachable_prop; mod validate; -use rustc_const_eval::check_consts::{self, ConstCx}; -use rustc_mir_dataflow::rustc_peek; - rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { @@ -128,7 +129,7 @@ pub fn provide(providers: &mut Providers) { mir_coroutine_witnesses: coroutine::mir_coroutine_witnesses, optimized_mir, is_mir_available, - is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did), + is_ctfe_mir_available: is_mir_available, mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable, mir_inliner_callees: inline::cycle::mir_inliner_callees, promoted_mir, @@ -168,8 +169,9 @@ fn remap_mir_for_const_eval_select<'tcx>( let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args.node { Operand::Constant(_) => { - // there is no good way of extracting a tuple arg from a constant (const generic stuff) - // so we just create a temporary and deconstruct that. + // There is no good way of extracting a tuple arg from a constant + // (const generic stuff) so we just create a temporary and deconstruct + // that. let local = body.local_decls.push(LocalDecl::new(ty, fn_span)); bb.statements.push(Statement { source_info: SourceInfo::outermost(fn_span), @@ -221,25 +223,30 @@ fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// Finds the full set of `DefId`s within the current crate that have /// MIR associated with them. fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { - let mut set = FxIndexSet::default(); - // All body-owners have MIR associated with them. - set.extend(tcx.hir().body_owners()); + let mut set: FxIndexSet<_> = tcx.hir().body_owners().collect(); - // Additionally, tuple struct/variant constructors have MIR, but - // they don't have a BodyId, so we need to build them separately. - struct GatherCtors<'a> { - set: &'a mut FxIndexSet, + // Coroutine-closures (e.g. async closures) have an additional by-move MIR + // body that isn't in the HIR. + for body_owner in tcx.hir().body_owners() { + if let DefKind::Closure = tcx.def_kind(body_owner) + && tcx.needs_coroutine_by_move_body_def_id(body_owner.to_def_id()) + { + set.insert(tcx.coroutine_by_move_body_def_id(body_owner).expect_local()); + } } - impl<'tcx> Visitor<'tcx> for GatherCtors<'_> { - fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) { - if let hir::VariantData::Tuple(_, _, def_id) = *v { - self.set.insert(def_id); + + // tuple struct/variant constructors have MIR, but they don't have a BodyId, + // so we need to build them separately. + for item in tcx.hir_crate_items(()).free_items() { + if let DefKind::Struct | DefKind::Enum = tcx.def_kind(item.owner_id) { + for variant in tcx.adt_def(item.owner_id).variants() { + if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { + set.insert(ctor_def_id.expect_local()); + } } - intravisit::walk_struct_def(self, v) } } - tcx.hir().visit_all_item_likes_in_crate(&mut GatherCtors { set: &mut set }); set } @@ -249,8 +256,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { // No need to const-check a non-const `fn`. match const_kind { - Some(ConstContext::Const { .. } | ConstContext::Static(_)) - | Some(ConstContext::ConstFn) => {} + Some(ConstContext::Const { .. } | ConstContext::Static(_) | ConstContext::ConstFn) => {} None => span_bug!( tcx.def_span(def), "`mir_const_qualif` should only be called on const fns and const items" @@ -294,7 +300,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &Lint(function_item_references::FunctionItemReferences), // What we need to do constant evaluation. &simplify::SimplifyCfg::Initial, - &rustc_peek::SanityCheck, // Just a lint + &Lint(sanity_check::SanityCheck), ], None, ); @@ -329,7 +335,7 @@ fn mir_promoted( tcx.ensure_with_value().has_ffi_unwind_calls(def); // the `by_move_body` query uses the raw mir, so make sure it is run. - if tcx.needs_coroutine_by_move_body_def_id(def) { + if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) { tcx.ensure_with_value().coroutine_by_move_body_def_id(def); } @@ -465,8 +471,8 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & tcx.alloc_steal_mir(body) } -// Made public such that `mir_drops_elaborated_and_const_checked` can be overridden -// by custom rustc drivers, running all the steps by themselves. +// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden +// by custom rustc drivers, running all the steps by themselves. See #114628. pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { assert!(body.phase == MirPhase::Analysis(AnalysisPhase::Initial)); let did = body.source.def_id(); @@ -480,10 +486,13 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' pm::run_passes( tcx, body, - &[&remove_uninit_drops::RemoveUninitDrops, &simplify::SimplifyCfg::RemoveFalseEdges], + &[ + &remove_uninit_drops::RemoveUninitDrops, + &simplify::SimplifyCfg::RemoveFalseEdges, + &Lint(post_drop_elaboration::CheckLiveDrops), + ], None, ); - check_consts::post_drop_elaboration::check_live_drops(tcx, body); // FIXME: make this a MIR lint } debug!("runtime_mir_lowering({:?})", did); @@ -512,10 +521,12 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { /// Returns the sequence of passes that lowers analysis to runtime MIR. fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let passes: &[&dyn MirPass<'tcx>] = &[ - // These next passes must be executed together + // These next passes must be executed together. &add_call_guards::CriticalCallEdges, - &reveal_all::RevealAll, // has to be done before drop elaboration, since we need to drop opaque types, too. - &add_subtyping_projections::Subtyper, // calling this after reveal_all ensures that we don't deal with opaque types + // Must be done before drop elaboration because we need to drop opaque types, too. + &reveal_all::RevealAll, + // Calling this after reveal_all ensures that we don't deal with opaque types. + &add_subtyping_projections::Subtyper, &elaborate_drops::ElaborateDrops, // This will remove extraneous landing pads which are no longer // necessary as well as forcing any call in a non-unwinding @@ -524,8 +535,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // AddMovesForPackedDrops needs to run after drop // elaboration. &add_moves_for_packed_drops::AddMovesForPackedDrops, - // `AddRetag` needs to run after `ElaborateDrops` but before `ElaborateBoxDerefs`. Otherwise it should run fairly late, - // but before optimizations begin. + // `AddRetag` needs to run after `ElaborateDrops` but before `ElaborateBoxDerefs`. + // Otherwise it should run fairly late, but before optimizations begin. &add_retag::AddRetag, &elaborate_box_derefs::ElaborateBoxDerefs, &coroutine::StateTransform, @@ -566,13 +577,15 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Before inlining: trim down MIR with passes to reduce inlining work. // Has to be done before inlining, otherwise actual call will be almost always inlined. - // Also simple, so can just do first + // Also simple, so can just do first. &lower_slice_len::LowerSliceLenCalls, - // Perform instsimplify before inline to eliminate some trivial calls (like clone shims). + // Perform instsimplify before inline to eliminate some trivial calls (like clone + // shims). &instsimplify::InstSimplify::BeforeInline, // Perform inlining, which may add a lot of code. &inline::Inline, - // Code from other crates may have storage markers, so this needs to happen after inlining. + // Code from other crates may have storage markers, so this needs to happen after + // inlining. &remove_storage_markers::RemoveStorageMarkers, // Inlining and instantiation may introduce ZST and useless drops. &remove_zsts::RemoveZsts, @@ -589,7 +602,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &multiple_return_terminators::MultipleReturnTerminators, - // After simplifycfg, it allows us to discover new opportunities for peephole optimizations. + // After simplifycfg, it allows us to discover new opportunities for peephole + // optimizations. &instsimplify::InstSimplify::AfterSimplifyCfg, &simplify::SimplifyLocals::BeforeConstProp, &dead_store_elimination::DeadStoreElimination::Initial, diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 746068064b8fb..23733994a8b4a 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -13,7 +13,7 @@ use rustc_mir_dataflow::impls::{MaybeStorageDead, MaybeStorageLive}; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; -pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { +pub(super) fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { let always_live_locals = &always_storage_live_locals(body); let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index a9bdff95fe5ac..6d635606687a9 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -7,9 +7,9 @@ use rustc_span::symbol::sym; use crate::take_array; -pub struct LowerIntrinsics; +pub(super) struct LowerIntrinsics; -impl<'tcx> MirPass<'tcx> for LowerIntrinsics { +impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let local_decls = &body.local_decls; for block in body.basic_blocks.as_mut() { @@ -35,20 +35,19 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } sym::forget => { - if let Some(target) = *target { - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - *destination, - Rvalue::Use(Operand::Constant(Box::new(ConstOperand { - span: terminator.source_info.span, - user_ty: None, - const_: Const::zero_sized(tcx.types.unit), - }))), - ))), - }); - terminator.kind = TerminatorKind::Goto { target }; - } + let target = target.unwrap(); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { + span: terminator.source_info.span, + user_ty: None, + const_: Const::zero_sized(tcx.types.unit), + }))), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; } sym::copy_nonoverlapping => { let target = target.unwrap(); @@ -121,43 +120,41 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { - if let Some(target) = *target { - let Ok([lhs, rhs]) = take_array(args) else { - bug!("Wrong arguments for {} intrinsic", intrinsic.name); - }; - let bin_op = match intrinsic.name { - sym::add_with_overflow => BinOp::AddWithOverflow, - sym::sub_with_overflow => BinOp::SubWithOverflow, - sym::mul_with_overflow => BinOp::MulWithOverflow, - _ => bug!("unexpected intrinsic"), - }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - *destination, - Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))), - ))), - }); - terminator.kind = TerminatorKind::Goto { target }; - } + let target = target.unwrap(); + let Ok([lhs, rhs]) = take_array(args) else { + bug!("Wrong arguments for {} intrinsic", intrinsic.name); + }; + let bin_op = match intrinsic.name { + sym::add_with_overflow => BinOp::AddWithOverflow, + sym::sub_with_overflow => BinOp::SubWithOverflow, + sym::mul_with_overflow => BinOp::MulWithOverflow, + _ => bug!("unexpected intrinsic"), + }; + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; } sym::size_of | sym::min_align_of => { - if let Some(target) = *target { - let tp_ty = generic_args.type_at(0); - let null_op = match intrinsic.name { - sym::size_of => NullOp::SizeOf, - sym::min_align_of => NullOp::AlignOf, - _ => bug!("unexpected intrinsic"), - }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - *destination, - Rvalue::NullaryOp(null_op, tp_ty), - ))), - }); - terminator.kind = TerminatorKind::Goto { target }; - } + let target = target.unwrap(); + let tp_ty = generic_args.type_at(0); + let null_op = match intrinsic.name { + sym::size_of => NullOp::SizeOf, + sym::min_align_of => NullOp::AlignOf, + _ => bug!("unexpected intrinsic"), + }; + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::NullaryOp(null_op, tp_ty), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; } sym::read_via_copy => { let Ok([arg]) = take_array(args) else { @@ -219,17 +216,23 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } sym::discriminant_value => { - if let (Some(target), Some(arg)) = (*target, args[0].node.place()) { - let arg = tcx.mk_place_deref(arg); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - *destination, - Rvalue::Discriminant(arg), - ))), - }); - terminator.kind = TerminatorKind::Goto { target }; - } + let target = target.unwrap(); + let Ok([arg]) = take_array(args) else { + span_bug!( + terminator.source_info.span, + "Wrong arguments for discriminant_value intrinsic" + ); + }; + let arg = arg.node.place().unwrap(); + let arg = tcx.mk_place_deref(arg); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::Discriminant(arg), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; } sym::offset => { let target = target.unwrap(); @@ -267,7 +270,6 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { Rvalue::Cast(CastKind::Transmute, arg.node, dst_ty), ))), }); - if let Some(target) = *target { terminator.kind = TerminatorKind::Goto { target }; } else { @@ -299,7 +301,6 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { Rvalue::Aggregate(Box::new(kind), fields.into()), ))), }); - terminator.kind = TerminatorKind::Goto { target }; } sym::ptr_metadata => { diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 77a7f4f47dd4e..420661f29c8cf 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -5,30 +5,26 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -pub struct LowerSliceLenCalls; +pub(super) struct LowerSliceLenCalls; -impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls { +impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() > 0 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - lower_slice_len_calls(tcx, body) - } -} - -pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let language_items = tcx.lang_items(); - let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else { - // there is no lang item to compare to :) - return; - }; + let language_items = tcx.lang_items(); + let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else { + // there is no lang item to compare to :) + return; + }; - // The one successor remains unchanged, so no need to invalidate - let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); - for block in basic_blocks { - // lower `<[_]>::len` calls - lower_slice_len_call(block, slice_len_fn_item_def_id); + // The one successor remains unchanged, so no need to invalidate + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); + for block in basic_blocks { + // lower `<[_]>::len` calls + lower_slice_len_call(block, slice_len_fn_item_def_id); + } } } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 47758b56f8c90..ad3126f66a67e 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -10,9 +10,9 @@ use rustc_type_ir::TyKind::*; use super::simplify::simplify_cfg; -pub struct MatchBranchSimplification; +pub(super) struct MatchBranchSimplification; -impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { +impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 1 } @@ -57,8 +57,9 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } trait SimplifyMatch<'tcx> { - /// Simplifies a match statement, returning true if the simplification succeeds, false otherwise. - /// Generic code is written here, and we generally don't need a custom implementation. + /// Simplifies a match statement, returning true if the simplification succeeds, false + /// otherwise. Generic code is written here, and we generally don't need a custom + /// implementation. fn simplify( &mut self, tcx: TyCtxt<'tcx>, @@ -240,7 +241,8 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { // Same value in both blocks. Use statement as is. patch.add_statement(parent_end, f.kind.clone()); } else { - // Different value between blocks. Make value conditional on switch condition. + // Different value between blocks. Make value conditional on switch + // condition. let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; let const_cmp = Operand::const_from_scalar( tcx, @@ -289,11 +291,11 @@ fn can_cast( #[derive(Default)] struct SimplifyToExp { - transfrom_kinds: Vec, + transform_kinds: Vec, } #[derive(Clone, Copy)] -enum ExpectedTransformKind<'tcx, 'a> { +enum ExpectedTransformKind<'a, 'tcx> { /// Identical statements. Same(&'a StatementKind<'tcx>), /// Assignment statements have the same value. @@ -302,17 +304,17 @@ enum ExpectedTransformKind<'tcx, 'a> { Cast { place: &'a Place<'tcx>, ty: Ty<'tcx> }, } -enum TransfromKind { +enum TransformKind { Same, Cast, } -impl From> for TransfromKind { +impl From> for TransformKind { fn from(compare_type: ExpectedTransformKind<'_, '_>) -> Self { match compare_type { - ExpectedTransformKind::Same(_) => TransfromKind::Same, - ExpectedTransformKind::SameByEq { .. } => TransfromKind::Same, - ExpectedTransformKind::Cast { .. } => TransfromKind::Cast, + ExpectedTransformKind::Same(_) => TransformKind::Same, + ExpectedTransformKind::SameByEq { .. } => TransformKind::Same, + ExpectedTransformKind::Cast { .. } => TransformKind::Cast, } } } @@ -394,14 +396,16 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { return None; } - // We first compare the two branches, and then the other branches need to fulfill the same conditions. + // We first compare the two branches, and then the other branches need to fulfill the same + // conditions. let mut expected_transform_kinds = Vec::new(); for (f, s) in iter::zip(first_stmts, second_stmts) { let compare_type = match (&f.kind, &s.kind) { // If two statements are exactly the same, we can optimize. (f_s, s_s) if f_s == s_s => ExpectedTransformKind::Same(f_s), - // If two statements are assignments with the match values to the same place, we can optimize. + // If two statements are assignments with the match values to the same place, we + // can optimize. ( StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), @@ -475,7 +479,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { } } } - self.transfrom_kinds = expected_transform_kinds.into_iter().map(|c| c.into()).collect(); + self.transform_kinds = expected_transform_kinds.into_iter().map(|c| c.into()).collect(); Some(()) } @@ -493,13 +497,13 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { let (_, first) = targets.iter().next().unwrap(); let first = &bbs[first]; - for (t, s) in iter::zip(&self.transfrom_kinds, &first.statements) { + for (t, s) in iter::zip(&self.transform_kinds, &first.statements) { match (t, &s.kind) { - (TransfromKind::Same, _) => { + (TransformKind::Same, _) => { patch.add_statement(parent_end, s.kind.clone()); } ( - TransfromKind::Cast, + TransformKind::Cast, StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), ) => { let operand = Operand::Copy(Place::from(discr_local)); diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index 32c8064ebca50..cf5c5f85a9ff6 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -1,19 +1,19 @@ use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, Location, MentionedItem, MirPass}; +use rustc_middle::mir::{self, Location, MentionedItem}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::Session; use rustc_span::source_map::Spanned; -pub struct MentionedItems; +pub(super) struct MentionedItems; struct MentionedItemsVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, - mentioned_items: &'a mut Vec>>, + mentioned_items: Vec>>, } -impl<'tcx> MirPass<'tcx> for MentionedItems { +impl<'tcx> crate::MirPass<'tcx> for MentionedItems { fn is_enabled(&self, _sess: &Session) -> bool { // If this pass is skipped the collector assume that nothing got mentioned! We could // potentially skip it in opt-level 0 if we are sure that opt-level will never *remove* uses @@ -23,9 +23,9 @@ impl<'tcx> MirPass<'tcx> for MentionedItems { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { - let mut mentioned_items = Vec::new(); - MentionedItemsVisitor { tcx, body, mentioned_items: &mut mentioned_items }.visit_body(body); - body.set_mentioned_items(mentioned_items); + let mut visitor = MentionedItemsVisitor { tcx, body, mentioned_items: Vec::new() }; + visitor.visit_body(body); + body.set_mentioned_items(visitor.mentioned_items); } } @@ -70,11 +70,11 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { match *rvalue { // We need to detect unsizing casts that required vtables. mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::Unsize), + mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _) + | mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _), ref operand, target_ty, - ) - | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => { + ) => { // This isn't monomorphized yet so we can't tell what the actual types are -- just // add everything that may involve a vtable. let source_ty = operand.ty(self.body, self.tcx); @@ -82,7 +82,9 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { source_ty.builtin_deref(true).map(|t| t.kind()), target_ty.builtin_deref(true).map(|t| t.kind()), ) { - (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, // &str/&[T] unsizing + // &str/&[T] unsizing + (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, + _ => true, }; if may_involve_vtable { @@ -94,7 +96,7 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { } // Similarly, record closures that are turned into function pointers. mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), + mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _), ref operand, _, ) => { @@ -104,7 +106,7 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { } // And finally, function pointer reification casts. mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer), + mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _), ref operand, _, ) => { diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs index 1e87a0e01d9be..b6d6ef5de1da9 100644 --- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs +++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs @@ -7,9 +7,9 @@ use rustc_middle::ty::TyCtxt; use crate::simplify; -pub struct MultipleReturnTerminators; +pub(super) struct MultipleReturnTerminators; -impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { +impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 4 } diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index dd1875f2a78ac..98fa149e2bc71 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -8,8 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location}; use rustc_middle::ty::TyCtxt; use tracing::{debug, trace}; -use crate::MirPass; - /// This pass looks for MIR that always copies the same local into the return place and eliminates /// the copy by renaming all uses of that local to `_0`. /// @@ -32,9 +30,9 @@ use crate::MirPass; /// /// [#47954]: https://github.com/rust-lang/rust/pull/47954 /// [#71003]: https://github.com/rust-lang/rust/pull/71003 -pub struct RenameReturnPlace; +pub(super) struct RenameReturnPlace; -impl<'tcx> MirPass<'tcx> for RenameReturnPlace { +impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { // unsound: #111005 sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 51e2760040478..29f8b4f6e4ddf 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -1,19 +1,99 @@ +use std::cell::RefCell; +use std::collections::hash_map::Entry; + +use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use tracing::trace; use crate::lint::lint_body; -use crate::{validate, MirPass}; +use crate::validate; + +thread_local! { + static PASS_NAMES: RefCell> = { + RefCell::new(FxHashMap::default()) + }; +} + +/// Converts a MIR pass name into a snake case form to match the profiling naming style. +fn to_profiler_name(type_name: &'static str) -> &'static str { + PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + let snake_case: String = type_name + .chars() + .flat_map(|c| { + if c.is_ascii_uppercase() { + vec!['_', c.to_ascii_lowercase()] + } else if c == '-' { + vec!['_'] + } else { + vec![c] + } + }) + .collect(); + let result = &*String::leak(format!("mir_pass{}", snake_case)); + e.insert(result); + result + } + }) +} + +// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }` +const fn c_name(name: &'static str) -> &'static str { + // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. + // and inline into call site + let bytes = name.as_bytes(); + let mut i = bytes.len(); + while i > 0 && bytes[i - 1] != b':' { + i = i - 1; + } + let (_, bytes) = bytes.split_at(i); + match std::str::from_utf8(bytes) { + Ok(name) => name, + Err(_) => name, + } +} + +/// A streamlined trait that you can implement to create a pass; the +/// pass will be named after the type, and it will consist of a main +/// loop that goes over each available MIR and applies `run_pass`. +pub(super) trait MirPass<'tcx> { + fn name(&self) -> &'static str { + // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. + // See copypaste in `MirLint` + const { + let name = std::any::type_name::(); + c_name(name) + } + } + + fn profiler_name(&self) -> &'static str { + to_profiler_name(self.name()) + } + + /// Returns `true` if this pass is enabled with the current combination of compiler flags. + fn is_enabled(&self, _sess: &Session) -> bool { + true + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); -/// Just like `MirPass`, except it cannot mutate `Body`. -pub trait MirLint<'tcx> { + fn is_mir_dump_enabled(&self) -> bool { + true + } +} + +/// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is +/// disabled (via the `Lint` adapter). +pub(super) trait MirLint<'tcx> { fn name(&self) -> &'static str { - // FIXME Simplify the implementation once more `str` methods get const-stable. + // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. // See copypaste in `MirPass` const { let name = std::any::type_name::(); - rustc_middle::util::common::c_name(name) + c_name(name) } } @@ -26,7 +106,7 @@ pub trait MirLint<'tcx> { /// An adapter for `MirLint`s that implements `MirPass`. #[derive(Debug, Clone)] -pub struct Lint(pub T); +pub(super) struct Lint(pub T); impl<'tcx, T> MirPass<'tcx> for Lint where @@ -49,7 +129,7 @@ where } } -pub struct WithMinOptLevel(pub u32, pub T); +pub(super) struct WithMinOptLevel(pub u32, pub T); impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel where @@ -70,7 +150,7 @@ where /// Run the sequence of passes without validating the MIR after each pass. The MIR is still /// validated at the end. -pub fn run_passes_no_validate<'tcx>( +pub(super) fn run_passes_no_validate<'tcx>( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>], @@ -80,7 +160,7 @@ pub fn run_passes_no_validate<'tcx>( } /// The optional `phase_change` is applied after executing all the passes, if present -pub fn run_passes<'tcx>( +pub(super) fn run_passes<'tcx>( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>], @@ -89,7 +169,7 @@ pub fn run_passes<'tcx>( run_passes_inner(tcx, body, passes, phase_change, true); } -pub fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool +pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool where P: MirPass<'tcx> + ?Sized, { @@ -185,16 +265,11 @@ fn run_passes_inner<'tcx>( } } -pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) { +pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) { validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body); } -pub fn dump_mir_for_pass<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - pass_name: &str, - is_after: bool, -) { +fn dump_mir_for_pass<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, pass_name: &str, is_after: bool) { mir::dump_mir( tcx, true, @@ -205,7 +280,7 @@ pub fn dump_mir_for_pass<'tcx>( ); } -pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { +pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { assert_eq!(body.pass_count, 0); mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(())) } diff --git a/compiler/rustc_mir_transform/src/post_drop_elaboration.rs b/compiler/rustc_mir_transform/src/post_drop_elaboration.rs new file mode 100644 index 0000000000000..75721d4607626 --- /dev/null +++ b/compiler/rustc_mir_transform/src/post_drop_elaboration.rs @@ -0,0 +1,13 @@ +use rustc_const_eval::check_consts; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +use crate::MirLint; + +pub(super) struct CheckLiveDrops; + +impl<'tcx> MirLint<'tcx> for CheckLiveDrops { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + check_consts::post_drop_elaboration::check_live_drops(tcx, body); + } +} diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs index 14dd0c6f61e76..937c207776b35 100644 --- a/compiler/rustc_mir_transform/src/prettify.rs +++ b/compiler/rustc_mir_transform/src/prettify.rs @@ -15,9 +15,9 @@ use rustc_session::Session; /// /// Thus after this pass, all the successors of a block are later than it in the /// `IndexVec`, unless that successor is a back-edge (such as from a loop). -pub struct ReorderBasicBlocks; +pub(super) struct ReorderBasicBlocks; -impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks { +impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks { fn is_enabled(&self, _session: &Session) -> bool { false } @@ -43,9 +43,9 @@ impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks { /// assigned or referenced will have a smaller number. /// /// (Does not reorder arguments nor the [`RETURN_PLACE`].) -pub struct ReorderLocals; +pub(super) struct ReorderLocals; -impl<'tcx> MirPass<'tcx> for ReorderLocals { +impl<'tcx> crate::MirPass<'tcx> for ReorderLocals { fn is_enabled(&self, _session: &Session) -> bool { false } @@ -63,7 +63,7 @@ impl<'tcx> MirPass<'tcx> for ReorderLocals { finder.visit_basic_block_data(bb, bbd); } - // track everything in case there are some locals that we never saw, + // Track everything in case there are some locals that we never saw, // such as in non-block things like debug info or in non-uses. for local in body.local_decls.indices() { finder.track(local); @@ -87,7 +87,7 @@ impl<'tcx> MirPass<'tcx> for ReorderLocals { fn permute(data: &mut IndexVec, map: &IndexSlice) { // FIXME: It would be nice to have a less-awkward way to apply permutations, - // but I don't know one that exists. `sort_by_cached_key` has logic for it + // but I don't know one that exists. `sort_by_cached_key` has logic for it // internally, but not in a way that we're allowed to use here. let mut enumerated: Vec<_> = std::mem::take(data).into_iter_enumerated().collect(); enumerated.sort_by_key(|p| map[p.0]); @@ -135,8 +135,8 @@ impl<'tcx> Visitor<'tcx> for LocalFinder { } struct LocalUpdater<'tcx> { - pub map: IndexVec, - pub tcx: TyCtxt<'tcx>, + map: IndexVec, + tcx: TyCtxt<'tcx>, } impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index f2610fd52bc12..d963ca5c48502 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -1,23 +1,21 @@ //! A pass that promotes borrows of constant rvalues. //! -//! The rvalues considered constant are trees of temps, -//! each with exactly one initialization, and holding -//! a constant value with no interior mutability. -//! They are placed into a new MIR constant body in -//! `promoted` and the borrow rvalue is replaced with -//! a `Literal::Promoted` using the index into `promoted` -//! of that constant MIR. +//! The rvalues considered constant are trees of temps, each with exactly one +//! initialization, and holding a constant value with no interior mutability. +//! They are placed into a new MIR constant body in `promoted` and the borrow +//! rvalue is replaced with a `Literal::Promoted` using the index into +//! `promoted` of that constant MIR. //! -//! This pass assumes that every use is dominated by an -//! initialization and can otherwise silence errors, if -//! move analysis runs after promotion on broken MIR. +//! This pass assumes that every use is dominated by an initialization and can +//! otherwise silence errors, if move analysis runs after promotion on broken +//! MIR. use std::assert_matches::assert_matches; use std::cell::Cell; use std::{cmp, iter, mem}; use either::{Left, Right}; -use rustc_const_eval::check_consts::{qualifs, ConstCx}; +use rustc_const_eval::check_consts::{ConstCx, qualifs}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_index::{Idx, IndexSlice, IndexVec}; @@ -25,8 +23,8 @@ use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Vis use rustc_middle::mir::*; use rustc_middle::ty::{self, GenericArgs, List, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, mir, span_bug}; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; use tracing::{debug, instrument}; /// A `MirPass` for promotion. @@ -37,11 +35,12 @@ use tracing::{debug, instrument}; /// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each /// newly created `Constant`. #[derive(Default)] -pub struct PromoteTemps<'tcx> { +pub(super) struct PromoteTemps<'tcx> { + // Must use `Cell` because `run_pass` takes `&self`, not `&mut self`. pub promoted_fragments: Cell>>, } -impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { +impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // There's not really any point in promoting errorful MIR. // @@ -386,7 +385,8 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_ref(&mut self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> { match kind { // Reject these borrow types just to be safe. - // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. + // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a + // usecase. BorrowKind::Fake(_) | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { return Err(Unpromotable); } @@ -468,7 +468,8 @@ impl<'tcx> Validator<'_, 'tcx> { let lhs_ty = lhs.ty(self.body, self.tcx); if let ty::RawPtr(_, _) | ty::FnPtr(..) = lhs_ty.kind() { - // Raw and fn pointer operations are not allowed inside consts and thus not promotable. + // Raw and fn pointer operations are not allowed inside consts and thus not + // promotable. assert_matches!( op, BinOp::Eq @@ -498,7 +499,8 @@ impl<'tcx> Validator<'_, 'tcx> { Some(x) if x != 0 => {} // okay _ => return Err(Unpromotable), // value not known or 0 -- not okay } - // Furthermore, for signed divison, we also have to exclude `int::MIN / -1`. + // Furthermore, for signed division, we also have to exclude `int::MIN / + // -1`. if lhs_ty.is_signed() { match rhs_val.map(|x| x.to_int(sz)) { Some(-1) | None => { @@ -512,8 +514,11 @@ impl<'tcx> Validator<'_, 'tcx> { }; let lhs_min = sz.signed_int_min(); match lhs_val.map(|x| x.to_int(sz)) { - Some(x) if x != lhs_min => {} // okay - _ => return Err(Unpromotable), // value not known or int::MIN -- not okay + // okay + Some(x) if x != lhs_min => {} + + // value not known or int::MIN -- not okay + _ => return Err(Unpromotable), } } _ => {} @@ -815,8 +820,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { TerminatorKind::Call { mut func, mut args, call_source: desugar, fn_span, .. } => { - // This promoted involves a function call, so it may fail to evaluate. - // Let's make sure it is added to `required_consts` so that failure cannot get lost. + // This promoted involves a function call, so it may fail to evaluate. Let's + // make sure it is added to `required_consts` so that failure cannot get lost. self.add_to_required = true; self.visit_operand(&mut func, loc); @@ -907,23 +912,19 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { self.extra_statements.push((loc, promoted_ref_statement)); ( - Rvalue::Ref( - tcx.lifetimes.re_erased, - *borrow_kind, - Place { - local: mem::replace(&mut place.local, promoted_ref), - projection: List::empty(), - }, - ), + Rvalue::Ref(tcx.lifetimes.re_erased, *borrow_kind, Place { + local: mem::replace(&mut place.local, promoted_ref), + projection: List::empty(), + }), promoted_operand, ) }; assert_eq!(self.new_block(), START_BLOCK); - self.visit_rvalue( - &mut rvalue, - Location { block: START_BLOCK, statement_index: usize::MAX }, - ); + self.visit_rvalue(&mut rvalue, Location { + block: START_BLOCK, + statement_index: usize::MAX, + }); let span = self.promoted.span; self.assign(RETURN_PLACE, rvalue, span); diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 2b07c04a12130..a62a892716fbf 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -1,15 +1,15 @@ use std::borrow::Cow; use rustc_data_structures::fx::FxHashSet; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::MaybeStorageDead; use rustc_mir_dataflow::storage::always_storage_live_locals; -use rustc_mir_dataflow::Analysis; use tracing::{debug, instrument}; use crate::ssa::{SsaLocals, StorageLiveLocals}; @@ -70,9 +70,9 @@ use crate::ssa::{SsaLocals, StorageLiveLocals}; /// /// For immutable borrows, we do not need to preserve such uniqueness property, /// so we perform all the possible instantiations without removing the `_1 = &_2` statement. -pub struct ReferencePropagation; +pub(super) struct ReferencePropagation; -impl<'tcx> MirPass<'tcx> for ReferencePropagation { +impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 2 } @@ -253,11 +253,8 @@ fn compute_replacement<'tcx>( debug!(?targets); - let mut finder = ReplacementFinder { - targets: &mut targets, - can_perform_opt, - allowed_replacements: FxHashSet::default(), - }; + let mut finder = + ReplacementFinder { targets, can_perform_opt, allowed_replacements: FxHashSet::default() }; let reachable_blocks = traversal::reachable_as_bitset(body); for (bb, bbdata) in body.basic_blocks.iter_enumerated() { // Only visit reachable blocks as we rely on dataflow. @@ -269,19 +266,19 @@ fn compute_replacement<'tcx>( let allowed_replacements = finder.allowed_replacements; return Replacer { tcx, - targets, + targets: finder.targets, storage_to_remove, allowed_replacements, any_replacement: false, }; - struct ReplacementFinder<'a, 'tcx, F> { - targets: &'a mut IndexVec>, + struct ReplacementFinder<'tcx, F> { + targets: IndexVec>, can_perform_opt: F, allowed_replacements: FxHashSet<(Local, Location)>, } - impl<'tcx, F> Visitor<'tcx> for ReplacementFinder<'_, 'tcx, F> + impl<'tcx, F> Visitor<'tcx> for ReplacementFinder<'tcx, F> where F: FnMut(Place<'tcx>, Location) -> bool, { @@ -345,7 +342,7 @@ fn fully_replacable_locals(ssa: &SsaLocals) -> BitSet { replacable } -/// Utility to help performing subtitution of `*pattern` by `target`. +/// Utility to help performing substitution of `*pattern` by `target`. struct Replacer<'tcx> { tcx: TyCtxt<'tcx>, targets: IndexVec>, diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 33c7d1695c02d..55394e93a5cb7 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -8,9 +8,9 @@ use tracing::debug; /// A pass that removes noop landing pads and replaces jumps to them with /// `UnwindAction::Continue`. This is important because otherwise LLVM generates /// terrible code for these. -pub struct RemoveNoopLandingPads; +pub(super) struct RemoveNoopLandingPads; -impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { +impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.panic_strategy() != PanicStrategy::Abort } @@ -18,7 +18,61 @@ impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let def_id = body.source.def_id(); debug!(?def_id); - self.remove_nop_landing_pads(body) + + // Skip the pass if there are no blocks with a resume terminator. + let has_resume = body + .basic_blocks + .iter_enumerated() + .any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::UnwindResume)); + if !has_resume { + debug!("remove_noop_landing_pads: no resume block in MIR"); + return; + } + + // make sure there's a resume block without any statements + let resume_block = { + let mut patch = MirPatch::new(body); + let resume_block = patch.resume_block(); + patch.apply(body); + resume_block + }; + debug!("remove_noop_landing_pads: resume block is {:?}", resume_block); + + let mut jumps_folded = 0; + let mut landing_pads_removed = 0; + let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks.len()); + + // This is a post-order traversal, so that if A post-dominates B + // then A will be visited before B. + let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); + for bb in postorder { + debug!(" processing {:?}", bb); + if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { + if let UnwindAction::Cleanup(unwind_bb) = *unwind { + if nop_landing_pads.contains(unwind_bb) { + debug!(" removing noop landing pad"); + landing_pads_removed += 1; + *unwind = UnwindAction::Continue; + } + } + } + + for target in body[bb].terminator_mut().successors_mut() { + if *target != resume_block && nop_landing_pads.contains(*target) { + debug!(" folding noop jump to {:?} to resume block", target); + *target = resume_block; + jumps_folded += 1; + } + } + + let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); + if is_nop_landing_pad { + nop_landing_pads.insert(bb); + } + debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad); + } + + debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed); } } @@ -82,61 +136,4 @@ impl RemoveNoopLandingPads { | TerminatorKind::InlineAsm { .. } => false, } } - - fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { - // Skip the pass if there are no blocks with a resume terminator. - let has_resume = body - .basic_blocks - .iter_enumerated() - .any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::UnwindResume)); - if !has_resume { - debug!("remove_noop_landing_pads: no resume block in MIR"); - return; - } - - // make sure there's a resume block without any statements - let resume_block = { - let mut patch = MirPatch::new(body); - let resume_block = patch.resume_block(); - patch.apply(body); - resume_block - }; - debug!("remove_noop_landing_pads: resume block is {:?}", resume_block); - - let mut jumps_folded = 0; - let mut landing_pads_removed = 0; - let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks.len()); - - // This is a post-order traversal, so that if A post-dominates B - // then A will be visited before B. - let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); - for bb in postorder { - debug!(" processing {:?}", bb); - if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { - if let UnwindAction::Cleanup(unwind_bb) = *unwind { - if nop_landing_pads.contains(unwind_bb) { - debug!(" removing noop landing pad"); - landing_pads_removed += 1; - *unwind = UnwindAction::Continue; - } - } - } - - for target in body[bb].terminator_mut().successors_mut() { - if *target != resume_block && nop_landing_pads.contains(*target) { - debug!(" folding noop jump to {:?} to resume block", target); - *target = resume_block; - jumps_folded += 1; - } - } - - let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); - if is_nop_landing_pad { - nop_landing_pads.insert(bb); - } - debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad); - } - - debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed); - } } diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs index 6c0b50fafdb40..71399eb72f004 100644 --- a/compiler/rustc_mir_transform/src/remove_place_mention.rs +++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs @@ -4,9 +4,9 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use tracing::trace; -pub struct RemovePlaceMention; +pub(super) struct RemovePlaceMention; -impl<'tcx> MirPass<'tcx> for RemovePlaceMention { +impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { !sess.opts.unstable_opts.mir_keep_place_mention } diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs index af89395dddd2d..3ecb4a8994f5f 100644 --- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs +++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs @@ -4,9 +4,9 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use tracing::trace; -pub struct RemoveStorageMarkers; +pub(super) struct RemoveStorageMarkers; -impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers { +impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() > 0 && !sess.emit_lifetime_markers() } diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index fae1cb5f7d8a5..e6647edf3f50d 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -3,11 +3,9 @@ use rustc_middle::mir::{Body, TerminatorKind}; use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, VariantDef}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; -use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable}; +use rustc_mir_dataflow::{Analysis, MaybeReachable, move_path_children_matching}; use rustc_target::abi::FieldIdx; -use crate::MirPass; - /// Removes `Drop` terminators whose target is known to be uninitialized at /// that point. /// @@ -16,9 +14,9 @@ use crate::MirPass; /// like [#90770]. /// /// [#90770]: https://github.com/rust-lang/rust/issues/90770 -pub struct RemoveUninitDrops; +pub(super) struct RemoveUninitDrops; -impl<'tcx> MirPass<'tcx> for RemoveUninitDrops { +impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let param_env = tcx.param_env(body.source.def_id()); let move_data = @@ -108,8 +106,9 @@ fn is_needs_drop_and_init<'tcx>( // If its projection *is* present in `MoveData`, then the field may have been moved // from separate from its parent. Recurse. adt.variants().iter_enumerated().any(|(vid, variant)| { - // Enums have multiple variants, which are discriminated with a `Downcast` projection. - // Structs have a single variant, and don't use a `Downcast` projection. + // Enums have multiple variants, which are discriminated with a `Downcast` + // projection. Structs have a single variant, and don't use a `Downcast` + // projection. let mpi = if adt.is_enum() { let downcast = move_path_children_matching(move_data, mpi, |x| x.is_downcast_to(vid)); diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 9adcb5a38fd8b..28925ba1beb13 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -10,9 +10,9 @@ use tracing::{debug, trace}; use super::simplify::simplify_cfg; -pub struct RemoveUnneededDrops; +pub(super) struct RemoveUnneededDrops; -impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { +impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running RemoveUnneededDrops on {:?}", body.source); diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 9a94cae338288..f13bb1c5993d5 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -4,9 +4,9 @@ use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; -pub struct RemoveZsts; +pub(super) struct RemoveZsts; -impl<'tcx> MirPass<'tcx> for RemoveZsts { +impl<'tcx> crate::MirPass<'tcx> for RemoveZsts { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() > 0 } diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index 50637e2ac03bb..b418ede42f06f 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -1,26 +1,21 @@ use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{traversal, Body, ConstOperand, Location}; +use rustc_middle::mir::{Body, ConstOperand, Location, traversal}; -pub struct RequiredConstsVisitor<'a, 'tcx> { - required_consts: &'a mut Vec>, +pub(super) struct RequiredConstsVisitor<'tcx> { + required_consts: Vec>, } -impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { - fn new(required_consts: &'a mut Vec>) -> Self { - RequiredConstsVisitor { required_consts } - } - - pub fn compute_required_consts(body: &mut Body<'tcx>) { - let mut required_consts = Vec::new(); - let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts); +impl<'tcx> RequiredConstsVisitor<'tcx> { + pub(super) fn compute_required_consts(body: &mut Body<'tcx>) { + let mut visitor = RequiredConstsVisitor { required_consts: Vec::new() }; for (bb, bb_data) in traversal::reverse_postorder(&body) { - required_consts_visitor.visit_basic_block_data(bb, bb_data); + visitor.visit_basic_block_data(bb, bb_data); } - body.set_required_consts(required_consts); + body.set_required_consts(visitor.required_consts); } } -impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { +impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'tcx> { fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, _: Location) { if constant.const_.is_required_const() { self.required_consts.push(*constant); diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 5eaa024f84689..f3b2f78b31c3a 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -4,9 +4,9 @@ use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; -pub struct RevealAll; +pub(super) struct RevealAll; -impl<'tcx> MirPass<'tcx> for RevealAll { +impl<'tcx> crate::MirPass<'tcx> for RevealAll { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body); @@ -35,9 +35,9 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { if place.projection.iter().all(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) { return; } - // `OpaqueCast` projections are only needed if there are opaque types on which projections are performed. - // After the `RevealAll` pass, all opaque types are replaced with their hidden types, so we don't need these - // projections anymore. + // `OpaqueCast` projections are only needed if there are opaque types on which projections + // are performed. After the `RevealAll` pass, all opaque types are replaced with their + // hidden types, so we don't need these projections anymore. place.projection = self.tcx.mk_place_elems( &place .projection diff --git a/compiler/rustc_mir_transform/src/sanity_check.rs b/compiler/rustc_mir_transform/src/sanity_check.rs new file mode 100644 index 0000000000000..c9445d1816295 --- /dev/null +++ b/compiler/rustc_mir_transform/src/sanity_check.rs @@ -0,0 +1,11 @@ +use rustc_middle::mir::Body; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::rustc_peek::sanity_check; + +pub(super) struct SanityCheck; + +impl<'tcx> crate::MirLint<'tcx> for SanityCheck { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + sanity_check(tcx, body); + } +} diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 8c70e4291185d..e872878a751ed 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -14,8 +14,8 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle}; use rustc_span::source_map::Spanned; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; +use rustc_span::{DUMMY_SP, Span}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_target::spec::abi::Abi; use tracing::{debug, instrument}; @@ -26,7 +26,7 @@ use crate::{ mod async_destructor_ctor; -pub fn provide(providers: &mut Providers) { +pub(super) fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } @@ -331,7 +331,7 @@ fn new_body<'tcx>( body } -pub struct DropShimElaborator<'a, 'tcx> { +pub(super) struct DropShimElaborator<'a, 'tcx> { pub body: &'a Body<'tcx>, pub patch: MirPatch<'tcx>, pub tcx: TyCtxt<'tcx>, @@ -404,8 +404,7 @@ fn build_thread_local_shim<'tcx>( let span = tcx.def_span(def_id); let source_info = SourceInfo::outermost(span); - let mut blocks = IndexVec::with_capacity(1); - blocks.push(BasicBlockData { + let blocks = IndexVec::from_raw(vec![BasicBlockData { statements: vec![Statement { source_info, kind: StatementKind::Assign(Box::new(( @@ -415,7 +414,7 @@ fn build_thread_local_shim<'tcx>( }], terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), is_cleanup: false, - }); + }]); new_body( MirSource::from_instance(instance), @@ -913,7 +912,7 @@ fn build_call_shim<'tcx>( body } -pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { +pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { debug_assert!(tcx.is_constructor(ctor_id)); let param_env = tcx.param_env_reveal_all_normalized(ctor_id); @@ -1003,7 +1002,8 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t let locals = local_decls_for_sig(&sig, span); let source_info = SourceInfo::outermost(span); - // FIXME: use `expose_provenance` once we figure out whether function pointers have meaningful provenance. + // FIXME: use `expose_provenance` once we figure out whether function pointers have meaningful + // provenance. let rvalue = Rvalue::Cast( CastKind::FnPtrToPtr, Operand::Move(Place::from(Local::new(1))), @@ -1070,19 +1070,26 @@ fn build_construct_coroutine_by_move_shim<'tcx>( let locals = local_decls_for_sig(&sig, span); let mut fields = vec![]; + + // Move all of the closure args. for idx in 1..sig.inputs().len() { fields.push(Operand::Move(Local::from_usize(idx + 1).into())); } + for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() { if receiver_by_ref { // The only situation where it's possible is when we capture immuatable references, // since those don't need to be reborrowed with the closure's env lifetime. Since // references are always `Copy`, just emit a copy. - assert_matches!( - ty.kind(), - ty::Ref(_, _, hir::Mutability::Not), - "field should be captured by immutable ref if we have an `Fn` instance" - ); + if !matches!(ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) { + // This copy is only sound if it's a `&T`. This may be + // reachable e.g. when eagerly computing the `Fn` instance + // of an async closure that doesn't borrowck. + tcx.dcx().delayed_bug(format!( + "field should be captured by immutable ref if we have \ + an `Fn` instance, but it was: {ty}" + )); + } fields.push(Operand::Copy(tcx.mk_place_field( self_local, FieldIdx::from_usize(idx), diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index 50810f23113f3..71723f040b3b6 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -7,9 +7,10 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Body, CallSource, CastKind, Const, ConstOperand, ConstValue, Local, - LocalDecl, MirSource, Operand, Place, PlaceElem, Rvalue, SourceInfo, Statement, StatementKind, - Terminator, TerminatorKind, UnwindAction, UnwindTerminateReason, RETURN_PLACE, + BasicBlock, BasicBlockData, Body, CallSource, CastKind, CoercionSource, Const, ConstOperand, + ConstValue, Local, LocalDecl, MirSource, Operand, Place, PlaceElem, RETURN_PLACE, Rvalue, + SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnwindAction, + UnwindTerminateReason, }; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::util::{AsyncDropGlueMorphology, Discr}; @@ -23,7 +24,7 @@ use tracing::debug; use super::{local_decls_for_sig, new_body}; -pub fn build_async_destructor_ctor_shim<'tcx>( +pub(super) fn build_async_destructor_ctor_shim<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>, @@ -329,7 +330,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { fn put_array_as_slice(&mut self, elem_ty: Ty<'tcx>) { let slice_ptr_ty = Ty::new_mut_ptr(self.tcx, Ty::new_slice(self.tcx, elem_ty)); self.put_temp_rvalue(Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize), + CastKind::PointerCoercion(PointerCoercion::Unsize, CoercionSource::Implicit), Operand::Copy(Self::SELF_PTR.into()), slice_ptr_ty, )) @@ -452,19 +453,17 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { } fn combine_sync_surface(&mut self) -> Ty<'tcx> { - self.apply_combinator( - 1, - LangItem::AsyncDropSurfaceDropInPlace, - &[self.self_ty.unwrap().into()], - ) + self.apply_combinator(1, LangItem::AsyncDropSurfaceDropInPlace, &[self + .self_ty + .unwrap() + .into()]) } fn combine_deferred_drop_in_place(&mut self) -> Ty<'tcx> { - self.apply_combinator( - 1, - LangItem::AsyncDropDeferredDropInPlace, - &[self.self_ty.unwrap().into()], - ) + self.apply_combinator(1, LangItem::AsyncDropDeferredDropInPlace, &[self + .self_ty + .unwrap() + .into()]) } fn combine_fuse(&mut self, inner_future_ty: Ty<'tcx>) -> Ty<'tcx> { @@ -484,11 +483,11 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { } fn combine_either(&mut self, other: Ty<'tcx>, matched: Ty<'tcx>) -> Ty<'tcx> { - self.apply_combinator( - 4, - LangItem::AsyncDropEither, - &[other.into(), matched.into(), self.self_ty.unwrap().into()], - ) + self.apply_combinator(4, LangItem::AsyncDropEither, &[ + other.into(), + matched.into(), + self.self_ty.unwrap().into(), + ]) } fn return_(mut self) -> Body<'tcx> { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index d1c2c91e00fd7..7ed43547e1127 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -35,7 +35,7 @@ use rustc_span::DUMMY_SP; use smallvec::SmallVec; use tracing::{debug, trace}; -pub enum SimplifyCfg { +pub(super) enum SimplifyCfg { Initial, PromoteConsts, RemoveFalseEdges, @@ -50,7 +50,7 @@ pub enum SimplifyCfg { } impl SimplifyCfg { - pub fn name(&self) -> &'static str { + fn name(&self) -> &'static str { match self { SimplifyCfg::Initial => "SimplifyCfg-initial", SimplifyCfg::PromoteConsts => "SimplifyCfg-promote-consts", @@ -66,7 +66,7 @@ impl SimplifyCfg { } } -pub(crate) fn simplify_cfg(body: &mut Body<'_>) { +pub(super) fn simplify_cfg(body: &mut Body<'_>) { CfgSimplifier::new(body).simplify(); remove_dead_blocks(body); @@ -74,7 +74,7 @@ pub(crate) fn simplify_cfg(body: &mut Body<'_>) { body.basic_blocks_mut().raw.shrink_to_fit(); } -impl<'tcx> MirPass<'tcx> for SimplifyCfg { +impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg { fn name(&self) -> &'static str { self.name() } @@ -85,13 +85,13 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { } } -pub struct CfgSimplifier<'a, 'tcx> { +struct CfgSimplifier<'a, 'tcx> { basic_blocks: &'a mut IndexSlice>, pred_count: IndexVec, } impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { - pub fn new(body: &'a mut Body<'tcx>) -> Self { + fn new(body: &'a mut Body<'tcx>) -> Self { let mut pred_count = IndexVec::from_elem(0u32, &body.basic_blocks); // we can't use mir.predecessors() here because that counts @@ -111,7 +111,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { CfgSimplifier { basic_blocks, pred_count } } - pub fn simplify(mut self) { + fn simplify(mut self) { self.strip_nops(); // Vec of the blocks that should be merged. We store the indices here, instead of the @@ -280,7 +280,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } } -pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) { +pub(super) fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) { if let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind { let otherwise = targets.otherwise(); if targets.iter().any(|t| t.1 == otherwise) { @@ -292,7 +292,7 @@ pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) { } } -pub(crate) fn remove_dead_blocks(body: &mut Body<'_>) { +pub(super) fn remove_dead_blocks(body: &mut Body<'_>) { let should_deduplicate_unreachable = |bbdata: &BasicBlockData<'_>| { // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just @@ -360,13 +360,13 @@ pub(crate) fn remove_dead_blocks(body: &mut Body<'_>) { } } -pub enum SimplifyLocals { +pub(super) enum SimplifyLocals { BeforeConstProp, AfterGVN, Final, } -impl<'tcx> MirPass<'tcx> for SimplifyLocals { +impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals { fn name(&self) -> &'static str { match &self { SimplifyLocals::BeforeConstProp => "SimplifyLocals-before-const-prop", @@ -381,23 +381,33 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("running SimplifyLocals on {:?}", body.source); - simplify_locals(body, tcx); - } -} -pub fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) { - // First, we're going to get a count of *actual* uses for every `Local`. - let mut used_locals = UsedLocals::new(body); + // First, we're going to get a count of *actual* uses for every `Local`. + let mut used_locals = UsedLocals::new(body); - // Next, we're going to remove any `Local` with zero actual uses. When we remove those - // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` - // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from - // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a - // fixedpoint where there are no more unused locals. - remove_unused_definitions_helper(&mut used_locals, body); + // Next, we're going to remove any `Local` with zero actual uses. When we remove those + // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` + // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from + // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a + // fixedpoint where there are no more unused locals. + remove_unused_definitions_helper(&mut used_locals, body); + + // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the + // `Local`s. + let map = make_local_map(&mut body.local_decls, &used_locals); + + // Only bother running the `LocalUpdater` if we actually found locals to remove. + if map.iter().any(Option::is_none) { + // Update references to all vars and tmps now + let mut updater = LocalUpdater { map, tcx }; + updater.visit_body_preserves_cfg(body); + + body.local_decls.shrink_to_fit(); + } + } } -pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { +pub(super) fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) { // First, we're going to get a count of *actual* uses for every `Local`. let mut used_locals = UsedLocals::new(body); @@ -407,18 +417,6 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a // fixedpoint where there are no more unused locals. remove_unused_definitions_helper(&mut used_locals, body); - - // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. - let map = make_local_map(&mut body.local_decls, &used_locals); - - // Only bother running the `LocalUpdater` if we actually found locals to remove. - if map.iter().any(Option::is_none) { - // Update references to all vars and tmps now - let mut updater = LocalUpdater { map, tcx }; - updater.visit_body_preserves_cfg(body); - - body.local_decls.shrink_to_fit(); - } } /// Construct the mapping while swapping out unused stuff out from the `vec`. diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 7c8a686d0077e..e83b4727c4856 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -2,12 +2,13 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use tracing::trace; -pub enum SimplifyConstCondition { +pub(super) enum SimplifyConstCondition { AfterConstProp, Final, } + /// A pass that replaces a branch with a goto when its condition is known. -impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { +impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { fn name(&self) -> &'static str { match self { SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop", diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index ac892adebec1b..26496b7f3fe19 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -9,8 +9,6 @@ use rustc_middle::mir::{ use rustc_middle::ty::{Ty, TyCtxt}; use tracing::trace; -use super::MirPass; - /// Pass to convert `if` conditions on integrals into switches on the integral. /// For an example, it turns something like /// @@ -25,9 +23,9 @@ use super::MirPass; /// ```ignore (MIR) /// switchInt(_4) -> [43i32: bb3, otherwise: bb2]; /// ``` -pub struct SimplifyComparisonIntegral; +pub(super) struct SimplifyComparisonIntegral; -impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { +impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() > 0 } @@ -75,12 +73,13 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { _ => unreachable!(), } - // delete comparison statement if it the value being switched on was moved, which means it can not be user later on + // delete comparison statement if it the value being switched on was moved, which means + // it can not be user later on if opt.can_remove_bin_op_stmt { bb.statements[opt.bin_op_stmt_idx].make_nop(); } else { - // if the integer being compared to a const integral is being moved into the comparison, - // e.g `_2 = Eq(move _3, const 'x');` + // if the integer being compared to a const integral is being moved into the + // comparison, e.g `_2 = Eq(move _3, const 'x');` // we want to avoid making a double move later on in the switchInt on _3. // So to avoid `switchInt(move _3) -> ['x': bb2, otherwise: bb1];`, // we convert the move in the comparison statement to a copy. @@ -104,20 +103,20 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { // remove StorageDead (if it exists) being used in the assign of the comparison for (stmt_idx, stmt) in bb.statements.iter().enumerate() { - if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local) - { + if !matches!( + stmt.kind, + StatementKind::StorageDead(local) if local == opt.to_switch_on.local + ) { continue; } storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); - // if we have StorageDeads to remove then make sure to insert them at the top of each target + // if we have StorageDeads to remove then make sure to insert them at the top of + // each target for bb_idx in new_targets.all_targets() { - storage_deads_to_insert.push(( - *bb_idx, - Statement { - source_info: terminator.source_info, - kind: StatementKind::StorageDead(opt.to_switch_on.local), - }, - )); + storage_deads_to_insert.push((*bb_idx, Statement { + source_info: terminator.source_info, + kind: StatementKind::StorageDead(opt.to_switch_on.local), + })); } } @@ -209,7 +208,8 @@ fn find_branch_value_info<'tcx>( (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { let branch_value_ty = branch_value.const_.ty(); - // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats + // we only want to apply this optimization if we are matching on integrals (and chars), + // as it is not possible to switch on floats if !branch_value_ty.is_integral() && !branch_value_ty.is_char() { return None; }; @@ -224,7 +224,8 @@ fn find_branch_value_info<'tcx>( struct OptimizationInfo<'tcx> { /// Basic block to apply the optimization bb_idx: BasicBlock, - /// Statement index of Eq/Ne assignment that can be removed. None if the assignment can not be removed - i.e the statement is used later on + /// Statement index of Eq/Ne assignment that can be removed. None if the assignment can not be + /// removed - i.e the statement is used later on bin_op_stmt_idx: usize, /// Can remove Eq/Ne assignment can_remove_bin_op_stmt: bool, diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs index 35cb6872fe9a2..9884b6dd1c35e 100644 --- a/compiler/rustc_mir_transform/src/single_use_consts.rs +++ b/compiler/rustc_mir_transform/src/single_use_consts.rs @@ -1,5 +1,5 @@ -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -19,9 +19,9 @@ use rustc_middle::ty::TyCtxt; /// /// It also removes *never*-used constants, since it had all the information /// needed to do that too, including updating the debug info. -pub struct SingleUseConsts; +pub(super) struct SingleUseConsts; -impl<'tcx> MirPass<'tcx> for SingleUseConsts { +impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() > 0 } diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 906e2c23f3b8c..2de0059bc7fd7 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -1,19 +1,19 @@ use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_hir::LangItem; -use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; +use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_middle::bug; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{excluded_locals, iter_fields}; -use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx}; use tracing::{debug, instrument}; -pub struct ScalarReplacementOfAggregates; +pub(super) struct ScalarReplacementOfAggregates; -impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates { +impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 2 } diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index c1254766f0a97..84df666e34a72 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{ParamEnv, TyCtxt}; use tracing::{debug, instrument, trace}; -pub struct SsaLocals { +pub(super) struct SsaLocals { /// Assignments to each local. This defines whether the local is SSA. assignments: IndexVec>, /// We visit the body in reverse postorder, to ensure each local is assigned before it is used. @@ -32,14 +32,18 @@ pub struct SsaLocals { borrowed_locals: BitSet, } -pub enum AssignedValue<'a, 'tcx> { +pub(super) enum AssignedValue<'a, 'tcx> { Arg, Rvalue(&'a mut Rvalue<'tcx>), Terminator, } impl SsaLocals { - pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ParamEnv<'tcx>) -> SsaLocals { + pub(super) fn new<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> SsaLocals { let assignment_order = Vec::with_capacity(body.local_decls.len()); let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls); @@ -101,25 +105,25 @@ impl SsaLocals { ssa } - pub fn num_locals(&self) -> usize { + pub(super) fn num_locals(&self) -> usize { self.assignments.len() } - pub fn locals(&self) -> impl Iterator { + pub(super) fn locals(&self) -> impl Iterator { self.assignments.indices() } - pub fn is_ssa(&self, local: Local) -> bool { + pub(super) fn is_ssa(&self, local: Local) -> bool { matches!(self.assignments[local], Set1::One(_)) } /// Return the number of uses if a local that are not "Deref". - pub fn num_direct_uses(&self, local: Local) -> u32 { + pub(super) fn num_direct_uses(&self, local: Local) -> u32 { self.direct_uses[local] } #[inline] - pub fn assignment_dominates( + pub(super) fn assignment_dominates( &self, dominators: &Dominators, local: Local, @@ -131,7 +135,7 @@ impl SsaLocals { } } - pub fn assignments<'a, 'tcx>( + pub(super) fn assignments<'a, 'tcx>( &'a self, body: &'a Body<'tcx>, ) -> impl Iterator, Location)> + 'a { @@ -148,18 +152,17 @@ impl SsaLocals { }) } - pub fn for_each_assignment_mut<'tcx>( + pub(super) fn for_each_assignment_mut<'tcx>( &self, basic_blocks: &mut IndexSlice>, mut f: impl FnMut(Local, AssignedValue<'_, 'tcx>, Location), ) { for &local in &self.assignment_order { match self.assignments[local] { - Set1::One(DefLocation::Argument) => f( - local, - AssignedValue::Arg, - Location { block: START_BLOCK, statement_index: 0 }, - ), + Set1::One(DefLocation::Argument) => f(local, AssignedValue::Arg, Location { + block: START_BLOCK, + statement_index: 0, + }), Set1::One(DefLocation::Assignment(loc)) => { let bb = &mut basic_blocks[loc.block]; // `loc` must point to a direct assignment to `local`. @@ -194,17 +197,17 @@ impl SsaLocals { /// _d => _a // transitively through _c /// /// Exception: we do not see through the return place, as it cannot be instantiated. - pub fn copy_classes(&self) -> &IndexSlice { + pub(super) fn copy_classes(&self) -> &IndexSlice { &self.copy_classes } /// Set of SSA locals that are immutably borrowed. - pub fn borrowed_locals(&self) -> &BitSet { + pub(super) fn borrowed_locals(&self) -> &BitSet { &self.borrowed_locals } /// Make a property uniform on a copy equivalence class by removing elements. - pub fn meet_copy_equivalence(&self, property: &mut BitSet) { + pub(super) fn meet_copy_equivalence(&self, property: &mut BitSet) { // Consolidate to have a local iff all its copies are. // // `copy_classes` defines equivalence classes between locals. The `local`s that recursively @@ -231,7 +234,7 @@ impl SsaLocals { } } -struct SsaVisitor<'tcx, 'a> { +struct SsaVisitor<'a, 'tcx> { body: &'a Body<'tcx>, dominators: &'a Dominators, assignments: IndexVec>, @@ -257,7 +260,7 @@ impl SsaVisitor<'_, '_> { } } -impl<'tcx> Visitor<'tcx> for SsaVisitor<'tcx, '_> { +impl<'tcx> Visitor<'tcx> for SsaVisitor<'_, 'tcx> { fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) { match ctxt { PlaceContext::MutatingUse(MutatingUseContext::Projection) diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs index 2427fbac5eefa..5612e779d6bca 100644 --- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs @@ -12,9 +12,7 @@ use rustc_middle::ty::{Ty, TyCtxt}; use rustc_target::abi::{Abi, Variants}; use tracing::trace; -use crate::MirPass; - -pub struct UnreachableEnumBranching; +pub(super) struct UnreachableEnumBranching; fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option { if let TerminatorKind::SwitchInt { discr: Operand::Move(p), .. } = terminator { @@ -74,7 +72,7 @@ fn variant_discriminants<'tcx>( } } -impl<'tcx> MirPass<'tcx> for UnreachableEnumBranching { +impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() > 0 } @@ -158,9 +156,9 @@ impl<'tcx> MirPass<'tcx> for UnreachableEnumBranching { }; true } - // If and only if there is a variant that does not have a branch set, - // change the current of otherwise as the variant branch and set otherwise to unreachable. - // It transforms following code + // If and only if there is a variant that does not have a branch set, change the + // current of otherwise as the variant branch and set otherwise to unreachable. It + // transforms following code // ```rust // match c { // Ordering::Less => 1, diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index a6c3c3b189ed0..f3dafd13824f3 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -10,9 +10,9 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use rustc_target::abi::Size; -pub struct UnreachablePropagation; +pub(super) struct UnreachablePropagation; -impl MirPass<'_> for UnreachablePropagation { +impl crate::MirPass<'_> for UnreachablePropagation { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { // Enable only under -Zmir-opt-level=2 as this can make programs less debuggable. sess.mir_opt_level() >= 2 @@ -26,7 +26,8 @@ impl MirPass<'_> for UnreachablePropagation { let terminator = bb_data.terminator(); let is_unreachable = match &terminator.kind { TerminatorKind::Unreachable => true, - // This will unconditionally run into an unreachable and is therefore unreachable as well. + // This will unconditionally run into an unreachable and is therefore unreachable + // as well. TerminatorKind::Goto { target } if unreachable_blocks.contains(target) => { patch.patch_terminator(bb, TerminatorKind::Unreachable); true @@ -85,8 +86,9 @@ fn remove_successors_from_switch<'tcx>( // } // } // - // This generates a `switchInt() -> [0: 0, 1: 1, otherwise: unreachable]`, which allows us or LLVM to - // turn it into just `x` later. Without the unreachable, such a transformation would be illegal. + // This generates a `switchInt() -> [0: 0, 1: 1, otherwise: unreachable]`, which allows us or + // LLVM to turn it into just `x` later. Without the unreachable, such a transformation would be + // illegal. // // In order to preserve this information, we record reachable and unreachable targets as // `Assume` statements in MIR. diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 99e06f59dd04d..e353be6a105f0 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -2,9 +2,10 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::LangItem; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; -use rustc_infer::traits::Reveal; +use rustc_index::bit_set::BitSet; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::{Obligation, ObligationCause, Reveal}; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -14,8 +15,10 @@ use rustc_middle::ty::{ Variance, }; use rustc_middle::{bug, span_bug}; -use rustc_target::abi::{Size, FIRST_VARIANT}; +use rustc_target::abi::{FIRST_VARIANT, Size}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::ObligationCtxt; +use rustc_type_ir::Upcast; use crate::util::{is_within_packed, relate_types}; @@ -25,7 +28,7 @@ enum EdgeKind { Normal, } -pub struct Validator { +pub(super) struct Validator { /// Describes at which point in the pipeline this validation is happening. pub when: String, /// The phase for which we are upholding the dialect. If the given phase forbids a specific @@ -36,7 +39,7 @@ pub struct Validator { pub mir_phase: MirPhase, } -impl<'tcx> MirPass<'tcx> for Validator { +impl<'tcx> crate::MirPass<'tcx> for Validator { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not // terribly important that they pass the validator. However, I think other passes might @@ -387,10 +390,11 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } self.check_unwind_edge(location, unwind); - // The code generation assumes that there are no critical call edges. The assumption - // is used to simplify inserting code that should be executed along the return edge - // from the call. FIXME(tmiasko): Since this is a strictly code generation concern, - // the code generation should be responsible for handling it. + // The code generation assumes that there are no critical call edges. The + // assumption is used to simplify inserting code that should be executed along + // the return edge from the call. FIXME(tmiasko): Since this is a strictly code + // generation concern, the code generation should be responsible for handling + // it. if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Optimized) && self.is_critical_call_edge(target, unwind) { @@ -403,8 +407,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { ); } - // The call destination place and Operand::Move place used as an argument might be - // passed by a reference to the callee. Consequently they cannot be packed. + // The call destination place and Operand::Move place used as an argument might + // be passed by a reference to the callee. Consequently they cannot be packed. if is_within_packed(self.tcx, &self.body.local_decls, destination).is_some() { // This is bad! The callee will expect the memory to be aligned. self.fail( @@ -530,7 +534,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { /// /// `caller_body` is used to detect cycles in MIR inlining and MIR validation before /// `optimized_mir` is available. -pub fn validate_types<'tcx>( +pub(super) fn validate_types<'tcx>( tcx: TyCtxt<'tcx>, mir_phase: MirPhase, param_env: ty::ParamEnv<'tcx>, @@ -585,6 +589,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { crate::util::relate_types(self.tcx, self.param_env, variance, src, dest) } + + /// Check that the given predicate definitely holds in the param-env of this MIR body. + fn predicate_must_hold_modulo_regions( + &self, + pred: impl Upcast, ty::Predicate<'tcx>>, + ) -> bool { + let infcx = self.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligation(Obligation::new( + self.tcx, + ObligationCause::dummy(), + self.param_env, + pred, + )); + ocx.select_all_or_error().is_empty() + } } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { @@ -714,7 +734,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // since we may be in the process of computing this MIR in the // first place. let layout = if def_id == self.caller_body.source.def_id() { - // FIXME: This is not right for async closures. + self.caller_body.coroutine_layout_raw() + } else if self.tcx.needs_coroutine_by_move_body_def_id(def_id) + && let ty::ClosureKind::FnOnce = + args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() + && self.caller_body.source.def_id() + == self.tcx.coroutine_by_move_body_def_id(def_id) + { + // Same if this is the by-move body of a coroutine-closure. self.caller_body.coroutine_layout_raw() } else { self.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) @@ -942,9 +969,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } AggregateKind::RawPtr(pointee_ty, mutability) => { if !matches!(self.mir_phase, MirPhase::Runtime(_)) { - // It would probably be fine to support this in earlier phases, - // but at the time of writing it's only ever introduced from intrinsic lowering, - // so earlier things just `bug!` on it. + // It would probably be fine to support this in earlier phases, but at the + // time of writing it's only ever introduced from intrinsic lowering, so + // earlier things just `bug!` on it. self.fail(location, "RawPtr should be in runtime MIR only"); } @@ -1098,10 +1125,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } UnOp::PtrMetadata => { if !matches!(self.mir_phase, MirPhase::Runtime(_)) { - // It would probably be fine to support this in earlier phases, - // but at the time of writing it's only ever introduced from intrinsic lowering - // or other runtime-phase optimization passes, - // so earlier things can just `bug!` on it. + // It would probably be fine to support this in earlier phases, but at + // the time of writing it's only ever introduced from intrinsic + // lowering or other runtime-phase optimization passes, so earlier + // things can just `bug!` on it. self.fail(location, "PtrMetadata should be in runtime MIR only"); } @@ -1120,12 +1147,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Cast(kind, operand, target_type) => { let op_ty = operand.ty(self.body, self.tcx); match kind { - CastKind::DynStar => { - // FIXME(dyn-star): make sure nothing needs to be done here. - } // FIXME: Add Checks for these CastKind::PointerWithExposedProvenance | CastKind::PointerExposeProvenance => {} - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => { // FIXME: check signature compatibility. check_kinds!( op_ty, @@ -1138,7 +1162,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ty::FnPtr(..) ); } - CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _) => { // FIXME: check safety and signature compatibility. check_kinds!( op_ty, @@ -1151,7 +1175,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ty::FnPtr(..) ); } - CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(..)) => { + CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(..), _) => { // FIXME: check safety, captures, and signature compatibility. check_kinds!( op_ty, @@ -1164,7 +1188,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ty::FnPtr(..) ); } - CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => { + CastKind::PointerCoercion(PointerCoercion::MutToConstPointer, _) => { // FIXME: check same pointee? check_kinds!( op_ty, @@ -1180,7 +1204,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, format!("After borrowck, MIR disallows {kind:?}")); } } - CastKind::PointerCoercion(PointerCoercion::ArrayToPointer) => { + CastKind::PointerCoercion(PointerCoercion::ArrayToPointer, _) => { // FIXME: Check pointee types check_kinds!( op_ty, @@ -1196,9 +1220,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, format!("After borrowck, MIR disallows {kind:?}")); } } - CastKind::PointerCoercion(PointerCoercion::Unsize) => { - // This is used for all `CoerceUnsized` types, - // not just pointers/references, so is hard to check. + CastKind::PointerCoercion(PointerCoercion::Unsize, _) => { + // Pointers being unsize coerced should at least implement + // `CoerceUnsized`. + if !self.predicate_must_hold_modulo_regions(ty::TraitRef::new( + self.tcx, + self.tcx.require_lang_item( + LangItem::CoerceUnsized, + Some(self.body.source_info(location).span), + ), + [op_ty, *target_type], + )) { + self.fail(location, format!("Unsize coercion, but `{op_ty}` isn't coercible to `{target_type}`")); + } + } + CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { + // FIXME(dyn-star): make sure nothing needs to be done here. } CastKind::IntToInt | CastKind::IntToFloat => { let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool(); @@ -1495,7 +1532,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } if let TerminatorKind::TailCall { .. } = terminator.kind { - // FIXME(explicit_tail_calls): implement tail-call specific checks here (such as signature matching, forbidding closures, etc) + // FIXME(explicit_tail_calls): implement tail-call specific checks here (such + // as signature matching, forbidding closures, etc) } } TerminatorKind::Assert { cond, .. } => { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 9c820b888d910..276098a840079 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -210,7 +210,7 @@ mod move_check; use std::path::PathBuf; use move_check::MoveCheckState; -use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock}; +use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -220,7 +220,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::mir::visit::Visitor as MirVisitor; -use rustc_middle::mir::{self, traversal, Location, MentionedItem}; +use rustc_middle::mir::{self, Location, MentionedItem, traversal}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; @@ -231,11 +231,11 @@ use rustc_middle::ty::{ }; use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; -use rustc_session::config::EntryFnType; use rustc_session::Limit; -use rustc_span::source_map::{dummy_spanned, respan, Spanned}; -use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_session::config::EntryFnType; +use rustc_span::source_map::{Spanned, dummy_spanned, respan}; +use rustc_span::symbol::{Ident, sym}; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::Size; use tracing::{debug, instrument, trace}; @@ -397,7 +397,7 @@ fn collect_items_rec<'tcx>( MonoItem::Static(def_id) => { recursion_depth_reset = None; - // Statics always get evaluted (which is possible because they can't be generic), so for + // Statics always get evaluated (which is possible because they can't be generic), so for // `MentionedItems` collection there's nothing to do here. if mode == CollectionMode::UsedItems { let instance = Instance::mono(tcx, def_id); @@ -665,11 +665,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::Unsize), + mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _) + | mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _), ref operand, target_ty, - ) - | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => { + ) => { let source_ty = operand.ty(self.body, self.tcx); // *Before* monomorphizing, record that we already handled this mention. self.used_mentioned_items @@ -694,7 +694,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { } } mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer), + mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _), ref operand, _, ) => { @@ -705,7 +705,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { visit_fn_use(self.tcx, fn_ty, false, span, self.used_items); } mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), + mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _), ref operand, _, ) => { @@ -1041,8 +1041,11 @@ fn find_vtable_types_for_unsizing<'tcx>( match (source_ty.kind(), target_ty.kind()) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _)) | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b), - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) + (_, _) + if let Some(source_boxed) = source_ty.boxed_ty() + && let Some(target_boxed) = target_ty.boxed_ty() => + { + ptr_vtable(source_boxed, target_boxed) } // T as dyn* Trait @@ -1172,15 +1175,15 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt output.push(create_fn_mono_item(tcx, instance, DUMMY_SP)); } } - GlobalAlloc::VTable(ty, trait_ref) => { - let alloc_id = tcx.vtable_allocation((ty, trait_ref)); + GlobalAlloc::VTable(ty, dyn_ty) => { + let alloc_id = tcx.vtable_allocation((ty, dyn_ty.principal())); collect_alloc(tcx, alloc_id, output) } } } fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option { - for impl_def_id in tcx.inherent_impls(def_id).ok()? { + for impl_def_id in tcx.inherent_impls(def_id) { if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind( tcx, fn_ident, @@ -1190,7 +1193,7 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> return Some(new.def_id); } } - return None; + None } /// Scans the MIR in order to find function calls, closures, and drop-glue. diff --git a/compiler/rustc_monomorphize/src/collector/move_check.rs b/compiler/rustc_monomorphize/src/collector/move_check.rs index 851f86e86b8e8..b86ef1e737328 100644 --- a/compiler/rustc_monomorphize/src/collector/move_check.rs +++ b/compiler/rustc_monomorphize/src/collector/move_check.rs @@ -132,12 +132,11 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { // but correct span? This would make the lint at least accept crate-level lint attributes. return; }; - self.tcx.emit_node_span_lint( - LARGE_ASSIGNMENTS, - lint_root, + self.tcx.emit_node_span_lint(LARGE_ASSIGNMENTS, lint_root, span, LargeAssignmentsLint { span, - LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 }, - ); + size: too_large_size.bytes(), + limit: limit as u64, + }); self.move_check.move_size_spans.push(span); } } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b22e8e30465ea..e92e6978d0f49 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,8 @@ // tidy-alphabetical-start #![feature(array_windows)] +#![feature(file_buffered)] +#![feature(if_let_guard)] +#![feature(let_chains)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 0d295b8f280f5..ad05cca66cab3 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -95,16 +95,16 @@ use std::cmp; use std::collections::hash_map::Entry; use std::fs::{self, File}; -use std::io::{BufWriter, Write}; +use std::io::Write; use std::path::{Path, PathBuf}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sync; use rustc_data_structures::unord::{UnordMap, UnordSet}; +use rustc_hir::LangItem; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; -use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; @@ -116,8 +116,8 @@ use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_pat use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, InstanceKind, TyCtxt}; use rustc_middle::util::Providers; -use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_session::CodegenUnits; +use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_span::symbol::Symbol; use tracing::debug; @@ -255,8 +255,12 @@ where } let size_estimate = mono_item.size_estimate(cx.tcx); - cgu.items_mut() - .insert(mono_item, MonoItemData { inlined: false, linkage, visibility, size_estimate }); + cgu.items_mut().insert(mono_item, MonoItemData { + inlined: false, + linkage, + visibility, + size_estimate, + }); // Get all inlined items that are reachable from `mono_item` without // going via another root item. This includes drop-glue, functions from @@ -504,10 +508,8 @@ fn compute_inlined_overlap<'tcx>(cgu1: &CodegenUnit<'tcx>, cgu2: &CodegenUnit<'t let mut overlap = 0; for (item, data) in src_cgu.items().iter() { - if data.inlined { - if dst_cgu.items().contains_key(item) { - overlap += data.size_estimate; - } + if data.inlined && dst_cgu.items().contains_key(item) { + overlap += data.size_estimate; } } overlap @@ -1241,8 +1243,7 @@ fn dump_mono_items_stats<'tcx>( let ext = format.extension(); let filename = format!("{crate_name}.mono_items.{ext}"); let output_path = output_directory.join(&filename); - let file = File::create(&output_path)?; - let mut file = BufWriter::new(file); + let mut file = File::create_buffered(&output_path)?; // Gather instantiated mono items grouped by def_id let mut items_per_def_id: FxIndexMap<_, Vec<_>> = Default::default(); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index c65ad9fa67e53..e049fe996645a 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -5,9 +5,9 @@ //! generic parameters are unused (and eventually, in what ways generic parameters are used - only //! for their size, offset of a field, etc.). +use rustc_hir::ConstContext; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_hir::ConstContext; use rustc_middle::mir::visit::{TyContext, Visitor}; use rustc_middle::mir::{self, Local, LocalDecl, Location}; use rustc_middle::query::Providers; diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 394518daa4250..196ddeb244302 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -185,10 +185,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { for var in var_infos.iter_mut() { // We simply put all regions from the input into the highest // compressed universe, so we only deal with them at the end. - if !var.is_region() { - if is_existential == var.is_existential() { - update_uv(var, orig_uv, is_existential) - } + if !var.is_region() && is_existential == var.is_existential() { + update_uv(var, orig_uv, is_existential) } } } diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index ea244b5107ad6..ca140500e2cd3 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -5,6 +5,7 @@ //! So if you got to this crate from the old solver, it's totally normal. // tidy-alphabetical-start +#![cfg_attr(not(bootstrap), allow(rustc::usage_of_type_ir_inherent))] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index bb05eb4c25697..520afbeb645c2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -7,7 +7,7 @@ use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, elaborate, Interner, Upcast as _}; +use rustc_type_ir::{self as ty, Interner, Upcast as _, elaborate}; use tracing::{debug, instrument}; use crate::delegate::SolverDelegate; @@ -304,6 +304,11 @@ where let mut candidates = vec![]; + if self.solver_mode() == SolverMode::Coherence { + if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) { + return vec![candidate]; + } + } self.assemble_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); @@ -314,11 +319,8 @@ where self.assemble_param_env_candidates(goal, &mut candidates); - match self.solver_mode() { - SolverMode::Normal => self.discard_impls_shadowed_by_env(goal, &mut candidates), - SolverMode::Coherence => { - self.assemble_coherence_unknowable_candidates(goal, &mut candidates) - } + if self.solver_mode() == SolverMode::Normal { + self.discard_impls_shadowed_by_env(goal, &mut candidates); } candidates @@ -682,38 +684,34 @@ where /// also consider impls which may get added in a downstream or sibling crate /// or which an upstream impl may add in a minor release. /// - /// To do so we add an ambiguous candidate in case such an unknown impl could - /// apply to the current goal. + /// To do so we return a single ambiguous candidate in case such an unknown + /// impl could apply to the current goal. #[instrument(level = "trace", skip_all)] - fn assemble_coherence_unknowable_candidates>( + fn consider_coherence_unknowable_candidate>( &mut self, goal: Goal, - candidates: &mut Vec>, - ) { - let cx = self.cx(); - - candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter( - |ecx| { - let trait_ref = goal.predicate.trait_ref(cx); - if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? { - Err(NoSolution) - } else { - // While the trait bound itself may be unknowable, we may be able to - // prove that a super trait is not implemented. For this, we recursively - // prove the super trait bounds of the current goal. - // - // We skip the goal itself as that one would cycle. - let predicate: I::Predicate = trait_ref.upcast(cx); - ecx.add_goals( - GoalSource::Misc, - elaborate::elaborate(cx, [predicate]) - .skip(1) - .map(|predicate| goal.with(cx, predicate)), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - }, - )) + ) -> Result, NoSolution> { + self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| { + let cx = ecx.cx(); + let trait_ref = goal.predicate.trait_ref(cx); + if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? { + Err(NoSolution) + } else { + // While the trait bound itself may be unknowable, we may be able to + // prove that a super trait is not implemented. For this, we recursively + // prove the super trait bounds of the current goal. + // + // We skip the goal itself as that one would cycle. + let predicate: I::Predicate = trait_ref.upcast(cx); + ecx.add_goals( + GoalSource::Misc, + elaborate::elaborate(cx, [predicate]) + .skip(1) + .map(|predicate| goal.with(cx, predicate)), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + }) } /// If there's a where-bound for the current goal, do not use any impl candidates diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index a57338acaab29..5c1a7852dc0b4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -7,7 +7,7 @@ use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::{self as ty, elaborate, Interner, Upcast as _}; +use rustc_type_ir::{self as ty, Interner, Upcast as _, elaborate}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; @@ -507,11 +507,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( sig: ty::CoroutineClosureSignature, ) -> I::Ty { let upvars_projection_def_id = cx.require_lang_item(TraitSolverLangItem::AsyncFnKindUpvars); - let tupled_upvars_ty = Ty::new_projection( - cx, - upvars_projection_def_id, - [ - I::GenericArg::from(args.kind_ty()), - Ty::from_closure_kind(cx, goal_kind).into(), - goal_region.into(), - sig.tupled_inputs_ty.into(), - args.tupled_upvars_ty().into(), - args.coroutine_captures_by_ref_ty().into(), - ], - ); + let tupled_upvars_ty = Ty::new_projection(cx, upvars_projection_def_id, [ + I::GenericArg::from(args.kind_ty()), + Ty::from_closure_kind(cx, goal_kind).into(), + goal_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ]); sig.to_coroutine( cx, args.parent_args(), diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 2e521ddcec322..252a9ed1a2e79 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -22,9 +22,9 @@ use crate::delegate::SolverDelegate; use crate::resolve::EagerResolver; use crate::solve::eval_ctxt::NestedGoals; use crate::solve::{ - inspect, response_no_constraints_raw, CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, - ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution, - PredefinedOpaquesData, QueryInput, QueryResult, Response, + CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal, + MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput, + QueryResult, Response, inspect, response_no_constraints_raw, }; trait ResponseT { @@ -122,6 +122,21 @@ where (certainty, NestedNormalizationGoals::empty()) }; + if let Certainty::Maybe(cause @ MaybeCause::Overflow { .. }) = certainty { + // If we have overflow, it's probable that we're substituting a type + // into itself infinitely and any partial substitutions in the query + // response are probably not useful anyways, so just return an empty + // query response. + // + // This may prevent us from potentially useful inference, e.g. + // 2 candidates, one ambiguous and one overflow, which both + // have the same inference constraints. + // + // Changing this to retain some constraints in the future + // won't be a breaking change, so this is good enough for now. + return Ok(self.make_ambiguous_response_no_constraints(cause)); + } + let external_constraints = self.compute_external_query_constraints(certainty, normalization_nested_goals); let (var_values, mut external_constraints) = (self.var_values, external_constraints) @@ -142,6 +157,17 @@ where }, ); + // HACK: We bail with overflow if the response would have too many non-region + // inference variables. This tends to only happen if we encounter a lot of + // ambiguous alias types which get replaced with fresh inference variables + // during generalization. This prevents a hang in nalgebra. + let num_non_region_vars = canonical.variables.iter().filter(|c| !c.is_region()).count(); + if num_non_region_vars > self.cx().recursion_limit() { + return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow { + suggest_increasing_limit: true, + })); + } + Ok(canonical) } @@ -238,7 +264,7 @@ where (normalization_nested_goals.clone(), certainty) } - /// This returns the canoncial variable values to instantiate the bound variables of + /// This returns the canonical variable values to instantiate the bound variables of /// the canonical response. This depends on the `original_values` for the /// bound variables. fn compute_query_response_instantiation_values>( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 3f2f34d3255f7..12ad0724b5cb1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -17,9 +17,9 @@ use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ - CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource, MaybeCause, - NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, SolverMode, - FIXPOINT_STEP_LIMIT, + CanonicalInput, CanonicalResponse, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, + GoalSource, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, + SolverMode, }; pub(super) mod canonical; @@ -370,7 +370,7 @@ where canonical_goal, &mut goal_evaluation, ); - let canonical_response = match canonical_response { + let response = match canonical_response { Err(e) => { self.inspect.goal_evaluation(goal_evaluation); return Err(e); @@ -378,12 +378,11 @@ where Ok(response) => response, }; - let (normalization_nested_goals, certainty, has_changed) = self - .instantiate_response_discarding_overflow( - goal.param_env, - orig_values, - canonical_response, - ); + let has_changed = !response.value.var_values.is_identity_modulo_regions() + || !response.value.external_constraints.opaque_types.is_empty(); + + let (normalization_nested_goals, certainty) = + self.instantiate_and_apply_query_response(goal.param_env, orig_values, response); self.inspect.goal_evaluation(goal_evaluation); // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. @@ -398,24 +397,6 @@ where Ok((normalization_nested_goals, has_changed, certainty)) } - fn instantiate_response_discarding_overflow( - &mut self, - param_env: I::ParamEnv, - original_values: Vec, - response: CanonicalResponse, - ) -> (NestedNormalizationGoals, Certainty, bool) { - if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty { - return (NestedNormalizationGoals::empty(), response.value.certainty, false); - } - - let has_changed = !response.value.var_values.is_identity_modulo_regions() - || !response.value.external_constraints.opaque_types.is_empty(); - - let (normalization_nested_goals, certainty) = - self.instantiate_and_apply_query_response(param_env, original_values, response); - (normalization_nested_goals, certainty, has_changed) - } - fn compute_goal(&mut self, goal: Goal) -> QueryResult { let Goal { param_env, predicate } = goal; let kind = predicate.kind(); @@ -516,10 +497,10 @@ where // Replace the goal with an unconstrained infer var, so the // RHS does not affect projection candidate assembly. let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term); - let unconstrained_goal = goal.with( - cx, - ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs }, - ); + let unconstrained_goal = goal.with(cx, ty::NormalizesTo { + alias: goal.predicate.alias, + term: unconstrained_rhs, + }); let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw( GoalEvaluationKind::Nested, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index e459d5cbe5889..be69a6e84ea13 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -6,7 +6,7 @@ use tracing::instrument; use crate::delegate::SolverDelegate; use crate::solve::assembly::Candidate; use crate::solve::{ - inspect, BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult, + BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult, inspect, }; pub(in crate::solve) struct ProbeCtxt<'me, 'a, D, I, F, T> diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 742d45de7d3de..85474bf37b448 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -13,8 +13,8 @@ use rustc_type_ir::{self as ty, Interner}; use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; use crate::solve::{ - inspect, CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, - QueryInput, QueryResult, + CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput, + QueryResult, inspect, }; /// The core data structure when building proof trees. diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index c65c5851e9b4f..536b502136ad3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -164,7 +164,7 @@ where // - `Bound` cannot exist as we don't have a binder around the self Type // - `Expr` is part of `feature(generic_const_exprs)` and is not implemented yet ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Expr(_) => { - panic!("unexpect const kind: {:?}", ct) + panic!("unexpected const kind: {:?}", ct) } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index c7a9846cd97f0..fc9c634942b70 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -3,7 +3,7 @@ mod inherent; mod opaque_types; mod weak_types; -use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _}; @@ -106,6 +106,12 @@ where if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { let cx = ecx.cx(); + if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.alias.args, + projection_pred.skip_binder().projection_term.args, + ) { + return Err(NoSolution); + } ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); @@ -144,7 +150,7 @@ where let goal_trait_ref = goal.predicate.alias.trait_ref(cx); let impl_trait_ref = cx.impl_trait_ref(impl_def_id); - if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup).args_may_unify( + if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()).args_may_unify( goal.predicate.alias.trait_ref(cx).args, impl_trait_ref.skip_binder().args, ) { @@ -334,11 +340,10 @@ where let pred = tupled_inputs_and_output .map_bound(|(inputs, output)| ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), inputs], - ), + projection_term: ty::AliasTerm::new(cx, goal.predicate.def_id(), [ + goal.predicate.self_ty(), + inputs, + ]), term: output.into(), }) .upcast(cx); @@ -390,26 +395,21 @@ where .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallOnceFuture) { ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), tupled_inputs_ty], - ), + ty::AliasTerm::new(cx, goal.predicate.def_id(), [ + goal.predicate.self_ty(), + tupled_inputs_ty, + ]), output_coroutine_ty.into(), ) } else if cx .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallRefFuture) { ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [ - I::GenericArg::from(goal.predicate.self_ty()), - tupled_inputs_ty.into(), - env_region.into(), - ], - ), + ty::AliasTerm::new(cx, goal.predicate.def_id(), [ + I::GenericArg::from(goal.predicate.self_ty()), + tupled_inputs_ty.into(), + env_region.into(), + ]), output_coroutine_ty.into(), ) } else if cx.is_lang_item( @@ -417,14 +417,10 @@ where TraitSolverLangItem::AsyncFnOnceOutput, ) { ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [ - I::GenericArg::from(goal.predicate.self_ty()), - tupled_inputs_ty.into(), - ], - ), + ty::AliasTerm::new(cx, goal.predicate.def_id(), [ + I::GenericArg::from(goal.predicate.self_ty()), + tupled_inputs_ty.into(), + ]), coroutine_return_ty.into(), ) } else { @@ -550,11 +546,10 @@ where // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't // exist. Instead, `Pointee` should be a supertrait of `Sized`. - let sized_predicate = ty::TraitRef::new( - cx, - cx.require_lang_item(TraitSolverLangItem::Sized), - [I::GenericArg::from(goal.predicate.self_ty())], - ); + let sized_predicate = + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [ + I::GenericArg::from(goal.predicate.self_ty()), + ]); // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? ecx.add_goal(GoalSource::Misc, goal.with(cx, sized_predicate)); Ty::new_unit(cx) @@ -725,11 +720,10 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new( - ecx.cx(), - goal.predicate.def_id(), - [self_ty, coroutine.resume_ty()], - ), + projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [ + self_ty, + coroutine.resume_ty(), + ]), term, } .upcast(cx), diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 81c89fad8e8a0..e47cc03f5adf9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,13 +1,13 @@ use std::convert::Infallible; use std::marker::PhantomData; +use rustc_type_ir::Interner; use rustc_type_ir::inherent::*; use rustc_type_ir::search_graph::{self, PathKind}; use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult}; -use rustc_type_ir::Interner; use super::inspect::ProofTreeBuilder; -use super::{has_no_inference_or_external_constraints, FIXPOINT_STEP_LIMIT}; +use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints}; use crate::delegate::SolverDelegate; /// This type is never constructed. We only use it to implement `search_graph::Delegate` diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 1314b7eb6ffc6..781ca127e151e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -2,11 +2,11 @@ use rustc_ast_ir::Movability; use rustc_type_ir::data_structures::IndexSet; -use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, elaborate, Interner, TraitPredicate, Upcast as _}; +use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _, elaborate}; use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; @@ -47,7 +47,7 @@ where let cx = ecx.cx(); let impl_trait_ref = cx.impl_trait_ref(impl_def_id); - if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup) + if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()) .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) { return Err(NoSolution); @@ -124,6 +124,13 @@ where if trait_clause.def_id() == goal.predicate.def_id() && trait_clause.polarity() == goal.predicate.polarity { + if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.trait_ref.args, + trait_clause.skip_binder().trait_ref.args, + ) { + return Err(NoSolution); + } + ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); ecx.eq( @@ -352,21 +359,18 @@ where )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { - ty::TraitRef::new( - cx, - cx.require_lang_item(TraitSolverLangItem::Sized), - [output_coroutine_ty], - ) + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [ + output_coroutine_ty, + ]) }, ); let pred = tupled_inputs_and_output_and_coroutine .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| { - ty::TraitRef::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), tupled_inputs_ty], - ) + ty::TraitRef::new(cx, goal.predicate.def_id(), [ + goal.predicate.self_ty(), + tupled_inputs_ty, + ]) }) .upcast(cx); // A built-in `AsyncFn` impl only holds if the output is sized. @@ -628,7 +632,7 @@ where } // FIXME: This actually should destructure the `Result` we get from transmutability and - // register candiates. We probably need to register >1 since we may have an OR of ANDs. + // register candidates. We probably need to register >1 since we may have an OR of ANDs. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let certainty = ecx.is_transmutable( goal.param_env, @@ -876,7 +880,6 @@ where .into_iter() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { elaborate::supertrait_def_ids(self.cx(), principal_def_id) - .into_iter() .filter(|def_id| self.cx().trait_is_auto(*def_id)) })) .collect(); @@ -1021,11 +1024,9 @@ where GoalSource::ImplWhereBound, goal.with( cx, - ty::TraitRef::new( - cx, - cx.require_lang_item(TraitSolverLangItem::Unsize), - [a_tail_ty, b_tail_ty], - ), + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Unsize), [ + a_tail_ty, b_tail_ty, + ]), ), ); self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) @@ -1063,11 +1064,9 @@ where GoalSource::ImplWhereBound, goal.with( cx, - ty::TraitRef::new( - cx, - cx.require_lang_item(TraitSolverLangItem::Unsize), - [a_last_ty, b_last_ty], - ), + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Unsize), [ + a_last_ty, b_last_ty, + ]), ), ); self.probe_builtin_trait_candidate(BuiltinImplSource::TupleUnsizing) diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index b33896154f239..c59ae48a07d03 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -12,6 +12,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 8e8d91ce4d038..6cb851eb8df6b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -381,6 +381,7 @@ parse_invalid_char_in_escape_msg = invalid character in {$is_hex -> *[false] unicode } escape + parse_invalid_comparison_operator = invalid comparison operator `{$invalid}` .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}` .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering` @@ -581,6 +582,11 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl .suggestion_add_trait = add a trait here .suggestion_remove_for = for an inherent impl, drop this `for` +parse_misspelled_kw = {$is_incorrect_case -> + [true] write keyword `{$similar_kw}` in lowercase + *[false] there is a keyword `{$similar_kw}` with a similar name +} + parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds .suggestion = remove the `{$modifier}` @@ -664,7 +670,7 @@ parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported parse_parenthesized_lifetime_suggestion = remove the parentheses -parse_path_single_colon = path separator must be a double colon +parse_path_double_colon = path separator must be a double colon .suggestion = use a double colon instead parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies @@ -797,15 +803,17 @@ parse_unexpected_expr_in_pat = expected {$is_bound -> [true] a pattern range bound *[false] a pattern - }, found {$is_method_call -> - [true] a method call - *[false] an expression - } + }, found an expression + + .label = arbitrary expressions are not allowed in patterns + +parse_unexpected_expr_in_pat_const_sugg = consider extracting the expression into a `const` + +parse_unexpected_expr_in_pat_create_guard_sugg = consider moving the expression to a match arm guard + +parse_unexpected_expr_in_pat_inline_const_sugg = consider wrapping the expression in an inline `const` (requires `{"#"}![feature(inline_const_pat)]`) - .label = {$is_method_call -> - [true] method calls - *[false] arbitrary expressions - } are not allowed in patterns +parse_unexpected_expr_in_pat_update_guard_sugg = consider moving the expression to the match arm guard parse_unexpected_if_with_if = unexpected `if` in the condition expression .suggestion = remove the `if` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index da1103a4fe5dc..20bcefd4fe1e7 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + use std::borrow::Cow; use rustc_ast::token::Token; @@ -1114,25 +1116,19 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); - let mut diag = Diag::new( - dcx, - level, - match token_descr { - Some(TokenDescription::ReservedIdentifier) => { - fluent::parse_expected_identifier_found_reserved_identifier_str - } - Some(TokenDescription::Keyword) => { - fluent::parse_expected_identifier_found_keyword_str - } - Some(TokenDescription::ReservedKeyword) => { - fluent::parse_expected_identifier_found_reserved_keyword_str - } - Some(TokenDescription::DocComment) => { - fluent::parse_expected_identifier_found_doc_comment_str - } - None => fluent::parse_expected_identifier_found_str, - }, - ); + let mut diag = Diag::new(dcx, level, match token_descr { + Some(TokenDescription::ReservedIdentifier) => { + fluent::parse_expected_identifier_found_reserved_identifier_str + } + Some(TokenDescription::Keyword) => fluent::parse_expected_identifier_found_keyword_str, + Some(TokenDescription::ReservedKeyword) => { + fluent::parse_expected_identifier_found_reserved_keyword_str + } + Some(TokenDescription::DocComment) => { + fluent::parse_expected_identifier_found_doc_comment_str + } + None => fluent::parse_expected_identifier_found_str, + }); diag.span(self.span); diag.arg("token", self.token); @@ -1174,23 +1170,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); - let mut diag = Diag::new( - dcx, - level, - match token_descr { - Some(TokenDescription::ReservedIdentifier) => { - fluent::parse_expected_semi_found_reserved_identifier_str - } - Some(TokenDescription::Keyword) => fluent::parse_expected_semi_found_keyword_str, - Some(TokenDescription::ReservedKeyword) => { - fluent::parse_expected_semi_found_reserved_keyword_str - } - Some(TokenDescription::DocComment) => { - fluent::parse_expected_semi_found_doc_comment_str - } - None => fluent::parse_expected_semi_found_str, - }, - ); + let mut diag = Diag::new(dcx, level, match token_descr { + Some(TokenDescription::ReservedIdentifier) => { + fluent::parse_expected_semi_found_reserved_identifier_str + } + Some(TokenDescription::Keyword) => fluent::parse_expected_semi_found_keyword_str, + Some(TokenDescription::ReservedKeyword) => { + fluent::parse_expected_semi_found_reserved_keyword_str + } + Some(TokenDescription::DocComment) => fluent::parse_expected_semi_found_doc_comment_str, + None => fluent::parse_expected_semi_found_str, + }); diag.span(self.span); diag.arg("token", self.token); @@ -1569,7 +1559,7 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword { } #[derive(Diagnostic)] -#[diag(parse_path_single_colon)] +#[diag(parse_path_double_colon)] pub(crate) struct PathSingleColon { #[primary_span] pub span: Span, @@ -1581,6 +1571,14 @@ pub(crate) struct PathSingleColon { pub type_ascription: bool, } +#[derive(Diagnostic)] +#[diag(parse_path_double_colon)] +pub(crate) struct PathTripleColon { + #[primary_span] + #[suggestion(applicability = "maybe-incorrect", code = "", style = "verbose")] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_colon_as_semi)] pub(crate) struct ColonAsSemi { @@ -2592,13 +2590,86 @@ pub(crate) struct ExpectedCommaAfterPatternField { #[derive(Diagnostic)] #[diag(parse_unexpected_expr_in_pat)] pub(crate) struct UnexpectedExpressionInPattern { + /// The unexpected expr's span. #[primary_span] #[label] pub span: Span, /// Was a `RangePatternBound` expected? pub is_bound: bool, - /// Was the unexpected expression a `MethodCallExpression`? - pub is_method_call: bool, + /// The unexpected expr's precedence (used in match arm guard suggestions). + pub expr_precedence: i8, +} + +#[derive(Subdiagnostic)] +pub(crate) enum UnexpectedExpressionInPatternSugg { + #[multipart_suggestion( + parse_unexpected_expr_in_pat_create_guard_sugg, + applicability = "maybe-incorrect" + )] + CreateGuard { + /// Where to put the suggested identifier. + #[suggestion_part(code = "{ident}")] + ident_span: Span, + /// Where to put the match arm. + #[suggestion_part(code = " if {ident} == {expr}")] + pat_hi: Span, + /// The suggested identifier. + ident: String, + /// The unexpected expression. + expr: String, + }, + + #[multipart_suggestion( + parse_unexpected_expr_in_pat_update_guard_sugg, + applicability = "maybe-incorrect" + )] + UpdateGuard { + /// Where to put the suggested identifier. + #[suggestion_part(code = "{ident}")] + ident_span: Span, + /// The beginning of the match arm guard's expression (insert a `(` if `Some`). + #[suggestion_part(code = "(")] + guard_lo: Option, + /// The end of the match arm guard's expression. + #[suggestion_part(code = "{guard_hi_paren} && {ident} == {expr}")] + guard_hi: Span, + /// Either `")"` or `""`. + guard_hi_paren: &'static str, + /// The suggested identifier. + ident: String, + /// The unexpected expression. + expr: String, + }, + + #[multipart_suggestion( + parse_unexpected_expr_in_pat_const_sugg, + applicability = "has-placeholders" + )] + Const { + /// Where to put the extracted constant declaration. + #[suggestion_part(code = "{indentation}const {ident}: /* Type */ = {expr};\n")] + stmt_lo: Span, + /// Where to put the suggested identifier. + #[suggestion_part(code = "{ident}")] + ident_span: Span, + /// The suggested identifier. + ident: String, + /// The unexpected expression. + expr: String, + /// The statement's block's indentation. + indentation: String, + }, + + #[multipart_suggestion( + parse_unexpected_expr_in_pat_inline_const_sugg, + applicability = "maybe-incorrect" + )] + InlineConst { + #[suggestion_part(code = "const {{ ")] + start_span: Span, + #[suggestion_part(code = " }}")] + end_span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 4d5d1ce099ec4..41108c91f2ebe 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -1,7 +1,7 @@ use rustc_ast::token::Delimiter; use rustc_errors::Diag; -use rustc_span::source_map::SourceMap; use rustc_span::Span; +use rustc_span::source_map::SourceMap; use super::UnmatchedDelim; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f30939093c2ec..3e46fc93fa49d 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -8,12 +8,11 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError}; +use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, }; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::parse::ParseSess; -use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use tracing::debug; @@ -188,9 +187,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { preceded_by_whitespace = true; continue; } - rustc_lexer::TokenKind::Ident => { - self.ident(start) - } + rustc_lexer::TokenKind::Ident => self.ident(start), rustc_lexer::TokenKind::RawIdent => { let sym = nfc_normalize(self.str_from(start + BytePos(2))); let span = self.mk_sp(start, self.pos); @@ -205,20 +202,31 @@ impl<'psess, 'src> StringReader<'psess, 'src> { self.report_unknown_prefix(start); self.ident(start) } - rustc_lexer::TokenKind::InvalidIdent - | rustc_lexer::TokenKind::InvalidPrefix + rustc_lexer::TokenKind::UnknownPrefixLifetime => { + self.report_unknown_prefix(start); + // Include the leading `'` in the real identifier, for macro + // expansion purposes. See #12512 for the gory details of why + // this is necessary. + let lifetime_name = self.str_from(start); + self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); + let ident = Symbol::intern(lifetime_name); + token::Lifetime(ident, IdentIsRaw::No) + } + rustc_lexer::TokenKind::InvalidIdent | rustc_lexer::TokenKind::InvalidPrefix // Do not recover an identifier with emoji if the codepoint is a confusable // with a recoverable substitution token, like `➖`. - if !UNICODE_ARRAY - .iter() - .any(|&(c, _, _)| { - let sym = self.str_from(start); - sym.chars().count() == 1 && c == sym.chars().next().unwrap() - }) => + if !UNICODE_ARRAY.iter().any(|&(c, _, _)| { + let sym = self.str_from(start); + sym.chars().count() == 1 && c == sym.chars().next().unwrap() + }) => { let sym = nfc_normalize(self.str_from(start)); let span = self.mk_sp(start, self.pos); - self.psess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default() + self.psess + .bad_unicode_identifiers + .borrow_mut() + .entry(sym) + .or_default() .push(span); token::Ident(sym, IdentIsRaw::No) } @@ -249,9 +257,9 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let suffix = if suffix_start < self.pos { let string = self.str_from(suffix_start); if string == "_" { - self - .dcx() - .emit_err(errors::UnderscoreLiteralSuffix { span: self.mk_sp(suffix_start, self.pos) }); + self.dcx().emit_err(errors::UnderscoreLiteralSuffix { + span: self.mk_sp(suffix_start, self.pos), + }); None } else { Some(Symbol::intern(string)) @@ -269,12 +277,50 @@ impl<'psess, 'src> StringReader<'psess, 'src> { self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); if starts_with_number { let span = self.mk_sp(start, self.pos); - self.dcx().struct_err("lifetimes cannot start with a number") + self.dcx() + .struct_err("lifetimes cannot start with a number") .with_span(span) .stash(span, StashKey::LifetimeIsChar); } let ident = Symbol::intern(lifetime_name); - token::Lifetime(ident) + token::Lifetime(ident, IdentIsRaw::No) + } + rustc_lexer::TokenKind::RawLifetime => { + self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); + + let ident_start = start + BytePos(3); + let prefix_span = self.mk_sp(start, ident_start); + + if prefix_span.at_least_rust_2021() { + let lifetime_name_without_tick = self.str_from(ident_start); + // Put the `'` back onto the lifetime name. + let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.len() + 1); + lifetime_name.push('\''); + lifetime_name += lifetime_name_without_tick; + let sym = Symbol::intern(&lifetime_name); + + // Make sure we mark this as a raw identifier. + self.psess.raw_identifier_spans.push(self.mk_sp(start, self.pos)); + + token::Lifetime(sym, IdentIsRaw::Yes) + } else { + // Otherwise, this should be parsed like `'r`. Warn about it though. + self.psess.buffer_lint( + RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, + prefix_span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::RawPrefix(prefix_span), + ); + + // Reset the state so we just lex the `'r`. + let lt_start = start + BytePos(2); + self.pos = lt_start; + self.cursor = Cursor::new(&str_before[2 as usize..]); + + let lifetime_name = self.str_from(start); + let ident = Symbol::intern(lifetime_name); + token::Lifetime(ident, IdentIsRaw::No) + } } rustc_lexer::TokenKind::Semi => token::Semi, rustc_lexer::TokenKind::Comma => token::Comma, @@ -331,16 +377,19 @@ impl<'psess, 'src> StringReader<'psess, 'src> { // first remove compound tokens like `<<` from `rustc_lexer`, and then add // fancier error recovery to it, as there will be less overall work to do this // way. - let (token, sugg) = unicode_chars::check_for_substitution(self, start, c, repeats+1); + let (token, sugg) = + unicode_chars::check_for_substitution(self, start, c, repeats + 1); self.dcx().emit_err(errors::UnknownTokenStart { span: self.mk_sp(start, self.pos + Pos::from_usize(repeats * c.len_utf8())), escaped: escaped_char(c), sugg, - null: if c == '\x00' {Some(errors::UnknownTokenNull)} else {None}, + null: if c == '\x00' { Some(errors::UnknownTokenNull) } else { None }, repeat: if repeats > 0 { swallow_next_invalid = repeats; Some(errors::UnknownTokenRepeat { repeats }) - } else {None} + } else { + None + }, }); if let Some(token) = token { @@ -699,7 +748,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let expn_data = prefix_span.ctxt().outer_expn_data(); - if expn_data.edition >= Edition::Edition2021 { + if expn_data.edition.at_least_rust_2021() { // In Rust 2021, this is a hard error. let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) @@ -817,7 +866,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { } pub fn nfc_normalize(string: &str) -> Symbol { - use unicode_normalization::{is_nfc_quick, IsNormalized, UnicodeNormalization}; + use unicode_normalization::{IsNormalized, UnicodeNormalization, is_nfc_quick}; match is_nfc_quick(string.chars()) { IsNormalized::Yes => Symbol::intern(string), _ => { diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index e7a7105803fcd..d35c9c7bae7d6 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -5,7 +5,7 @@ use rustc_errors::{Applicability, PErr}; use rustc_span::symbol::kw; use super::diagnostics::{ - report_suspicious_mismatch_block, same_indentation_level, TokenTreeDiagInfo, + TokenTreeDiagInfo, report_suspicious_mismatch_block, same_indentation_level, }; use super::{StringReader, UnmatchedDelim}; use crate::Parser; @@ -299,7 +299,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { } return diff_errs; } - return errs; + errs } fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'psess> { diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index efa53f0962b78..2e066f0179c3f 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -40,8 +40,8 @@ pub(crate) fn emit_unescape_error( dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false }) } EscapeError::MoreThanOneChar => { - use unicode_normalization::char::is_combining_mark; use unicode_normalization::UnicodeNormalization; + use unicode_normalization::char::is_combining_mark; let mut sugg = None; let mut note = None; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 788bb732ef722..f7a8b8780edc4 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -18,7 +18,7 @@ use std::path::Path; use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{token, AttrItem, Attribute, MetaItem}; +use rustc_ast::{AttrItem, Attribute, MetaItem, token}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, FatalError, PResult}; @@ -29,7 +29,7 @@ pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); #[macro_use] pub mod parser; -use parser::{make_unclosed_delims_error, Parser}; +use parser::{Parser, make_unclosed_delims_error}; pub mod lexer; pub mod validate_attr; diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 49df2811d525b..8bd615e6d7913 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::{iter, mem}; use rustc_ast::token::{Delimiter, Token, TokenKind}; @@ -6,9 +7,10 @@ use rustc_ast::tokenstream::{ Spacing, ToAttrTokenStream, }; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, HasTokens}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::PResult; use rustc_session::parse::ParseSess; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, sym}; use super::{ Capturing, FlatToken, ForceCollect, NodeRange, NodeReplacement, Parser, ParserRange, @@ -106,7 +108,7 @@ struct LazyAttrTokenStreamImpl { start_token: (Token, Spacing), cursor_snapshot: TokenCursor, num_calls: u32, - break_last_token: bool, + break_last_token: u32, node_replacements: Box<[NodeReplacement]>, } @@ -134,9 +136,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { node_replacements.array_windows() { assert!( - node_range.0.end <= next_node_range.0.start - || node_range.0.end >= next_node_range.0.end, - "Node ranges should be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})", + node_range.0.end <= next_node_range.0.start, + "Node ranges should be disjoint: ({:?}, {:?}) ({:?}, {:?})", node_range, tokens, next_node_range, @@ -144,20 +145,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { ); } - // Process the replace ranges, starting from the highest start - // position and working our way back. If have tokens like: - // - // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` - // - // Then we will generate replace ranges for both - // the `#[cfg(FALSE)] field: bool` and the entire - // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` - // - // By starting processing from the replace range with the greatest - // start position, we ensure that any (outer) replace range which - // encloses another (inner) replace range will fully overwrite the - // inner range's replacement. - for (node_range, target) in node_replacements.into_iter().rev() { + // Process the replace ranges. + for (node_range, target) in node_replacements.into_iter() { assert!( !node_range.0.is_empty(), "Cannot replace an empty node range: {:?}", @@ -234,6 +223,8 @@ impl<'a> Parser<'a> { force_collect: ForceCollect, f: impl FnOnce(&mut Self, AttrVec) -> PResult<'a, (R, Trailing, UsePreAttrPos)>, ) -> PResult<'a, R> { + let possible_capture_mode = self.capture_cfg; + // We must collect if anything could observe the collected tokens, i.e. // if any of the following conditions hold. // - We are force collecting tokens (because force collection requires @@ -244,9 +235,9 @@ impl<'a> Parser<'a> { // - Our target supports custom inner attributes (custom // inner attribute invocation might require token capturing). || R::SUPPORTS_CUSTOM_INNER_ATTRS - // - We are in `capture_cfg` mode (which requires tokens if + // - We are in "possible capture mode" (which requires tokens if // the parsed node has `#[cfg]` or `#[cfg_attr]` attributes). - || self.capture_cfg; + || possible_capture_mode; if !needs_collection { return Ok(f(self, attrs.attrs)?.0); } @@ -267,18 +258,48 @@ impl<'a> Parser<'a> { res? }; - // When we're not in `capture_cfg` mode, then skip collecting and - // return early if either of the following conditions hold. // - `None`: Our target doesn't support tokens at all (e.g. `NtIdent`). + // - `Some(None)`: Our target supports tokens and has none. // - `Some(Some(_))`: Our target already has tokens set (e.g. we've - // parsed something like `#[my_attr] $item`). The actual parsing code - // takes care of prepending any attributes to the nonterminal, so we - // don't need to modify the already captured tokens. + // parsed something like `#[my_attr] $item`). + let ret_can_hold_tokens = matches!(ret.tokens_mut(), Some(None)); + + // Ignore any attributes we've previously processed. This happens when + // an inner call to `collect_tokens` returns an AST node and then an + // outer call ends up with the same AST node without any additional + // wrapping layer. + let mut seen_indices = FxHashSet::default(); + for (i, attr) in ret.attrs().iter().enumerate() { + let is_unseen = self.capture_state.seen_attrs.insert(attr.id); + if !is_unseen { + seen_indices.insert(i); + } + } + let ret_attrs: Cow<'_, [Attribute]> = + if seen_indices.is_empty() { + Cow::Borrowed(ret.attrs()) + } else { + let ret_attrs = + ret.attrs() + .iter() + .enumerate() + .filter_map(|(i, attr)| { + if seen_indices.contains(&i) { None } else { Some(attr.clone()) } + }) + .collect(); + Cow::Owned(ret_attrs) + }; + + // When we're not in "definite capture mode", then skip collecting and + // return early if `ret` doesn't support tokens or already has some. // // Note that this check is independent of `force_collect`. There's no // need to collect tokens when we don't support tokens or already have // tokens. - if !self.capture_cfg && matches!(ret.tokens_mut(), None | Some(Some(_))) { + let definite_capture_mode = self.capture_cfg + && matches!(self.capture_state.capturing, Capturing::Yes) + && has_cfg_or_cfg_attr(&ret_attrs); + if !definite_capture_mode && !ret_can_hold_tokens { return Ok(ret); } @@ -297,12 +318,12 @@ impl<'a> Parser<'a> { // outer and inner attributes. So this check is more precise than // the earlier `needs_tokens` check, and we don't need to // check `R::SUPPORTS_CUSTOM_INNER_ATTRS`.) - || needs_tokens(ret.attrs()) - // - We are in `capture_cfg` mode and there are `#[cfg]` or - // `#[cfg_attr]` attributes. (During normal non-`capture_cfg` - // parsing, we don't need any special capturing for those - // attributes, because they're builtin.) - || (self.capture_cfg && has_cfg_or_cfg_attr(ret.attrs())); + || needs_tokens(&ret_attrs) + // - We are in "definite capture mode", which requires that there + // are `#[cfg]` or `#[cfg_attr]` attributes. (During normal + // non-`capture_cfg` parsing, we don't need any special capturing + // for those attributes, because they're builtin.) + || definite_capture_mode; if !needs_collection { return Ok(ret); } @@ -318,17 +339,20 @@ impl<'a> Parser<'a> { let parser_replacements_end = self.capture_state.parser_replacements.len(); assert!( - !(self.break_last_token && matches!(capture_trailing, Trailing::Yes)), - "Cannot set break_last_token and have trailing token" + !(self.break_last_token > 0 && matches!(capture_trailing, Trailing::Yes)), + "Cannot have break_last_token > 0 and have trailing token" ); + assert!(self.break_last_token <= 2, "cannot break token more than twice"); let end_pos = self.num_bump_calls + capture_trailing as u32 - // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), then - // extend the range of captured tokens to include it, since the parser was not actually - // bumped past it. When the `LazyAttrTokenStream` gets converted into an - // `AttrTokenStream`, we will create the proper token. - + self.break_last_token as u32; + // If we "broke" the last token (e.g. breaking a `>>` token once into `>` + `>`, or + // breaking a `>>=` token twice into `>` + `>` + `=`), then extend the range of + // captured tokens to include it, because the parser was not actually bumped past it. + // (Even if we broke twice, it was still just one token originally, hence the `1`.) + // When the `LazyAttrTokenStream` gets converted into an `AttrTokenStream`, we will + // rebreak that final token once or twice. + + if self.break_last_token == 0 { 0 } else { 1 }; let num_calls = end_pos - collect_pos.start_pos; @@ -336,7 +360,7 @@ impl<'a> Parser<'a> { // `Parser::parse_inner_attributes`, and pair them in a `ParserReplacement` with `None`, // which means the relevant tokens will be removed. (More details below.) let mut inner_attr_parser_replacements = Vec::new(); - for attr in ret.attrs() { + for attr in ret_attrs.iter() { if attr.style == ast::AttrStyle::Inner { if let Some(inner_attr_parser_range) = self.capture_state.inner_attr_parser_ranges.remove(&attr.id) @@ -359,11 +383,10 @@ impl<'a> Parser<'a> { // from `ParserRange` form to `NodeRange` form. We will perform the actual // replacement only when we convert the `LazyAttrTokenStream` to an // `AttrTokenStream`. - self.capture_state.parser_replacements - [parser_replacements_start..parser_replacements_end] - .iter() - .cloned() - .chain(inner_attr_parser_replacements.iter().cloned()) + self.capture_state + .parser_replacements + .drain(parser_replacements_start..parser_replacements_end) + .chain(inner_attr_parser_replacements) .map(|(parser_range, data)| { (NodeRange::new(parser_range, collect_pos.start_pos), data) }) @@ -399,21 +422,13 @@ impl<'a> Parser<'a> { break_last_token: self.break_last_token, node_replacements, }); + let mut tokens_used = false; - // If we support tokens and don't already have them, store the newly captured tokens. - if let Some(target_tokens @ None) = ret.tokens_mut() { - *target_tokens = Some(tokens.clone()); - } - - // If `capture_cfg` is set and we're inside a recursive call to - // `collect_tokens`, then we need to register a replace range if we - // have `#[cfg]` or `#[cfg_attr]`. This allows us to run eager - // cfg-expansion on the captured token stream. - if self.capture_cfg - && matches!(self.capture_state.capturing, Capturing::Yes) - && has_cfg_or_cfg_attr(ret.attrs()) - { - assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); + // If in "definite capture mode" we need to register a replace range + // for the `#[cfg]` and/or `#[cfg_attr]` attrs. This allows us to run + // eager cfg-expansion on the captured token stream. + if definite_capture_mode { + assert!(self.break_last_token == 0, "Should not have unglued last token with cfg attr"); // What is the status here when parsing the example code at the top of this method? // @@ -429,7 +444,9 @@ impl<'a> Parser<'a> { // cfg-expand this AST node. let start_pos = if has_outer_attrs { attrs.start_pos.unwrap() } else { collect_pos.start_pos }; - let target = AttrsTarget { attrs: ret.attrs().iter().cloned().collect(), tokens }; + let target = + AttrsTarget { attrs: ret_attrs.iter().cloned().collect(), tokens: tokens.clone() }; + tokens_used = true; self.capture_state .parser_replacements .push((ParserRange(start_pos..end_pos), Some(target))); @@ -438,7 +455,16 @@ impl<'a> Parser<'a> { // the outermost call to this method. self.capture_state.parser_replacements.clear(); self.capture_state.inner_attr_parser_ranges.clear(); + self.capture_state.seen_attrs.clear(); } + + // If we support tokens and don't already have them, store the newly captured tokens. + if let Some(target_tokens @ None) = ret.tokens_mut() { + tokens_used = true; + *target_tokens = Some(tokens); + } + + assert!(tokens_used); // check we didn't create `tokens` unnecessarily Ok(ret) } } @@ -448,7 +474,7 @@ impl<'a> Parser<'a> { /// close delims. fn make_attr_token_stream( iter: impl Iterator, - break_last_token: bool, + break_last_token: u32, ) -> AttrTokenStream { #[derive(Debug)] struct FrameData { @@ -462,10 +488,10 @@ fn make_attr_token_stream( for flat_token in iter { match flat_token { FlatToken::Token((Token { kind: TokenKind::OpenDelim(delim), span }, spacing)) => { - stack_rest.push(mem::replace( - &mut stack_top, - FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }, - )); + stack_rest.push(mem::replace(&mut stack_top, FrameData { + open_delim_sp: Some((delim, span, spacing)), + inner: vec![], + })); } FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => { let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); @@ -490,18 +516,17 @@ fn make_attr_token_stream( } } - if break_last_token { + if break_last_token > 0 { let last_token = stack_top.inner.pop().unwrap(); if let AttrTokenTree::Token(last_token, spacing) = last_token { - let unglued_first = last_token.kind.break_two_token_op().unwrap().0; + let (unglued, _) = last_token.kind.break_two_token_op(break_last_token).unwrap(); - // An 'unglued' token is always two ASCII characters + // Tokens are always ASCII chars, so we can use byte arithmetic here. let mut first_span = last_token.span.shrink_to_lo(); - first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1)); + first_span = + first_span.with_hi(first_span.lo() + rustc_span::BytePos(break_last_token)); - stack_top - .inner - .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing)); + stack_top.inner.push(AttrTokenTree::Token(Token::new(unglued, first_span), spacing)); } else { panic!("Unexpected last token {last_token:?}") } @@ -510,9 +535,11 @@ fn make_attr_token_stream( } /// Tokens are needed if: -/// - any non-single-segment attributes (other than doc comments) are present; or -/// - any `cfg_attr` attributes are present; -/// - any single-segment, non-builtin attributes are present. +/// - any non-single-segment attributes (other than doc comments) are present, +/// e.g. `rustfmt::skip`; or +/// - any `cfg_attr` attributes are present; or +/// - any single-segment, non-builtin attributes are present, e.g. `derive`, +/// `test`, `global_allocator`. fn needs_tokens(attrs: &[ast::Attribute]) -> bool { attrs.iter().any(|attr| match attr.ident() { None => !attr.is_doc_comment(), diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index fcdc10c0837e5..f32307f6ed4d8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -15,14 +15,15 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, - Subdiagnostic, + Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, Subdiagnostic, + Suggestions, pluralize, }; use rustc_session::errors::ExprParenthesesNeeded; +use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span, SpanSnippetError, Symbol, DUMMY_SP}; -use thin_vec::{thin_vec, ThinVec}; +use rustc_span::symbol::{AllKeywords, Ident, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span, SpanSnippetError, Symbol}; +use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, trace}; use super::pat::Expected; @@ -203,6 +204,37 @@ impl std::fmt::Display for UnaryFixity { } } +#[derive(Debug, rustc_macros::Subdiagnostic)] +#[suggestion( + parse_misspelled_kw, + applicability = "machine-applicable", + code = "{similar_kw}", + style = "verbose" +)] +struct MisspelledKw { + similar_kw: String, + #[primary_span] + span: Span, + is_incorrect_case: bool, +} + +/// Checks if the given `lookup` identifier is similar to any keyword symbol in `candidates`. +fn find_similar_kw(lookup: Ident, candidates: &[Symbol]) -> Option { + let lowercase = lookup.name.as_str().to_lowercase(); + let lowercase_sym = Symbol::intern(&lowercase); + if candidates.contains(&lowercase_sym) { + Some(MisspelledKw { similar_kw: lowercase, span: lookup.span, is_incorrect_case: true }) + } else if let Some(similar_sym) = find_best_match_for_name(candidates, lookup.name, None) { + Some(MisspelledKw { + similar_kw: similar_sym.to_string(), + span: lookup.span, + is_incorrect_case: false, + }) + } else { + None + } +} + struct MultiSugg { msg: String, patches: Vec<(Span, String)>, @@ -638,9 +670,9 @@ impl<'a> Parser<'a> { let concat = Symbol::intern(&format!("{prev}{cur}")); let ident = Ident::new(concat, DUMMY_SP); if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { - let span = self.prev_token.span.to(self.token.span); + let concat_span = self.prev_token.span.to(self.token.span); err.span_suggestion_verbose( - span, + concat_span, format!("consider removing the space to spell keyword `{concat}`"), concat, Applicability::MachineApplicable, @@ -689,15 +721,12 @@ impl<'a> Parser<'a> { let span = self.token.span.with_lo(pos).with_hi(pos); err.span_suggestion_verbose( span, - format!( - "add a space before {} to write a regular comment", - match (kind, style) { - (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`", - (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`", - (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`", - (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`", - }, - ), + format!("add a space before {} to write a regular comment", match (kind, style) { + (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`", + (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`", + (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`", + (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`", + },), " ".to_string(), Applicability::MachineApplicable, ); @@ -741,9 +770,61 @@ impl<'a> Parser<'a> { err.span_label(sp, label_exp); err.span_label(self.token.span, "unexpected token"); } + + // Check for misspelled keywords if there are no suggestions added to the diagnostic. + if matches!(&err.suggestions, Suggestions::Enabled(list) if list.is_empty()) { + self.check_for_misspelled_kw(&mut err, &expected); + } Err(err) } + /// Checks if the current token or the previous token are misspelled keywords + /// and adds a helpful suggestion. + fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) { + let Some((curr_ident, _)) = self.token.ident() else { + return; + }; + let expected_tokens: &[TokenType] = + expected.len().checked_sub(10).map_or(&expected, |index| &expected[index..]); + let expected_keywords: Vec = expected_tokens + .iter() + .filter_map(|token| if let TokenType::Keyword(kw) = token { Some(*kw) } else { None }) + .collect(); + + // When there are a few keywords in the last ten elements of `self.expected_tokens` and the current + // token is an identifier, it's probably a misspelled keyword. + // This handles code like `async Move {}`, misspelled `if` in match guard, misspelled `else` in `if`-`else` + // and mispelled `where` in a where clause. + if !expected_keywords.is_empty() + && !curr_ident.is_used_keyword() + && let Some(misspelled_kw) = find_similar_kw(curr_ident, &expected_keywords) + { + err.subdiagnostic(misspelled_kw); + // We don't want other suggestions to be added as they are most likely meaningless + // when there is a misspelled keyword. + err.seal_suggestions(); + } else if let Some((prev_ident, _)) = self.prev_token.ident() + && !prev_ident.is_used_keyword() + { + // We generate a list of all keywords at runtime rather than at compile time + // so that it gets generated only when the diagnostic needs it. + // Also, it is unlikely that this list is generated multiple times because the + // parser halts after execution hits this path. + let all_keywords = AllKeywords::new().collect_used(|| prev_ident.span.edition()); + + // Otherwise, check the previous token with all the keywords as possible candidates. + // This handles code like `Struct Human;` and `While a < b {}`. + // We check the previous token only when the current token is an identifier to avoid false + // positives like suggesting keyword `for` for `extern crate foo {}`. + if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) { + err.subdiagnostic(misspelled_kw); + // We don't want other suggestions to be added as they are most likely meaningless + // when there is a misspelled keyword. + err.seal_suggestions(); + } + } + } + /// The user has written `#[attr] expr` which is unsupported. (#106020) pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed { // Missing semicolon typo error. @@ -846,6 +927,7 @@ impl<'a> Parser<'a> { ); } } + err.emit() } @@ -1851,14 +1933,13 @@ impl<'a> Parser<'a> { (token::Eof, None) => (self.prev_token.span, self.token.span), _ => (self.prev_token.span.shrink_to_hi(), self.token.span), }; - let msg = format!( - "expected `{}`, found {}", - token_str, - match (&self.token.kind, self.subparser_name) { - (token::Eof, Some(origin)) => format!("end of {origin}"), - _ => this_token_str, - }, - ); + let msg = format!("expected `{}`, found {}", token_str, match ( + &self.token.kind, + self.subparser_name + ) { + (token::Eof, Some(origin)) => format!("end of {origin}"), + _ => this_token_str, + },); let mut err = self.dcx().struct_span_err(sp, msg); let label_exp = format!("expected `{token_str}`"); let sm = self.psess.source_map(); @@ -2474,7 +2555,7 @@ impl<'a> Parser<'a> { err.delay_as_bug(); } } - return Ok(false); // Don't continue. + Ok(false) // Don't continue. } /// Attempt to parse a generic const argument that has not been enclosed in braces. @@ -2779,27 +2860,25 @@ impl<'a> Parser<'a> { PatKind::Ident(BindingMode::NONE, ident, None) => { match &first_pat.kind { PatKind::Ident(_, old_ident, _) => { - let path = PatKind::Path( - None, - Path { - span: new_span, - segments: thin_vec![ - PathSegment::from_ident(*old_ident), - PathSegment::from_ident(*ident), - ], - tokens: None, - }, - ); + let path = PatKind::Path(None, Path { + span: new_span, + segments: thin_vec![ + PathSegment::from_ident(*old_ident), + PathSegment::from_ident(*ident), + ], + tokens: None, + }); first_pat = self.mk_pat(new_span, path); show_sugg = true; } PatKind::Path(old_qself, old_path) => { let mut segments = old_path.segments.clone(); segments.push(PathSegment::from_ident(*ident)); - let path = PatKind::Path( - old_qself.clone(), - Path { span: new_span, segments, tokens: None }, - ); + let path = PatKind::Path(old_qself.clone(), Path { + span: new_span, + segments, + tokens: None, + }); first_pat = self.mk_pat(new_span, path); show_sugg = true; } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 84684e808d940..0ac6133e8289f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -10,25 +10,25 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::util::classify; -use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; -use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; +use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{ self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, - ClosureBinder, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall, MetaItemLit, - Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, DUMMY_NODE_ID, + ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall, + MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, }; use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; use rustc_lexer::unescape::unescape_char; use rustc_macros::Subdiagnostic; -use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; -use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; +use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error}; use rustc_session::lint::BuiltinLintDiag; +use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_span::source_map::{self, Spanned}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{BytePos, ErrorGuaranteed, Pos, Span}; -use thin_vec::{thin_vec, ThinVec}; +use thin_vec::{ThinVec, thin_vec}; use tracing::instrument; use super::diagnostics::SnapshotParser; @@ -41,7 +41,7 @@ use super::{ use crate::{errors, maybe_recover_from_interpolated_ty_qpath}; #[derive(Debug)] -enum DestructuredFloat { +pub(super) enum DestructuredFloat { /// 1e2 Single(Symbol, Span), /// 1. @@ -49,7 +49,7 @@ enum DestructuredFloat { /// 1.2 | 1.2e3 MiddleDot(Symbol, Span, Span, Symbol, Span), /// Invalid - Error, + Error(ErrorGuaranteed), } impl<'a> Parser<'a> { @@ -811,20 +811,17 @@ impl<'a> Parser<'a> { // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, it is an illegal postfix operator. if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) { - let msg = format!( - "cast cannot be followed by {}", - match with_postfix.kind { - ExprKind::Index(..) => "indexing", - ExprKind::Try(_) => "`?`", - ExprKind::Field(_, _) => "a field access", - ExprKind::MethodCall(_) => "a method call", - ExprKind::Call(_, _) => "a function call", - ExprKind::Await(_, _) => "`.await`", - ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match", - ExprKind::Err(_) => return Ok(with_postfix), - _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), - } - ); + let msg = format!("cast cannot be followed by {}", match with_postfix.kind { + ExprKind::Index(..) => "indexing", + ExprKind::Try(_) => "`?`", + ExprKind::Field(_, _) => "a field access", + ExprKind::MethodCall(_) => "a method call", + ExprKind::Call(_, _) => "a function call", + ExprKind::Await(_, _) => "`.await`", + ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match", + ExprKind::Err(_) => return Ok(with_postfix), + _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), + }); let mut err = self.dcx().struct_span_err(span, msg); let suggest_parens = |err: &mut Diag<'_>| { @@ -1008,7 +1005,7 @@ impl<'a> Parser<'a> { self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None); self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix) } - DestructuredFloat::Error => base, + DestructuredFloat::Error(_) => base, }) } _ => { @@ -1018,7 +1015,7 @@ impl<'a> Parser<'a> { } } - fn error_unexpected_after_dot(&self) { + fn error_unexpected_after_dot(&self) -> ErrorGuaranteed { let actual = pprust::token_to_string(&self.token); let span = self.token.span; let sm = self.psess.source_map(); @@ -1028,18 +1025,20 @@ impl<'a> Parser<'a> { } _ => (span, actual), }; - self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual }); + self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual }) } - // We need an identifier or integer, but the next token is a float. - // Break the float into components to extract the identifier or integer. + /// We need an identifier or integer, but the next token is a float. + /// Break the float into components to extract the identifier or integer. + /// + /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`. + // // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2 - // parts unless those parts are processed immediately. `TokenCursor` should either - // support pushing "future tokens" (would be also helpful to `break_and_eat`), or - // we should break everything including floats into more basic proc-macro style - // tokens in the lexer (probably preferable). - // See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`. - fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat { + // parts unless those parts are processed immediately. `TokenCursor` should either + // support pushing "future tokens" (would be also helpful to `break_and_eat`), or + // we should break everything including floats into more basic proc-macro style + // tokens in the lexer (probably preferable). + pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat { #[derive(Debug)] enum FloatComponent { IdentLike(String), @@ -1078,34 +1077,30 @@ impl<'a> Parser<'a> { DestructuredFloat::Single(Symbol::intern(i), span) } // 1. - [IdentLike(i), Punct('.')] => { - let (ident_span, dot_span) = if can_take_span_apart() { - let (span, ident_len) = (span.data(), BytePos::from_usize(i.len())); - let ident_span = span.with_hi(span.lo + ident_len); - let dot_span = span.with_lo(span.lo + ident_len); - (ident_span, dot_span) + [IdentLike(left), Punct('.')] => { + let (left_span, dot_span) = if can_take_span_apart() { + let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len())); + let dot_span = span.with_lo(left_span.hi()); + (left_span, dot_span) } else { (span, span) }; - let symbol = Symbol::intern(i); - DestructuredFloat::TrailingDot(symbol, ident_span, dot_span) + let left = Symbol::intern(left); + DestructuredFloat::TrailingDot(left, left_span, dot_span) } // 1.2 | 1.2e3 - [IdentLike(i1), Punct('.'), IdentLike(i2)] => { - let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() { - let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len())); - let ident1_span = span.with_hi(span.lo + ident1_len); - let dot_span = span - .with_lo(span.lo + ident1_len) - .with_hi(span.lo + ident1_len + BytePos(1)); - let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1)); - (ident1_span, dot_span, ident2_span) + [IdentLike(left), Punct('.'), IdentLike(right)] => { + let (left_span, dot_span, right_span) = if can_take_span_apart() { + let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len())); + let dot_span = span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1)); + let right_span = span.with_lo(dot_span.hi()); + (left_span, dot_span, right_span) } else { (span, span, span) }; - let symbol1 = Symbol::intern(i1); - let symbol2 = Symbol::intern(i2); - DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) + let left = Symbol::intern(left); + let right = Symbol::intern(right); + DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span) } // 1e+ | 1e- (recovered) [IdentLike(_), Punct('+' | '-')] | @@ -1116,8 +1111,8 @@ impl<'a> Parser<'a> { // 1.2e+3 | 1.2e-3 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => { // See the FIXME about `TokenCursor` above. - self.error_unexpected_after_dot(); - DestructuredFloat::Error + let guar = self.error_unexpected_after_dot(); + DestructuredFloat::Error(guar) } _ => panic!("unexpected components in a float token: {components:?}"), } @@ -1183,7 +1178,7 @@ impl<'a> Parser<'a> { fields.insert(start_idx, Ident::new(symbol2, span2)); fields.insert(start_idx, Ident::new(symbol1, span1)); } - DestructuredFloat::Error => { + DestructuredFloat::Error(_) => { trailing_dot = None; fields.insert(start_idx, Ident::new(symbol, self.prev_token.span)); } @@ -2050,7 +2045,7 @@ impl<'a> Parser<'a> { }; // On an error path, eagerly consider a lifetime to be an unclosed character lit, if that // makes sense. - if let Some(ident) = self.token.lifetime() + if let Some((ident, IdentIsRaw::No)) = self.token.lifetime() && could_be_unclosed_char_literal(ident) { let lt = self.expect_lifetime(); @@ -2554,13 +2549,12 @@ impl<'a> Parser<'a> { let maybe_fatarrow = self.token.clone(); let block = if self.check(&token::OpenDelim(Delimiter::Brace)) { self.parse_block()? + } else if let Some(block) = recover_block_from_condition(self) { + block } else { - if let Some(block) = recover_block_from_condition(self) { - block - } else { - self.error_on_extra_if(&cond)?; - // Parse block, which will always fail, but we can add a nice note to the error - self.parse_block().map_err(|mut err| { + self.error_on_extra_if(&cond)?; + // Parse block, which will always fail, but we can add a nice note to the error + self.parse_block().map_err(|mut err| { if self.prev_token == token::Semi && self.token == token::AndAnd && let maybe_let = self.look_ahead(1, |t| t.clone()) @@ -2592,7 +2586,6 @@ impl<'a> Parser<'a> { } err })? - } }; self.error_on_if_block_attrs(lo, false, block.span, attrs); block @@ -2848,10 +2841,13 @@ impl<'a> Parser<'a> { .emit_err(errors::MissingExpressionInForLoop { span: expr.span.shrink_to_lo() }); let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar)); let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span); - return Ok(self.mk_expr( - lo.to(self.prev_token.span), - ExprKind::ForLoop { pat, iter: err_expr, body: block, label: opt_label, kind }, - )); + return Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::ForLoop { + pat, + iter: err_expr, + body: block, + label: opt_label, + kind, + })); } let (attrs, loop_block) = self.parse_inner_attrs_and_block()?; @@ -2925,9 +2921,9 @@ impl<'a> Parser<'a> { } pub(crate) fn eat_label(&mut self) -> Option { count: usize, - // Invariant: has been dropped iff count == 0. - element: ManuallyDrop, + // Invariant: uninit iff count == 0. + element: MaybeUninit, } impl RepeatN { + /// Returns the element if it hasn't been dropped already. + fn element_ref(&self) -> Option<&A> { + if self.count > 0 { + // SAFETY: The count is non-zero, so it must be initialized. + Some(unsafe { self.element.assume_init_ref() }) + } else { + None + } + } /// If we haven't already dropped the element, return it in an option. /// /// Clears the count so it won't be dropped again later. @@ -90,23 +97,44 @@ impl RepeatN { fn take_element(&mut self) -> Option { if self.count > 0 { self.count = 0; + let element = mem::replace(&mut self.element, MaybeUninit::uninit()); // SAFETY: We just set count to zero so it won't be dropped again, // and it used to be non-zero so it hasn't already been dropped. - unsafe { Some(ManuallyDrop::take(&mut self.element)) } + unsafe { Some(element.assume_init()) } } else { None } } } -#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_repeat_n", since = "1.82.0")] +impl Clone for RepeatN { + fn clone(&self) -> RepeatN { + RepeatN { + count: self.count, + element: self.element_ref().cloned().map_or_else(MaybeUninit::uninit, MaybeUninit::new), + } + } +} + +#[stable(feature = "iter_repeat_n", since = "1.82.0")] +impl fmt::Debug for RepeatN { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RepeatN") + .field("count", &self.count) + .field("element", &self.element_ref()) + .finish() + } +} + +#[stable(feature = "iter_repeat_n", since = "1.82.0")] impl Drop for RepeatN { fn drop(&mut self) { self.take_element(); } } -#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_repeat_n", since = "1.82.0")] impl Iterator for RepeatN { type Item = A; @@ -154,14 +182,14 @@ impl Iterator for RepeatN { } } -#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_repeat_n", since = "1.82.0")] impl ExactSizeIterator for RepeatN { fn len(&self) -> usize { self.count } } -#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_repeat_n", since = "1.82.0")] impl DoubleEndedIterator for RepeatN { #[inline] fn next_back(&mut self) -> Option { @@ -179,12 +207,12 @@ impl DoubleEndedIterator for RepeatN { } } -#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_repeat_n", since = "1.82.0")] impl FusedIterator for RepeatN {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for RepeatN {} -#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_repeat_n", since = "1.82.0")] impl UncheckedIterator for RepeatN { #[inline] unsafe fn next_unchecked(&mut self) -> Self::Item { @@ -194,9 +222,11 @@ impl UncheckedIterator for RepeatN { // SAFETY: the check above ensured that the count used to be non-zero, // so element hasn't been dropped yet, and we just lowered the count to // zero so it won't be dropped later, and thus it's okay to take it here. - unsafe { ManuallyDrop::take(&mut self.element) } + unsafe { mem::replace(&mut self.element, MaybeUninit::uninit()).assume_init() } } else { - A::clone(&self.element) + // SAFETY: the count is non-zero, so it must have not been dropped yet. + let element = unsafe { self.element.assume_init_ref() }; + A::clone(element) } } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 50a2d952e5b36..7963459bfb5d9 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,8 +1,8 @@ use super::super::{ - try_process, ArrayChunks, ByRefSized, Chain, Cloned, Copied, Cycle, Enumerate, Filter, - FilterMap, FlatMap, Flatten, Fuse, Inspect, Intersperse, IntersperseWith, Map, MapWhile, - MapWindows, Peekable, Product, Rev, Scan, Skip, SkipWhile, StepBy, Sum, Take, TakeWhile, - TrustedRandomAccessNoCoerce, Zip, + ArrayChunks, ByRefSized, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, FlatMap, + Flatten, Fuse, Inspect, Intersperse, IntersperseWith, Map, MapWhile, MapWindows, Peekable, + Product, Rev, Scan, Skip, SkipWhile, StepBy, Sum, Take, TakeWhile, TrustedRandomAccessNoCoerce, + Zip, try_process, }; use crate::array; use crate::cmp::{self, Ordering}; @@ -876,6 +876,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_do_not_const_check] + #[cfg_attr(not(test), rustc_diagnostic_item = "iter_filter")] fn filter

(self, predicate: P) -> Filter where Self: Sized, @@ -3412,6 +3413,7 @@ pub trait Iterator { /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] #[rustc_do_not_const_check] + #[cfg_attr(not(test), rustc_diagnostic_item = "iter_copied")] fn copied<'a, T: 'a>(self) -> Copied where Self: Sized + Iterator, @@ -3460,6 +3462,7 @@ pub trait Iterator { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_do_not_const_check] + #[cfg_attr(not(test), rustc_diagnostic_item = "iter_cloned")] fn cloned<'a, T: 'a>(self) -> Cloned where Self: Sized + Iterator, @@ -3953,7 +3956,7 @@ pub trait Iterator { /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted()); /// ``` #[inline] - #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "is_sorted", since = "1.82.0")] #[rustc_do_not_const_check] fn is_sorted(self) -> bool where @@ -3980,7 +3983,7 @@ pub trait Iterator { /// assert!(std::iter::empty::().is_sorted_by(|a, b| false)); /// assert!(std::iter::empty::().is_sorted_by(|a, b| true)); /// ``` - #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "is_sorted", since = "1.82.0")] #[rustc_do_not_const_check] fn is_sorted_by(mut self, compare: F) -> bool where @@ -4025,7 +4028,7 @@ pub trait Iterator { /// assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); /// ``` #[inline] - #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "is_sorted", since = "1.82.0")] #[rustc_do_not_const_check] fn is_sorted_by_key(self, f: F) -> bool where diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e60bcf3aa5db7..01cadd78cc09d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,7 +107,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(offset_of_nested))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_align_of_val)] @@ -120,20 +119,20 @@ #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] #![feature(const_cell_into_inner)] +#![feature(const_char_encode_utf16)] +#![feature(const_char_encode_utf8)] #![feature(const_eval_select)] #![feature(const_exact_div)] -#![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] #![feature(const_index_range_slice_index)] -#![feature(const_intrinsic_copy)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] #![feature(const_ipv6)] #![feature(const_likely)] -#![feature(const_maybe_uninit_as_mut_ptr)] +#![feature(const_make_ascii)] #![feature(const_maybe_uninit_assume_init)] #![feature(const_nonnull_new)] #![feature(const_num_midpoint)] @@ -151,8 +150,8 @@ #![feature(const_size_of_val_raw)] #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_from_ref)] -#![feature(const_slice_index)] #![feature(const_slice_split_at_mut)] +#![feature(const_str_as_mut)] #![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_strict_overflow_ops)] #![feature(const_swap)] @@ -166,11 +165,14 @@ #![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(duration_consts_float)] +#![feature(f128_const)] +#![feature(f16_const)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] #![feature(is_val_statically_known)] #![feature(isqrt)] +#![feature(lazy_get)] #![feature(link_cfg)] #![feature(offset_of_enum)] #![feature(panic_internals)] @@ -192,9 +194,8 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(asm_const))] -#![cfg_attr(bootstrap, feature(const_fn_floating_point_arithmetic))] -#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))] +#![cfg_attr(bootstrap, feature(const_mut_refs))] +#![cfg_attr(bootstrap, feature(const_refs_to_cell))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] @@ -205,9 +206,7 @@ #![feature(cfg_target_has_atomic_equal_alignment)] #![feature(cfg_ub_checks)] #![feature(const_for)] -#![feature(const_mut_refs)] #![feature(const_precise_live_drops)] -#![feature(const_refs_to_cell)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] @@ -396,6 +395,8 @@ pub mod panicking; #[unstable(feature = "core_pattern_types", issue = "123646")] pub mod pat; pub mod pin; +#[unstable(feature = "random", issue = "130703")] +pub mod random; #[unstable(feature = "new_range_api", issue = "125687")] pub mod range; pub mod result; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index ac51a40d9f478..888832251f6da 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1072,7 +1072,7 @@ pub(crate) mod builtin { /// If the environment variable is not defined, then a compilation error /// will be emitted. To not emit a compile error, use the [`option_env!`] /// macro instead. A compilation error will also be emitted if the - /// environment variable is not a vaild Unicode string. + /// environment variable is not a valid Unicode string. /// /// # Examples /// diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 5654f5aa4b8d2..fd41b80cdbd0a 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -288,8 +288,19 @@ marker_impls! { /// } /// ``` /// -/// There is a small difference between the two: the `derive` strategy will also place a `Copy` -/// bound on type parameters, which isn't always desired. +/// There is a small difference between the two. The `derive` strategy will also place a `Copy` +/// bound on type parameters: +/// +/// ``` +/// #[derive(Clone)] +/// struct MyStruct(T); +/// +/// impl Copy for MyStruct { } +/// ``` +/// +/// This isn't always desired. For example, shared references (`&T`) can be copied regardless of +/// whether `T` is `Copy`. Likewise, a generic struct containing markers such as [`PhantomData`] +/// could potentially be duplicated with a bit-wise copy. /// /// ## What's the difference between `Copy` and `Clone`? /// @@ -992,7 +1003,7 @@ pub macro ConstParamTy($item:item) { /* compiler built-in */ } -#[cfg_attr(not(bootstrap), lang = "unsized_const_param_ty")] +#[lang = "unsized_const_param_ty"] #[unstable(feature = "unsized_const_params", issue = "95174")] #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] /// A marker for types which can be used as types of `const` generic parameters. @@ -1002,10 +1013,9 @@ pub macro ConstParamTy($item:item) { pub trait UnsizedConstParamTy: StructuralPartialEq + Eq {} /// Derive macro generating an impl of the trait `ConstParamTy`. -#[cfg(not(bootstrap))] -#[cfg_attr(not(bootstrap), rustc_builtin_macro)] -#[cfg_attr(not(bootstrap), allow_internal_unstable(unsized_const_params))] -#[cfg_attr(not(bootstrap), unstable(feature = "unsized_const_params", issue = "95174"))] +#[rustc_builtin_macro] +#[allow_internal_unstable(unsized_const_params)] +#[unstable(feature = "unsized_const_params", issue = "95174")] pub macro UnsizedConstParamTy($item:item) { /* compiler built-in */ } @@ -1021,14 +1031,6 @@ marker_impls! { (), {T: ConstParamTy_, const N: usize} [T; N], } -#[cfg(bootstrap)] -marker_impls! { - #[unstable(feature = "adt_const_params", issue = "95174")] - ConstParamTy_ for - str, - {T: ConstParamTy_} [T], - {T: ConstParamTy_ + ?Sized} &T, -} marker_impls! { #[unstable(feature = "unsized_const_params", issue = "95174")] diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index be5cee2e85267..3e47785ee488e 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -47,7 +47,7 @@ use crate::ptr; #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] -#[cfg_attr(not(bootstrap), rustc_pub_transparent)] +#[rustc_pub_transparent] pub struct ManuallyDrop { value: T, } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index c308def2f574a..c67796ad3db83 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -237,7 +237,7 @@ use crate::{fmt, intrinsics, ptr, slice}; #[lang = "maybe_uninit"] #[derive(Copy)] #[repr(transparent)] -#[cfg_attr(not(bootstrap), rustc_pub_transparent)] +#[rustc_pub_transparent] pub union MaybeUninit { uninit: (), value: ManuallyDrop, @@ -351,6 +351,9 @@ impl MaybeUninit { /// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not /// be null. /// + /// Note that if `T` has padding bytes, those bytes are *not* preserved when the + /// `MaybeUninit` value is returned from this function, so those bytes will *not* be zeroed. + /// /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. /// It is your responsibility to make sure `T` gets dropped if it got initialized. /// @@ -390,7 +393,6 @@ impl MaybeUninit { // These are OK to allow since we do not leak &mut to user-visible API #[rustc_allow_const_fn_unstable(const_mut_refs)] #[rustc_allow_const_fn_unstable(const_ptr_write)] - #[rustc_allow_const_fn_unstable(const_maybe_uninit_as_mut_ptr)] #[rustc_const_stable(feature = "const_maybe_uninit_zeroed", since = "1.75.0")] pub const fn zeroed() -> MaybeUninit { let mut u = MaybeUninit::::uninit(); @@ -567,7 +569,11 @@ impl MaybeUninit { /// (Notice that the rules around references to uninitialized data are not finalized yet, but /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_maybe_uninit_as_mut_ptr", issue = "75251")] + #[rustc_const_stable( + feature = "const_maybe_uninit_as_mut_ptr", + since = "CURRENT_RUSTC_VERSION" + )] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index fed484ae3cd12..414262fcf5ab1 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1326,7 +1326,6 @@ impl SizedTypeProperties for T {} /// # Examples /// /// ``` -/// # #![cfg_attr(bootstrap, feature(offset_of_nested))] /// #![feature(offset_of_enum)] /// /// use std::mem; diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 049b32ede9c3d..7fa3c33439170 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -43,8 +43,7 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; /// conversions that extend the bits of `Src` with trailing padding to fill /// trailing uninitialized bytes of `Self`; e.g.: /// -#[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] -#[cfg_attr(not(bootstrap), doc = "```rust")] +/// ```rust /// #![feature(transmutability)] /// /// use core::mem::{Assume, TransmuteFrom}; @@ -149,10 +148,9 @@ where #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Assume { /// When `false`, [`TransmuteFrom`] is not implemented for transmutations - /// that might violate the the alignment requirements of references; e.g.: + /// that might violate the alignment requirements of references; e.g.: /// - #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] - #[cfg_attr(not(bootstrap), doc = "```compile_fail,E0277")] + /// ```compile_fail,E0277 /// #![feature(transmutability)] /// use core::mem::{align_of, TransmuteFrom}; /// @@ -171,8 +169,7 @@ pub struct Assume { /// that references in the transmuted value satisfy the alignment /// requirements of their referent types; e.g.: /// - #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] - #[cfg_attr(not(bootstrap), doc = "```rust")] + /// ```rust /// #![feature(pointer_is_aligned_to, transmutability)] /// use core::mem::{align_of, Assume, TransmuteFrom}; /// @@ -203,8 +200,7 @@ pub struct Assume { /// that might violate the library safety invariants of the destination /// type; e.g.: /// - #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] - #[cfg_attr(not(bootstrap), doc = "```compile_fail,E0277")] + /// ```compile_fail,E0277 /// #![feature(transmutability)] /// use core::mem::TransmuteFrom; /// @@ -225,8 +221,7 @@ pub struct Assume { /// that undefined behavior does not arise from using the transmuted value; /// e.g.: /// - #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] - #[cfg_attr(not(bootstrap), doc = "```rust")] + /// ```rust /// #![feature(transmutability)] /// use core::mem::{Assume, TransmuteFrom}; /// @@ -254,8 +249,7 @@ pub struct Assume { /// that might violate the language-level bit-validity invariant of the /// destination type; e.g.: /// - #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] - #[cfg_attr(not(bootstrap), doc = "```compile_fail,E0277")] + /// ```compile_fail,E0277 /// #![feature(transmutability)] /// use core::mem::TransmuteFrom; /// @@ -271,8 +265,7 @@ pub struct Assume { /// that the value being transmuted is a bit-valid instance of the /// transmuted value; e.g.: /// - #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] - #[cfg_attr(not(bootstrap), doc = "```rust")] + /// ```rust /// #![feature(transmutability)] /// use core::mem::{Assume, TransmuteFrom}; /// @@ -335,9 +328,7 @@ impl Assume { /// This is especially useful for extending [`Assume`] in generic contexts; /// e.g.: /// - #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] - #[cfg_attr(not(bootstrap), doc = "```rust")] - #[unstable(feature = "transmutability", issue = "99571")] + /// ```rust /// #![feature( /// adt_const_params, /// generic_const_exprs, @@ -379,6 +370,7 @@ impl Assume { /// try_transmute_ref::<_, _, { Assume::NOTHING }>(src) /// }; ///``` + #[unstable(feature = "transmutability", issue = "99571")] pub const fn and(self, other_assumptions: Self) -> Self { Self { alignment: self.alignment || other_assumptions.alignment, @@ -390,8 +382,7 @@ impl Assume { /// Remove `other_assumptions` the obligations of `self`; e.g.: /// - #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")] - #[cfg_attr(not(bootstrap), doc = "```rust")] + /// ```rust /// #![feature(transmutability)] /// use core::mem::Assume; /// diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs index 350f64bb4f7a3..be9c0eccd5eb8 100644 --- a/library/core/src/num/dec2flt/decimal.rs +++ b/library/core/src/num/dec2flt/decimal.rs @@ -9,7 +9,7 @@ //! algorithm can be found in "ParseNumberF64 by Simple Decimal Conversion", //! available online: . -use crate::num::dec2flt::common::{is_8digits, ByteSlice}; +use crate::num::dec2flt::common::{ByteSlice, is_8digits}; #[derive(Clone)] pub struct Decimal { diff --git a/library/core/src/num/dec2flt/parse.rs b/library/core/src/num/dec2flt/parse.rs index 975bb8ad6bc1f..06ee8e95fbc47 100644 --- a/library/core/src/num/dec2flt/parse.rs +++ b/library/core/src/num/dec2flt/parse.rs @@ -1,6 +1,6 @@ //! Functions to parse floating-point numbers. -use crate::num::dec2flt::common::{is_8digits, ByteSlice}; +use crate::num::dec2flt::common::{ByteSlice, is_8digits}; use crate::num::dec2flt::float::RawFloat; use crate::num::dec2flt::number::Number; diff --git a/library/core/src/num/dec2flt/slow.rs b/library/core/src/num/dec2flt/slow.rs index bf1044033e69e..85d4b13284b7d 100644 --- a/library/core/src/num/dec2flt/slow.rs +++ b/library/core/src/num/dec2flt/slow.rs @@ -1,7 +1,7 @@ //! Slow, fallback algorithm for cases the Eisel-Lemire algorithm cannot round. use crate::num::dec2flt::common::BiasedFp; -use crate::num::dec2flt::decimal::{parse_decimal, Decimal}; +use crate::num::dec2flt::decimal::{Decimal, parse_decimal}; use crate::num::dec2flt::float::RawFloat; /// Parse the significant digits and biased, binary exponent of a float. diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index b8e22a8aef955..6ef2fdd14c149 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -113,7 +113,7 @@ pub enum IntErrorKind { impl ParseIntError { /// Outputs the detailed cause of parsing an integer failing. #[must_use] - #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] #[stable(feature = "int_error_matching", since = "1.55.0")] pub const fn kind(&self) -> &IntErrorKind { &self.kind diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index d4236e47bfe3b..100271fa54c1f 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -439,10 +439,6 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] pub const fn classify(self) -> FpCategory { - // Other float types suffer from various platform bugs that violate the usual IEEE semantics - // and also make bitwise classification not always work reliably. However, `f128` cannot fit - // into any other float types so this is not a concern, and we can rely on bit patterns. - let bits = self.to_bits(); match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) { (0, Self::EXP_MASK) => FpCategory::Infinite, @@ -914,7 +910,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u128 { // SAFETY: `u128` is a plain old datatype so we can always transmute to it. @@ -963,7 +959,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] pub const fn from_bits(v: u128) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u128` is a plain old datatype so we can always transmute from it. @@ -990,7 +986,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 16] { self.to_bits().to_be_bytes() @@ -1016,7 +1012,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 16] { self.to_bits().to_le_bytes() @@ -1053,7 +1049,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 16] { self.to_bits().to_ne_bytes() @@ -1081,7 +1077,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_be_bytes(bytes)) } @@ -1108,7 +1104,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_le_bytes(bytes)) } @@ -1145,7 +1141,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 1e2f841aca733..6bdc569df28bd 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -424,42 +424,13 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] pub const fn classify(self) -> FpCategory { - // A previous implementation for f32/f64 tried to only use bitmask-based checks, - // using `to_bits` to transmute the float to its bit repr and match on that. - // If we only cared about being "technically" correct, that's an entirely legit - // implementation. - // - // Unfortunately, there are platforms out there that do not correctly implement the IEEE - // float semantics Rust relies on: some hardware flushes denormals to zero, and some - // platforms convert to `f32` to perform operations without properly rounding back (e.g. - // WASM, see llvm/llvm-project#96437). These are platforms bugs, and Rust will misbehave on - // such platforms, but we can at least try to make things seem as sane as possible by being - // careful here. - if self.is_infinite() { - // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask. - FpCategory::Infinite - } else if self.is_nan() { - // And it may not be NaN, as it can simply be an "overextended" finite value. - FpCategory::Nan - } else { - // However, std can't simply compare to zero to check for zero, either, - // as correctness requires avoiding equality tests that may be Subnormal == -0.0 - // because it may be wrong under "denormals are zero" and "flush to zero" modes. - // Most of std's targets don't use those, but they are used for thumbv7neon. - // So, this does use bitpattern matching for the rest. On x87, due to the incorrect - // float codegen on this hardware, this doesn't actually return a right answer for NaN - // because it cannot correctly discern between a floating point NaN, and some normal - // floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so - // we are fine. - // FIXME(jubilee): This probably could at least answer things correctly for Infinity, - // like the f64 version does, but I need to run more checks on how things go on x86. - // I fear losing mantissa data that would have answered that differently. - let b = self.to_bits(); - match (b & Self::MAN_MASK, b & Self::EXP_MASK) { - (0, 0) => FpCategory::Zero, - (_, 0) => FpCategory::Subnormal, - _ => FpCategory::Normal, - } + let b = self.to_bits(); + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (_, Self::EXP_MASK) => FpCategory::Nan, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, } } @@ -925,7 +896,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u16 { // SAFETY: `u16` is a plain old datatype so we can always transmute to it. @@ -973,7 +944,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] pub const fn from_bits(v: u16) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u16` is a plain old datatype so we can always transmute from it. @@ -999,7 +970,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() @@ -1024,7 +995,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() @@ -1062,7 +1033,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() @@ -1086,7 +1057,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } @@ -1109,7 +1080,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } @@ -1143,7 +1114,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index c1adcc753f2e5..d0eb6bb3f2879 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -415,6 +415,7 @@ impl f32 { /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f32::MANTISSA_DIGITS #[stable(feature = "assoc_int_consts", since = "1.43.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "f32_epsilon")] pub const EPSILON: f32 = 1.19209290e-07_f32; /// Smallest finite `f32` value. @@ -652,45 +653,18 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] pub const fn classify(self) -> FpCategory { - // A previous implementation tried to only use bitmask-based checks, - // using f32::to_bits to transmute the float to its bit repr and match on that. - // If we only cared about being "technically" correct, that's an entirely legit - // implementation. - // - // Unfortunately, there is hardware out there that does not correctly implement the IEEE - // float semantics Rust relies on: x87 uses a too-large mantissa and exponent, and some - // hardware flushes subnormals to zero. These are platforms bugs, and Rust will misbehave on - // such hardware, but we can at least try to make things seem as sane as possible by being - // careful here. - // - // FIXME(jubilee): Using x87 operations is never necessary in order to function - // on x86 processors for Rust-to-Rust calls, so this issue should not happen. - // Code generation should be adjusted to use non-C calling conventions, avoiding this. - if self.is_infinite() { - // A value may compare unequal to infinity, despite having a "full" exponent mask. - FpCategory::Infinite - } else if self.is_nan() { - // And it may not be NaN, as it can simply be an "overextended" finite value. - FpCategory::Nan - } else { - // However, std can't simply compare to zero to check for zero, either, - // as correctness requires avoiding equality tests that may be Subnormal == -0.0 - // because it may be wrong under "denormals are zero" and "flush to zero" modes. - // Most of std's targets don't use those, but they are used for thumbv7neon. - // So, this does use bitpattern matching for the rest. On x87, due to the incorrect - // float codegen on this hardware, this doesn't actually return a right answer for NaN - // because it cannot correctly discern between a floating point NaN, and some normal - // floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so - // we are fine. - // FIXME(jubilee): This probably could at least answer things correctly for Infinity, - // like the f64 version does, but I need to run more checks on how things go on x86. - // I fear losing mantissa data that would have answered that differently. - let b = self.to_bits(); - match (b & Self::MAN_MASK, b & Self::EXP_MASK) { - (0, 0) => FpCategory::Zero, - (_, 0) => FpCategory::Subnormal, - _ => FpCategory::Normal, - } + // We used to have complicated logic here that avoids the simple bit-based tests to work + // around buggy codegen for x87 targets (see + // https://github.com/rust-lang/rust/issues/114479). However, some LLVM versions later, none + // of our tests is able to find any difference between the complicated and the naive + // version, so now we are back to the naive version. + let b = self.to_bits(); + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (_, Self::EXP_MASK) => FpCategory::Nan, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, } } @@ -1115,7 +1089,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_bits(self) -> u32 { // SAFETY: `u32` is a plain old datatype so we can always transmute to it. @@ -1159,7 +1133,7 @@ impl f32 { /// assert_eq!(v, 12.5); /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_bits(v: u32) -> Self { @@ -1183,7 +1157,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_be_bytes(self) -> [u8; 4] { self.to_bits().to_be_bytes() @@ -1204,7 +1178,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_le_bytes(self) -> [u8; 4] { self.to_bits().to_le_bytes() @@ -1238,7 +1212,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_ne_bytes(self) -> [u8; 4] { self.to_bits().to_ne_bytes() @@ -1256,7 +1230,7 @@ impl f32 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_be_bytes(bytes: [u8; 4]) -> Self { @@ -1275,7 +1249,7 @@ impl f32 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_le_bytes(bytes: [u8; 4]) -> Self { @@ -1305,7 +1279,7 @@ impl f32 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_ne_bytes(bytes: [u8; 4]) -> Self { diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index e6406771ad333..4bc275ad14786 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -414,6 +414,7 @@ impl f64 { /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f64::MANTISSA_DIGITS #[stable(feature = "assoc_int_consts", since = "1.43.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "f64_epsilon")] pub const EPSILON: f64 = 2.2204460492503131e-16_f64; /// Smallest finite `f64` value. @@ -651,41 +652,18 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] pub const fn classify(self) -> FpCategory { - // A previous implementation tried to only use bitmask-based checks, - // using f64::to_bits to transmute the float to its bit repr and match on that. - // If we only cared about being "technically" correct, that's an entirely legit - // implementation. - // - // Unfortunately, there is hardware out there that does not correctly implement the IEEE - // float semantics Rust relies on: x87 uses a too-large exponent, and some hardware flushes - // subnormals to zero. These are platforms bugs, and Rust will misbehave on such hardware, - // but we can at least try to make things seem as sane as possible by being careful here. - // - // FIXME(jubilee): Using x87 operations is never necessary in order to function - // on x86 processors for Rust-to-Rust calls, so this issue should not happen. - // Code generation should be adjusted to use non-C calling conventions, avoiding this. - // - // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask. - // And it may not be NaN, as it can simply be an "overextended" finite value. - if self.is_nan() { - FpCategory::Nan - } else { - // However, std can't simply compare to zero to check for zero, either, - // as correctness requires avoiding equality tests that may be Subnormal == -0.0 - // because it may be wrong under "denormals are zero" and "flush to zero" modes. - // Most of std's targets don't use those, but they are used for thumbv7neon. - // So, this does use bitpattern matching for the rest. On x87, due to the incorrect - // float codegen on this hardware, this doesn't actually return a right answer for NaN - // because it cannot correctly discern between a floating point NaN, and some normal - // floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so - // we are fine. - let b = self.to_bits(); - match (b & Self::MAN_MASK, b & Self::EXP_MASK) { - (0, Self::EXP_MASK) => FpCategory::Infinite, - (0, 0) => FpCategory::Zero, - (_, 0) => FpCategory::Subnormal, - _ => FpCategory::Normal, - } + // We used to have complicated logic here that avoids the simple bit-based tests to work + // around buggy codegen for x87 targets (see + // https://github.com/rust-lang/rust/issues/114479). However, some LLVM versions later, none + // of our tests is able to find any difference between the complicated and the naive + // version, so now we are back to the naive version. + let b = self.to_bits(); + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (_, Self::EXP_MASK) => FpCategory::Nan, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, } } @@ -1111,7 +1089,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_bits(self) -> u64 { // SAFETY: `u64` is a plain old datatype so we can always transmute to it. @@ -1155,7 +1133,7 @@ impl f64 { /// assert_eq!(v, 12.5); /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_bits(v: u64) -> Self { @@ -1179,7 +1157,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_be_bytes(self) -> [u8; 8] { self.to_bits().to_be_bytes() @@ -1200,7 +1178,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_le_bytes(self) -> [u8; 8] { self.to_bits().to_le_bytes() @@ -1234,7 +1212,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_ne_bytes(self) -> [u8; 8] { self.to_bits().to_ne_bytes() @@ -1252,7 +1230,7 @@ impl f64 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_be_bytes(bytes: [u8; 8]) -> Self { @@ -1271,7 +1249,7 @@ impl f64 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_le_bytes(bytes: [u8; 8]) -> Self { @@ -1301,7 +1279,7 @@ impl f64 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_ne_bytes(bytes: [u8; 8]) -> Self { diff --git a/library/core/src/num/flt2dec/decoder.rs b/library/core/src/num/flt2dec/decoder.rs index 5763860540aa4..40b3aae24a536 100644 --- a/library/core/src/num/flt2dec/decoder.rs +++ b/library/core/src/num/flt2dec/decoder.rs @@ -1,7 +1,7 @@ //! Decodes a floating-point value into individual parts and error ranges. -use crate::num::dec2flt::float::RawFloat; use crate::num::FpCategory; +use crate::num::dec2flt::float::RawFloat; /// Decoded unsigned finite value, such that: /// diff --git a/library/core/src/num/flt2dec/mod.rs b/library/core/src/num/flt2dec/mod.rs index 7d923a2652f28..d6413fadc3381 100644 --- a/library/core/src/num/flt2dec/mod.rs +++ b/library/core/src/num/flt2dec/mod.rs @@ -122,7 +122,7 @@ functions. issue = "none" )] -pub use self::decoder::{decode, DecodableFloat, Decoded, FullDecoded}; +pub use self::decoder::{DecodableFloat, Decoded, FullDecoded, decode}; use super::fmt::{Formatted, Part}; use crate::mem::MaybeUninit; diff --git a/library/core/src/num/flt2dec/strategy/dragon.rs b/library/core/src/num/flt2dec/strategy/dragon.rs index f8db6370653ab..e801f07b3bc0e 100644 --- a/library/core/src/num/flt2dec/strategy/dragon.rs +++ b/library/core/src/num/flt2dec/strategy/dragon.rs @@ -8,7 +8,7 @@ use crate::cmp::Ordering; use crate::mem::MaybeUninit; use crate::num::bignum::{Big32x40 as Big, Digit32 as Digit}; use crate::num::flt2dec::estimator::estimate_scaling_factor; -use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS}; +use crate::num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs index b9f0d114c6a14..bdf544a4133bb 100644 --- a/library/core/src/num/flt2dec/strategy/grisu.rs +++ b/library/core/src/num/flt2dec/strategy/grisu.rs @@ -7,7 +7,7 @@ use crate::mem::MaybeUninit; use crate::num::diy_float::Fp; -use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS}; +use crate::num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; // see the comments in `format_shortest_opt` for the rationale. #[doc(hidden)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 878a911dde50d..7241b3ff6a3b7 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3023,8 +3023,16 @@ macro_rules! int_impl { pub const fn div_floor(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; - if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { - d - 1 + + // If the remainder is non-zero, we need to subtract one if the + // signs of self and rhs differ, as this means we rounded upwards + // instead of downwards. We do this branchlessly by creating a mask + // which is all-ones iff the signs differ, and 0 otherwise. Then by + // adding this mask (which corresponds to the signed value -1), we + // get our correction. + let correction = (self ^ rhs) >> (Self::BITS - 1); + if r != 0 { + d + correction } else { d } @@ -3059,8 +3067,12 @@ macro_rules! int_impl { pub const fn div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; - if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) { - d + 1 + + // When remainder is non-zero we have a.div_ceil(b) == 1 + a.div_floor(b), + // so we can re-use the algorithm from div_floor, just adding 1. + let correction = 1 + ((self ^ rhs) >> (Self::BITS - 1)); + if r != 0 { + d + correction } else { d } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index e9e5324666ada..31e35015d2de1 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -6,7 +6,7 @@ use crate::str::FromStr; use crate::ub_checks::assert_unsafe_precondition; use crate::{ascii, intrinsics, mem}; -// Used because the `?` operator is not allowed in a const context. +// FIXME(const-hack): Used because the `?` operator is not allowed in a const context. macro_rules! try_opt { ($e:expr) => { match $e { @@ -23,6 +23,16 @@ macro_rules! unlikely { }; } +// Use this when the generated code should differ between signed and unsigned types. +macro_rules! sign_dependent_expr { + (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { + $signed_case + }; + (unsigned ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { + $unsigned_case + }; +} + // All these modules are technically private and only exposed for coretests: #[cfg(not(no_fp_fmt_parse))] pub mod bignum; @@ -65,9 +75,9 @@ pub use nonzero::NonZero; )] pub use nonzero::ZeroablePrimitive; #[stable(feature = "signed_nonzero", since = "1.34.0")] -pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; +pub use nonzero::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize}; #[stable(feature = "nonzero", since = "1.28.0")] -pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; +pub use nonzero::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub use saturating::Saturating; #[stable(feature = "rust1", since = "1.0.0")] @@ -614,8 +624,9 @@ impl u8 { /// /// [`to_ascii_uppercase`]: Self::to_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_make_ascii", issue = "130698")] #[inline] - pub fn make_ascii_uppercase(&mut self) { + pub const fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); } @@ -639,8 +650,9 @@ impl u8 { /// /// [`to_ascii_lowercase`]: Self::to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_make_ascii", issue = "130698")] #[inline] - pub fn make_ascii_lowercase(&mut self) { + pub const fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); } @@ -1385,7 +1397,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } #[doc(hidden)] #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] -#[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } @@ -1410,15 +1422,25 @@ const fn from_str_radix_panic(radix: u32) { } macro_rules! from_str_radix { - ($($int_ty:ty)+) => {$( + ($signedness:ident $($int_ty:ty)+) => {$( impl $int_ty { /// Converts a string slice in a given base to an integer. /// - /// The string is expected to be an optional `+` sign - /// followed by digits. - /// Leading and trailing whitespace represent an error. - /// Digits are a subset of these characters, depending on `radix`: + /// The string is expected to be an optional + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + " `+` or `-` " + } + if unsigned { + " `+` " + } + }] + /// sign followed by only digits. Leading and trailing non-digit characters (including + /// whitespace) represent an error. Underscores (which are accepted in rust literals) + /// also represent an error. /// + /// Digits are a subset of these characters, depending on `radix`: /// * `0-9` /// * `a-z` /// * `A-Z` @@ -1430,12 +1452,15 @@ macro_rules! from_str_radix { /// # Examples /// /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` + /// Trailing space returns error: + /// ``` + #[doc = concat!("assert!(", stringify!($int_ty), "::from_str_radix(\"1 \", 10).is_err());")] + /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> { use self::IntErrorKind::*; use self::ParseIntError as PIE; @@ -1535,20 +1560,31 @@ macro_rules! from_str_radix { )+} } -from_str_radix! { i8 u8 i16 u16 i32 u32 i64 u64 i128 u128 } +from_str_radix! { unsigned u8 u16 u32 u64 u128 } +from_str_radix! { signed i8 i16 i32 i64 i128 } // Re-use the relevant implementation of from_str_radix for isize and usize to avoid outputting two // identical functions. macro_rules! from_str_radix_size_impl { - ($($t:ident $size:ty),*) => {$( + ($($signedness:ident $t:ident $size:ty),*) => {$( impl $size { /// Converts a string slice in a given base to an integer. /// - /// The string is expected to be an optional `+` sign - /// followed by digits. - /// Leading and trailing whitespace represent an error. - /// Digits are a subset of these characters, depending on `radix`: + /// The string is expected to be an optional + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + " `+` or `-` " + } + if unsigned { + " `+` " + } + }] + /// sign followed by only digits. Leading and trailing non-digit characters (including + /// whitespace) represent an error. Underscores (which are accepted in rust literals) + /// also represent an error. /// + /// Digits are a subset of these characters, depending on `radix`: /// * `0-9` /// * `a-z` /// * `A-Z` @@ -1560,12 +1596,15 @@ macro_rules! from_str_radix_size_impl { /// # Examples /// /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` + /// Trailing space returns error: + /// ``` + #[doc = concat!("assert!(", stringify!($size), "::from_str_radix(\"1 \", 10).is_err());")] + /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> { match <$t>::from_str_radix(src, radix) { Ok(x) => Ok(x as $size), @@ -1576,8 +1615,8 @@ macro_rules! from_str_radix_size_impl { } #[cfg(target_pointer_width = "16")] -from_str_radix_size_impl! { i16 isize, u16 usize } +from_str_radix_size_impl! { signed i16 isize, unsigned u16 usize } #[cfg(target_pointer_width = "32")] -from_str_radix_size_impl! { i32 isize, u32 usize } +from_str_radix_size_impl! { signed i32 isize, unsigned u32 usize } #[cfg(target_pointer_width = "64")] -from_str_radix_size_impl! { i64 isize, u64 usize } +from_str_radix_size_impl! { signed i64 isize, unsigned u64 usize } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 8b888f12da0b1..e5c9a7e086ac9 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1972,16 +1972,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { }; } -// Use this when the generated code should differ between signed and unsigned types. -macro_rules! sign_dependent_expr { - (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { - $signed_case - }; - (unsigned ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { - $unsigned_case - }; -} - nonzero_integer! { Self = NonZeroU8, Primitive = unsigned u8, diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 37fac2b126fac..4b230b15a1e6f 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -79,7 +79,10 @@ mod impls { where F: AsyncFn, { - type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a; + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallRefFuture<'_> { F::async_call(*self, args) @@ -104,7 +107,10 @@ mod impls { where F: AsyncFnMut, { - type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a; + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallRefFuture<'_> { F::async_call_mut(*self, args) diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 98d41b71e8eb8..25c4b87f4e76b 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -172,9 +172,9 @@ pub use self::deref::DerefPure; pub use self::deref::Receiver; #[stable(feature = "rust1", since = "1.0.0")] pub use self::deref::{Deref, DerefMut}; -pub(crate) use self::drop::fallback_surface_drop; #[stable(feature = "rust1", since = "1.0.0")] pub use self::drop::Drop; +pub(crate) use self::drop::fallback_surface_drop; #[stable(feature = "rust1", since = "1.0.0")] pub use self::function::{Fn, FnMut, FnOnce}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 50cb22b7eb3f5..30c667e2494b2 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -667,7 +667,7 @@ impl Option { /// ``` #[must_use] #[inline] - #[stable(feature = "is_none_or", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "is_none_or", since = "1.82.0")] pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { match self { None => true, @@ -739,6 +739,7 @@ impl Option { #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] pub const fn as_pin_ref(self: Pin<&Self>) -> Option> { + // FIXME(const-hack): use `map` once that is possible match Pin::get_ref(self).as_ref() { // SAFETY: `x` is guaranteed to be pinned because it comes from `self` // which is pinned. @@ -758,6 +759,7 @@ impl Option { // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`. // `x` is guaranteed to be pinned because it comes from `self` which is pinned. unsafe { + // FIXME(const-hack): use `map` once that is possible match Pin::get_unchecked_mut(self).as_mut() { Some(x) => Some(Pin::new_unchecked(x)), None => None, @@ -921,6 +923,7 @@ impl Option { #[inline] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "option_expect")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] pub const fn expect(self, msg: &str) -> T { match self { @@ -958,6 +961,7 @@ impl Option { #[inline(always)] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "option_unwrap")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] pub const fn unwrap(self) -> T { match self { @@ -1065,7 +1069,7 @@ impl Option { #[inline] #[track_caller] #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + #[rustc_const_unstable(feature = "const_option", issue = "67441")] pub const unsafe fn unwrap_unchecked(self) -> T { match self { Some(val) => val, @@ -1290,10 +1294,7 @@ impl Option { where T: Deref, { - match self.as_ref() { - Some(t) => Some(t.deref()), - None => None, - } + self.as_ref().map(|t| t.deref()) } /// Converts from `Option` (or `&mut Option`) to `Option<&mut T::Target>`. @@ -1316,10 +1317,7 @@ impl Option { where T: DerefMut, { - match self.as_mut() { - Some(t) => Some(t.deref_mut()), - None => None, - } + self.as_mut().map(|t| t.deref_mut()) } ///////////////////////////////////////////////////////////////////////// @@ -1338,9 +1336,8 @@ impl Option { /// assert_eq!(x.iter().next(), None); /// ``` #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] #[stable(feature = "rust1", since = "1.0.0")] - pub const fn iter(&self) -> Iter<'_, T> { + pub fn iter(&self) -> Iter<'_, T> { Iter { inner: Item { opt: self.as_ref() } } } @@ -1633,13 +1630,7 @@ impl Option { #[inline] #[stable(feature = "option_entry", since = "1.20.0")] pub fn get_or_insert(&mut self, value: T) -> &mut T { - if let None = *self { - *self = Some(value); - } - - // SAFETY: a `None` variant for `self` would have been replaced by a `Some` - // variant in the code above. - unsafe { self.as_mut().unwrap_unchecked() } + self.get_or_insert_with(|| value) } /// Inserts the default value into the option if it is [`None`], then @@ -1725,7 +1716,7 @@ impl Option { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] pub const fn take(&mut self) -> Option { - // FIXME replace `mem::replace` by `mem::take` when the latter is const ready + // FIXME(const-hack) replace `mem::replace` by `mem::take` when the latter is const ready mem::replace(self, None) } @@ -1894,7 +1885,7 @@ impl Option<&T> { where T: Copy, { - // FIXME: this implementation, which sidesteps using `Option::map` since it's not const + // FIXME(const-hack): this implementation, which sidesteps using `Option::map` since it's not const // ready yet, should be reverted when possible to avoid code repetition match self { Some(&v) => Some(v), @@ -1942,7 +1933,7 @@ impl Option<&mut T> { /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "copied", since = "1.35.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + #[rustc_const_unstable(feature = "const_option", issue = "67441")] pub const fn copied(self) -> Option where T: Copy, @@ -2547,6 +2538,7 @@ impl Option> { #[stable(feature = "option_flattening", since = "1.40.0")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] pub const fn flatten(self) -> Option { + // FIXME(const-hack): could be written with `and_then` match self { Some(inner) => inner, None => None, diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 6c5236ed99ce8..c95a000561c35 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -140,6 +140,31 @@ pub macro unreachable_2021 { ), } +/// Invokes a closure, aborting if the closure unwinds. +/// +/// When compiled with aborting panics, this function is effectively a no-op. +/// With unwinding panics, an unwind results in another call into the panic +/// hook followed by a process abort. +/// +/// # Notes +/// +/// Instead of using this function, code should attempt to support unwinding. +/// Implementing [`Drop`] allows you to restore invariants uniformly in both +/// return and unwind paths. +/// +/// If an unwind can lead to logical issues but not soundness issues, you +/// should allow the unwind. Opting out of [`UnwindSafe`] indicates to your +/// consumers that they need to consider correctness in the face of unwinds. +/// +/// If an unwind would be unsound, then this function should be used in order +/// to prevent unwinds. However, note that `extern "C" fn` will automatically +/// convert unwinds to aborts, so using this function isn't necessary for FFI. +#[unstable(feature = "abort_unwind", issue = "130338")] +#[rustc_nounwind] +pub fn abort_unwind R, R>(f: F) -> R { + f() +} + /// An internal trait used by std to pass data from std to `panic_unwind` and /// other panic runtimes. Not intended to be stabilized any time soon, do not /// use. diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index e4d0c897b65ca..af2c83b546071 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -12,7 +12,7 @@ use crate::panic::Location; #[stable(feature = "panic_hooks", since = "1.10.0")] #[derive(Debug)] pub struct PanicInfo<'a> { - message: fmt::Arguments<'a>, + message: &'a fmt::Arguments<'a>, location: &'a Location<'a>, can_unwind: bool, force_no_backtrace: bool, @@ -26,13 +26,13 @@ pub struct PanicInfo<'a> { /// See [`PanicInfo::message`]. #[stable(feature = "panic_info_message", since = "1.81.0")] pub struct PanicMessage<'a> { - message: fmt::Arguments<'a>, + message: &'a fmt::Arguments<'a>, } impl<'a> PanicInfo<'a> { #[inline] pub(crate) fn new( - message: fmt::Arguments<'a>, + message: &'a fmt::Arguments<'a>, location: &'a Location<'a>, can_unwind: bool, force_no_backtrace: bool, @@ -146,7 +146,7 @@ impl Display for PanicInfo<'_> { formatter.write_str("panicked at ")?; self.location.fmt(formatter)?; formatter.write_str(":\n")?; - formatter.write_fmt(self.message)?; + formatter.write_fmt(*self.message)?; Ok(()) } } @@ -177,7 +177,7 @@ impl<'a> PanicMessage<'a> { impl Display for PanicMessage<'_> { #[inline] fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_fmt(self.message) + formatter.write_fmt(*self.message) } } @@ -185,6 +185,6 @@ impl Display for PanicMessage<'_> { impl fmt::Debug for PanicMessage<'_> { #[inline] fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_fmt(self.message) + formatter.write_fmt(*self.message) } } diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index e4a623040871a..7420579e3ce91 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -64,7 +64,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { } let pi = PanicInfo::new( - fmt, + &fmt, Location::caller(), /* can_unwind */ true, /* force_no_backtrace */ false, @@ -102,7 +102,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo // PanicInfo with the `can_unwind` flag set to false forces an abort. let pi = PanicInfo::new( - fmt, + &fmt, Location::caller(), /* can_unwind */ false, force_no_backtrace, diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 65f6bfb7ee176..9c13662e08e8f 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1084,7 +1084,7 @@ use crate::{cmp, fmt}; #[lang = "pin"] #[fundamental] #[repr(transparent)] -#[cfg_attr(not(bootstrap), rustc_pub_transparent)] +#[rustc_pub_transparent] #[derive(Copy, Clone)] pub struct Pin { // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to: diff --git a/library/core/src/primitive.rs b/library/core/src/primitive.rs index 81a72118614dd..b5f97b898878f 100644 --- a/library/core/src/primitive.rs +++ b/library/core/src/primitive.rs @@ -46,7 +46,7 @@ pub use f32; #[stable(feature = "core_primitive", since = "1.43.0")] pub use f64; #[stable(feature = "core_primitive", since = "1.43.0")] -pub use i128; +pub use i8; #[stable(feature = "core_primitive", since = "1.43.0")] pub use i16; #[stable(feature = "core_primitive", since = "1.43.0")] @@ -54,13 +54,13 @@ pub use i32; #[stable(feature = "core_primitive", since = "1.43.0")] pub use i64; #[stable(feature = "core_primitive", since = "1.43.0")] -pub use i8; +pub use i128; #[stable(feature = "core_primitive", since = "1.43.0")] pub use isize; #[stable(feature = "core_primitive", since = "1.43.0")] pub use str; #[stable(feature = "core_primitive", since = "1.43.0")] -pub use u128; +pub use u8; #[stable(feature = "core_primitive", since = "1.43.0")] pub use u16; #[stable(feature = "core_primitive", since = "1.43.0")] @@ -68,6 +68,6 @@ pub use u32; #[stable(feature = "core_primitive", since = "1.43.0")] pub use u64; #[stable(feature = "core_primitive", since = "1.43.0")] -pub use u8; +pub use u128; #[stable(feature = "core_primitive", since = "1.43.0")] pub use usize; diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index a7037b2a119ff..962da6643ddb1 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -832,8 +832,9 @@ mod prim_array {} #[doc(alias = "[")] #[doc(alias = "]")] #[doc(alias = "[]")] -/// A dynamically-sized view into a contiguous sequence, `[T]`. Contiguous here -/// means that elements are laid out so that every element is the same +/// A dynamically-sized view into a contiguous sequence, `[T]`. +/// +/// Contiguous here means that elements are laid out so that every element is the same /// distance from its neighbors. /// /// *[See also the `std::slice` module](crate::slice).* @@ -1760,6 +1761,8 @@ mod prim_ref {} /// - `i32` is ABI-compatible with `NonZero`, and similar for all other integer types. /// - If `T` is guaranteed to be subject to the [null pointer /// optimization](option/index.html#representation), then `T` and `Option` are ABI-compatible. +/// Furthermore, if `U` satisfies the requirements [outlined here](result/index.html#representation), +/// then `T` and `Result` and `Result` are all ABI-compatible. /// /// Furthermore, ABI compatibility satisfies the following general properties: /// diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 19fe03d57cc0a..ceb5906d226ef 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -154,6 +154,11 @@ impl Alignment { // SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow. !(unsafe { self.as_usize().unchecked_sub(1) }) } + + // Remove me once `Ord::max` is usable in const + pub(crate) const fn max(a: Self, b: Self) -> Self { + if a.as_usize() > b.as_usize() { a } else { b } + } } #[unstable(feature = "ptr_alignment_type", issue = "102070")] @@ -199,7 +204,6 @@ impl From for usize { } } -#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[unstable(feature = "ptr_alignment_type", issue = "102070")] impl cmp::Ord for Alignment { #[inline] @@ -208,7 +212,6 @@ impl cmp::Ord for Alignment { } } -#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[unstable(feature = "ptr_alignment_type", issue = "102070")] impl cmp::PartialOrd for Alignment { #[inline] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 3b635e2a4aa9e..1146ca6ef4301 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -40,15 +40,17 @@ impl *const T { #[inline] const fn const_impl(ptr: *const u8) -> bool { - // Compare via a cast to a thin pointer, so fat pointers are only - // considering their "data" part for null-ness. match (ptr).guaranteed_eq(null_mut()) { - None => false, Some(res) => res, + // To remain maximally convervative, we stop execution when we don't + // know whether the pointer is null or not. + // We can *not* return `false` here, that would be unsound in `NonNull::new`! + None => panic!("null-ness of this pointer cannot be determined in const context"), } } - #[allow(unused_unsafe)] + // Compare via a cast to a thin pointer, so fat pointers are only + // considering their "data" part for null-ness. const_eval_select((self as *const u8,), const_impl, runtime_impl) } @@ -268,7 +270,7 @@ impl *const T { /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] #[inline] pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> { // SAFETY: the caller must guarantee that `self` is valid @@ -300,7 +302,7 @@ impl *const T { /// ``` // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized. #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] #[inline] #[must_use] pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T { @@ -334,7 +336,7 @@ impl *const T { /// ``` #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit> where T: Sized, @@ -1190,7 +1192,7 @@ impl *const T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1210,7 +1212,7 @@ impl *const T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1662,7 +1664,7 @@ impl *const [T] { /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit]> { if self.is_null() { None diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index ccc9f8754f00c..76a0e2ba77483 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -187,14 +187,14 @@ impl DynMetadata { // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the // `Send` part! // SAFETY: DynMetadata always contains a valid vtable pointer - return unsafe { crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) }; + unsafe { crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) } } /// Returns the alignment of the type associated with this vtable. #[inline] pub fn align_of(self) -> usize { // SAFETY: DynMetadata always contains a valid vtable pointer - return unsafe { crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) }; + unsafe { crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) } } /// Returns the size and alignment together as a `Layout` diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index d7ed4edcc0041..4f97048eab10d 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -467,7 +467,7 @@ pub use crate::intrinsics::write_bytes; mod metadata; #[unstable(feature = "ptr_metadata", issue = "81513")] -pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin}; +pub use metadata::{DynMetadata, Pointee, Thin, from_raw_parts, from_raw_parts_mut, metadata}; mod non_null; #[stable(feature = "nonnull", since = "1.25.0")] @@ -1516,11 +1516,7 @@ pub const unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[rustc_allow_const_fn_unstable( - const_mut_refs, - const_maybe_uninit_as_mut_ptr, - const_intrinsic_copy -)] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_read_unaligned"] pub const unsafe fn read_unaligned(src: *const T) -> T { @@ -1734,7 +1730,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { - copy_nonoverlapping(addr_of!(src) as *const u8, dst as *mut u8, mem::size_of::()); + copy_nonoverlapping((&raw const src) as *const u8, dst as *mut u8, mem::size_of::()); // We are calling the intrinsic directly to avoid function calls in the generated code. intrinsics::forget(src); } @@ -2277,6 +2273,14 @@ impl fmt::Debug for F { /// `addr_of!(expr)` is equivalent to `&raw const expr`. The macro is *soft-deprecated*; /// use `&raw const` instead. /// +/// It is still an open question under which conditions writing through an `addr_of!`-created +/// pointer is permitted. If the place `expr` evaluates to is based on a raw pointer, then the +/// result of `addr_of!` inherits all permissions from that raw pointer. However, if the place is +/// based on a reference, local variable, or `static`, then until all details are decided, the same +/// rules as for shared references apply: it is UB to write through a pointer created with this +/// operation, except for bytes located inside an `UnsafeCell`. Use `&raw mut` (or [`addr_of_mut`]) +/// to create a raw pointer that definitely permits mutation. +/// /// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned /// and points to initialized data. For cases where those requirements do not hold, /// raw pointers should be used instead. However, `&expr as *const _` creates a reference @@ -2344,7 +2348,6 @@ impl fmt::Debug for F { /// no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] -#[allow_internal_unstable(raw_ref_op)] pub macro addr_of($place:expr) { &raw const $place } @@ -2435,7 +2438,6 @@ pub macro addr_of($place:expr) { /// makes no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] -#[allow_internal_unstable(raw_ref_op)] pub macro addr_of_mut($place:expr) { &raw mut $place } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 42975cc927b8e..8e33cf081ba6c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -33,22 +33,7 @@ impl *mut T { #[rustc_diagnostic_item = "ptr_is_null"] #[inline] pub const fn is_null(self) -> bool { - #[inline] - fn runtime_impl(ptr: *mut u8) -> bool { - ptr.addr() == 0 - } - - #[inline] - const fn const_impl(ptr: *mut u8) -> bool { - // Compare via a cast to a thin pointer, so fat pointers are only - // considering their "data" part for null-ness. - match (ptr).guaranteed_eq(null_mut()) { - None => false, - Some(res) => res, - } - } - - const_eval_select((self as *mut u8,), const_impl, runtime_impl) + self.cast_const().is_null() } /// Casts to a pointer of another type. @@ -276,7 +261,7 @@ impl *mut T { /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] #[inline] pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> { // SAFETY: the caller must guarantee that `self` is valid for a @@ -310,7 +295,7 @@ impl *mut T { /// ``` // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized. #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] #[inline] #[must_use] pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T { @@ -349,7 +334,7 @@ impl *mut T { /// ``` #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit> where T: Sized, @@ -595,7 +580,7 @@ impl *mut T { /// println!("{s:?}"); // It'll print: "[4, 2, 3]". /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] #[inline] pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { // SAFETY: the caller must guarantee that `self` is be valid for @@ -631,7 +616,7 @@ impl *mut T { /// ``` // FIXME: mention it in the docs for `as_mut` and `as_uninit_mut` once stabilized. #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] #[inline] #[must_use] pub const unsafe fn as_mut_unchecked<'a>(self) -> &'a mut T { @@ -654,7 +639,7 @@ impl *mut T { /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_mut<'a>(self) -> Option<&'a mut MaybeUninit> where T: Sized, @@ -1284,7 +1269,7 @@ impl *mut T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1304,7 +1289,7 @@ impl *mut T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1324,7 +1309,7 @@ impl *mut T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1344,7 +1329,7 @@ impl *mut T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1584,7 +1569,7 @@ impl *mut T { /// /// ``` /// #![feature(const_pointer_is_aligned)] - /// #![feature(const_mut_refs)] + /// # #![cfg_attr(bootstrap, feature(const_mut_refs))] /// /// // On some platforms, the alignment of primitives is less than their size. /// #[repr(align(4))] @@ -1710,7 +1695,7 @@ impl *mut T { /// ``` /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] - /// #![feature(const_mut_refs)] + /// # #![cfg_attr(bootstrap, feature(const_mut_refs))] /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] @@ -2031,7 +2016,7 @@ impl *mut [T] { /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit]> { if self.is_null() { None @@ -2083,7 +2068,7 @@ impl *mut [T] { /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit]> { if self.is_null() { None diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index b1429fff74434..daa40b3c9d2e5 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -133,7 +133,7 @@ impl NonNull { #[inline] #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_ref<'a>(self) -> &'a MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. @@ -157,7 +157,7 @@ impl NonNull { #[inline] #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_mut<'a>(self) -> &'a mut MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. @@ -924,7 +924,7 @@ impl NonNull { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn copy_to(self, dest: NonNull, count: usize) where T: Sized, @@ -944,7 +944,7 @@ impl NonNull { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull, count: usize) where T: Sized, @@ -964,7 +964,7 @@ impl NonNull { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn copy_from(self, src: NonNull, count: usize) where T: Sized, @@ -984,7 +984,7 @@ impl NonNull { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull, count: usize) where T: Sized, @@ -1563,7 +1563,7 @@ impl NonNull<[T]> { #[inline] #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> &'a [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice`. unsafe { slice::from_raw_parts(self.cast().as_ptr(), self.len()) } @@ -1628,7 +1628,7 @@ impl NonNull<[T]> { #[inline] #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice_mut<'a>(self) -> &'a mut [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice_mut`. unsafe { slice::from_raw_parts_mut(self.cast().as_ptr(), self.len()) } diff --git a/library/core/src/random.rs b/library/core/src/random.rs new file mode 100644 index 0000000000000..051fe26086389 --- /dev/null +++ b/library/core/src/random.rs @@ -0,0 +1,62 @@ +//! Random value generation. +//! +//! The [`Random`] trait allows generating a random value for a type using a +//! given [`RandomSource`]. + +/// A source of randomness. +#[unstable(feature = "random", issue = "130703")] +pub trait RandomSource { + /// Fills `bytes` with random bytes. + fn fill_bytes(&mut self, bytes: &mut [u8]); +} + +/// A trait for getting a random value for a type. +/// +/// **Warning:** Be careful when manipulating random values! The +/// [`random`](Random::random) method on integers samples them with a uniform +/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using +/// modulo operations, some of the resulting values can become more likely than +/// others. Use audited crates when in doubt. +#[unstable(feature = "random", issue = "130703")] +pub trait Random: Sized { + /// Generates a random value. + fn random(source: &mut (impl RandomSource + ?Sized)) -> Self; +} + +impl Random for bool { + fn random(source: &mut (impl RandomSource + ?Sized)) -> Self { + u8::random(source) & 1 == 1 + } +} + +macro_rules! impl_primitive { + ($t:ty) => { + impl Random for $t { + /// Generates a random value. + /// + /// **Warning:** Be careful when manipulating the resulting value! This + /// method samples according to a uniform distribution, so a value of 1 is + /// just as likely as [`MAX`](Self::MAX). By using modulo operations, some + /// values can become more likely than others. Use audited crates when in + /// doubt. + fn random(source: &mut (impl RandomSource + ?Sized)) -> Self { + let mut bytes = (0 as Self).to_ne_bytes(); + source.fill_bytes(&mut bytes); + Self::from_ne_bytes(bytes) + } + } + }; +} + +impl_primitive!(u8); +impl_primitive!(i8); +impl_primitive!(u16); +impl_primitive!(i16); +impl_primitive!(u32); +impl_primitive!(i32); +impl_primitive!(u64); +impl_primitive!(i64); +impl_primitive!(u128); +impl_primitive!(i128); +impl_primitive!(usize); +impl_primitive!(isize); diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 408972c267f1a..427526fd14b91 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -24,9 +24,9 @@ mod iter; #[unstable(feature = "new_range_api", issue = "125687")] pub mod legacy; +use Bound::{Excluded, Included, Unbounded}; #[doc(inline)] pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive}; -use Bound::{Excluded, Included, Unbounded}; #[doc(inline)] pub use crate::iter::Step; diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs index 4935280df60bc..1e261d8c1d93a 100644 --- a/library/core/src/range/iter.rs +++ b/library/core/src/range/iter.rs @@ -2,7 +2,7 @@ use crate::iter::{ FusedIterator, Step, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, TrustedStep, }; use crate::num::NonZero; -use crate::range::{legacy, Range, RangeFrom, RangeInclusive}; +use crate::range::{Range, RangeFrom, RangeInclusive, legacy}; /// By-value [`Range`] iterator. #[unstable(feature = "new_range_api", issue = "125687")] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 73b11f803d929..610edae48d36b 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -653,6 +653,7 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "result_ok_method")] pub fn ok(self) -> Option { match self { Ok(x) => Some(x), @@ -1535,11 +1536,17 @@ impl Result<&T, E> { /// ``` #[inline] #[stable(feature = "result_copied", since = "1.59.0")] - pub fn copied(self) -> Result + #[rustc_const_unstable(feature = "const_result", issue = "82814")] + pub const fn copied(self) -> Result where T: Copy, { - self.map(|&t| t) + // FIXME(const-hack): this implementation, which sidesteps using `Result::map` since it's not const + // ready yet, should be reverted when possible to avoid code repetition + match self { + Ok(&v) => Ok(v), + Err(e) => Err(e), + } } /// Maps a `Result<&T, E>` to a `Result` by cloning the contents of the @@ -1579,11 +1586,17 @@ impl Result<&mut T, E> { /// ``` #[inline] #[stable(feature = "result_copied", since = "1.59.0")] - pub fn copied(self) -> Result + #[rustc_const_unstable(feature = "const_result", issue = "82814")] + pub const fn copied(self) -> Result where T: Copy, { - self.map(|&mut t| t) + // FIXME(const-hack): this implementation, which sidesteps using `Result::map` since it's not const + // ready yet, should be reverted when possible to avoid code repetition + match self { + Ok(&mut v) => Ok(v), + Err(e) => Err(e), + } } /// Maps a `Result<&mut T, E>` to a `Result` by cloning the contents of the @@ -1663,8 +1676,13 @@ impl Result, E> { /// ``` #[inline] #[unstable(feature = "result_flattening", issue = "70142")] - pub fn flatten(self) -> Result { - self.and_then(convert::identity) + #[rustc_const_unstable(feature = "result_flattening", issue = "70142")] + pub const fn flatten(self) -> Result { + // FIXME(const-hack): could be written with `and_then` + match self { + Ok(inner) => inner, + Err(e) => Err(e), + } } } diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index d1ea52fab6b87..8f8050fdc3aaf 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -67,10 +67,15 @@ impl [u8] { /// /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_make_ascii", issue = "130698")] #[inline] - pub fn make_ascii_uppercase(&mut self) { - for byte in self { + pub const fn make_ascii_uppercase(&mut self) { + // FIXME(const-hack): We would like to simply iterate using `for` loops but this isn't currently allowed in constant expressions. + let mut i = 0; + while i < self.len() { + let byte = &mut self[i]; byte.make_ascii_uppercase(); + i += 1; } } @@ -84,10 +89,15 @@ impl [u8] { /// /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_make_ascii", issue = "130698")] #[inline] - pub fn make_ascii_lowercase(&mut self) { - for byte in self { + pub const fn make_ascii_lowercase(&mut self) { + // FIXME(const-hack): We would like to simply iterate using `for` loops but this isn't currently allowed in constant expressions. + let mut i = 0; + while i < self.len() { + let byte = &mut self[i]; byte.make_ascii_lowercase(); + i += 1; } } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index de1492e82ce7d..bc8571c8503e9 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -31,12 +31,12 @@ where #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { + // FIXME(const-hack): once integer formatting in panics is possible, we + // should use the same implementation at compiletime and runtime. const_eval_select((index, len), slice_start_index_len_fail_ct, slice_start_index_len_fail_rt) } -// FIXME const-hack #[inline] #[track_caller] fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! { @@ -52,12 +52,12 @@ const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { + // FIXME(const-hack): once integer formatting in panics is possible, we + // should use the same implementation at compiletime and runtime. const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt) } -// FIXME const-hack #[inline] #[track_caller] fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! { @@ -73,12 +73,12 @@ const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_index_order_fail(index: usize, end: usize) -> ! { + // FIXME(const-hack): once integer formatting in panics is possible, we + // should use the same implementation at compiletime and runtime. const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) } -// FIXME const-hack #[inline] #[track_caller] fn slice_index_order_fail_rt(index: usize, end: usize) -> ! { @@ -246,7 +246,6 @@ pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The methods `index` and `index_mut` panic if the index is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for usize { type Output = T; @@ -386,7 +385,6 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for ops::Range { type Output = [T]; @@ -522,7 +520,6 @@ unsafe impl SliceIndex<[T]> for range::Range { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for ops::RangeTo { type Output = [T]; @@ -561,7 +558,6 @@ unsafe impl SliceIndex<[T]> for ops::RangeTo { /// The methods `index` and `index_mut` panic if the start of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; @@ -644,7 +640,6 @@ unsafe impl SliceIndex<[T]> for range::RangeFrom { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for ops::RangeFull { type Output = [T]; @@ -684,7 +679,6 @@ unsafe impl SliceIndex<[T]> for ops::RangeFull { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; @@ -766,7 +760,6 @@ unsafe impl SliceIndex<[T]> for range::RangeInclusive { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 62b170a87d445..c5746157d01b2 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -11,7 +11,7 @@ use crate::iter::{ use crate::marker::PhantomData; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; -use crate::ptr::{self, without_provenance, without_provenance_mut, NonNull}; +use crate::ptr::{NonNull, without_provenance, without_provenance_mut}; use crate::{cmp, fmt}; #[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c2a3819464410..830debe02ea2b 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -14,11 +14,11 @@ macro_rules! if_zst { if T::IS_ZST { // SAFETY: for ZSTs, the pointer is storing a provenance-free length, // so consuming and updating it as a `usize` is fine. - let $len = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::() }; + let $len = unsafe { &mut *(&raw mut $this.end_or_len).cast::() }; $zst_body } else { // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null - let $end = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::>() }; + let $end = unsafe { &mut *(&raw mut $this.end_or_len).cast::>() }; $other_body } }}; @@ -30,7 +30,7 @@ macro_rules! if_zst { $zst_body } else { // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null - let $end = unsafe { *ptr::addr_of!($this.end_or_len).cast::>() }; + let $end = unsafe { *(&raw const $this.end_or_len).cast::>() }; $other_body } }}; diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index da7ceb2dd0a0d..be19c3d3bc153 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -51,7 +51,6 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option { } #[rustc_allow_const_fn_unstable(const_cmp)] -#[rustc_allow_const_fn_unstable(const_slice_index)] #[rustc_allow_const_fn_unstable(const_align_offset)] #[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] const fn memchr_aligned(x: u8, text: &[u8]) -> Option { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index c7918499d4ab9..dd8fa1ae343ae 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -39,11 +39,11 @@ mod raw; mod rotate; mod specialize; +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] +pub use ascii::EscapeAscii; #[unstable(feature = "str_internals", issue = "none")] #[doc(hidden)] pub use ascii::is_ascii_simple; -#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] -pub use ascii::EscapeAscii; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; #[unstable(feature = "slice_range", issue = "76393")] @@ -156,7 +156,7 @@ impl [T] { if let [first, ..] = self { Some(first) } else { None } } - /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. + /// Returns a mutable reference to the first element of the slice, or `None` if it is empty. /// /// # Examples /// @@ -529,7 +529,7 @@ impl [T] { None } else { // SAFETY: We manually verified the bounds of the slice. - // FIXME: Without const traits, we need this instead of `get_unchecked`. + // FIXME(const-hack): Without const traits, we need this instead of `get_unchecked`. let last = unsafe { self.split_at_unchecked(self.len() - N).1 }; // SAFETY: We explicitly check for the correct number of elements, @@ -563,7 +563,7 @@ impl [T] { None } else { // SAFETY: We manually verified the bounds of the slice. - // FIXME: Without const traits, we need this instead of `get_unchecked`. + // FIXME(const-hack): Without const traits, we need this instead of `get_unchecked`. let last = unsafe { self.split_at_mut_unchecked(self.len() - N).1 }; // SAFETY: We explicitly check for the correct number of elements, @@ -846,7 +846,7 @@ impl [T] { /// [`as_mut_ptr`]: slice::as_mut_ptr #[stable(feature = "slice_ptr_range", since = "1.48.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] - #[rustc_allow_const_fn_unstable(const_mut_refs)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs, const_refs_to_cell))] #[inline] #[must_use] pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { @@ -883,8 +883,8 @@ impl [T] { pub const fn swap(&mut self, a: usize, b: usize) { // FIXME: use swap_unchecked here (https://github.com/rust-lang/rust/pull/88540#issuecomment-944344343) // Can't take two mutable loans from one vector, so instead use raw pointers. - let pa = ptr::addr_of_mut!(self[a]); - let pb = ptr::addr_of_mut!(self[b]); + let pa = &raw mut self[a]; + let pb = &raw mut self[b]; // SAFETY: `pa` and `pb` have been created from safe mutable references and refer // to elements in the slice and therefore are guaranteed to be valid and aligned. // Note that accessing the elements behind `a` and `b` is checked and will @@ -1010,6 +1010,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "slice_iter")] pub fn iter(&self) -> Iter<'_, T> { Iter::new(self) } @@ -1952,7 +1953,7 @@ impl [T] { #[inline] #[must_use] pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { - // HACK: the const function `from_raw_parts` is used to make this + // FIXME(const-hack): the const function `from_raw_parts` is used to make this // function const; previously the implementation used // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` @@ -4088,7 +4089,7 @@ impl [T] { /// assert!(![0.0, 1.0, f32::NAN].is_sorted()); /// ``` #[inline] - #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "is_sorted", since = "1.82.0")] #[must_use] pub fn is_sorted(&self) -> bool where @@ -4115,7 +4116,7 @@ impl [T] { /// assert!(empty.is_sorted_by(|a, b| false)); /// assert!(empty.is_sorted_by(|a, b| true)); /// ``` - #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "is_sorted", since = "1.82.0")] #[must_use] pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool where @@ -4139,7 +4140,7 @@ impl [T] { /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); /// ``` #[inline] - #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "is_sorted", since = "1.82.0")] #[must_use] pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool where diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 85507eb8a7381..2cf3fecb47542 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -11,13 +11,13 @@ use crate::{array, ptr, ub_checks}; /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, +/// * `data` must be non-null, [valid] for reads for `len * mem::size_of::()` many bytes, /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single allocated object! /// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) /// for an example incorrectly not taking this into account. -/// * `data` must be non-null and aligned even for zero-length slices. One +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One /// reason for this is that enum layout optimizations may rely on references /// (including slices of any length) being aligned and non-null to distinguish /// them from other data. You can obtain a pointer that is usable as `data` @@ -146,12 +146,12 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `data` must be [valid] for both reads and writes for `len * mem::size_of::()` many bytes, +/// * `data` must be non-null, [valid] for both reads and writes for `len * mem::size_of::()` many bytes, /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single allocated object! /// Slices can never span across multiple allocated objects. -/// * `data` must be non-null and aligned even for zero-length slices. One +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One /// reason for this is that enum layout optimizations may rely on references /// (including slices of any length) being aligned and non-null to distinguish /// them from other data. You can obtain a pointer that is usable as `data` @@ -219,7 +219,7 @@ pub const fn from_mut(s: &mut T) -> &mut [T] { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * The `start` pointer of the range must be a [valid] and properly aligned pointer +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer /// to the first element of a slice. /// /// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* @@ -235,7 +235,7 @@ pub const fn from_mut(s: &mut T) -> &mut [T] { /// of lifetime `'a`, except inside an `UnsafeCell`. /// /// * The total length of the range must be no larger than `isize::MAX`, -/// and adding that size to `data` must not "wrap around" the address space. +/// and adding that size to `start` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. @@ -288,7 +288,7 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * The `start` pointer of the range must be a [valid] and properly aligned pointer +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer /// to the first element of a slice. /// /// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* @@ -305,7 +305,7 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { /// Both read and write accesses are forbidden. /// /// * The total length of the range must be no larger than `isize::MAX`, -/// and adding that size to `data` must not "wrap around" the address space. +/// and adding that size to `start` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. diff --git a/library/core/src/slice/sort/select.rs b/library/core/src/slice/sort/select.rs index f6529f23bcb3f..3358c03d30a9b 100644 --- a/library/core/src/slice/sort/select.rs +++ b/library/core/src/slice/sort/select.rs @@ -7,6 +7,7 @@ //! better performance than one would get using heapsort as fallback. use crate::mem::{self, SizedTypeProperties}; +#[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::shared::pivot::choose_pivot; use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; use crate::slice::sort::unstable::quicksort::partition; @@ -40,7 +41,13 @@ where let min_idx = min_index(v, &mut is_less).unwrap(); v.swap(min_idx, index); } else { - partition_at_index_loop(v, index, None, &mut is_less); + cfg_if! { + if #[cfg(feature = "optimize_for_size")] { + median_of_medians(v, &mut is_less, index); + } else { + partition_at_index_loop(v, index, None, &mut is_less); + } + } } let (left, right) = v.split_at_mut(index); @@ -53,6 +60,7 @@ where // most once, it doesn't make sense to use something more sophisticated than insertion-sort. const INSERTION_SORT_THRESHOLD: usize = 16; +#[cfg(not(feature = "optimize_for_size"))] fn partition_at_index_loop<'a, T, F>( mut v: &'a mut [T], mut index: usize, @@ -169,6 +177,7 @@ fn median_of_medians bool>(mut v: &mut [T], is_less: &mut if v.len() >= 2 { insertion_sort_shift_left(v, 1, is_less); } + return; } diff --git a/library/core/src/slice/sort/shared/mod.rs b/library/core/src/slice/sort/shared/mod.rs index ad1171bfc6a0a..e2cdcb3dd511d 100644 --- a/library/core/src/slice/sort/shared/mod.rs +++ b/library/core/src/slice/sort/shared/mod.rs @@ -1,3 +1,5 @@ +#![cfg_attr(any(feature = "optimize_for_size", target_pointer_width = "16"), allow(dead_code))] + use crate::marker::Freeze; pub(crate) mod pivot; diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index fae628a7c1474..6adf779a72f0c 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -378,7 +378,12 @@ where /// Swap two values in the slice pointed to by `v_base` at the position `a_pos` and `b_pos` if the /// value at position `b_pos` is less than the one at position `a_pos`. -pub unsafe fn swap_if_less(v_base: *mut T, a_pos: usize, b_pos: usize, is_less: &mut F) +/// +/// Purposefully not marked `#[inline]`, despite us wanting it to be inlined for integers like +/// types. `is_less` could be a huge function and we want to give the compiler an option to +/// not inline this function. For the same reasons that this function is very perf critical +/// it should be in the same module as the functions that use it. +unsafe fn swap_if_less(v_base: *mut T, a_pos: usize, b_pos: usize, is_less: &mut F) where F: FnMut(&T, &T) -> bool, { diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs index a383b0f589ccf..7adcc83b818d1 100644 --- a/library/core/src/slice/sort/stable/mod.rs +++ b/library/core/src/slice/sort/stable/mod.rs @@ -1,15 +1,24 @@ //! This module contains the entry points for `slice::sort`. +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] +use crate::cmp; +use crate::intrinsics; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::{ - insertion_sort_shift_left, StableSmallSortTypeImpl, SMALL_SORT_GENERAL_SCRATCH_LEN, + SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left, }; -use crate::{cmp, intrinsics}; -pub(crate) mod drift; pub(crate) mod merge; + +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] +pub(crate) mod drift; +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] pub(crate) mod quicksort; +#[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] +pub(crate) mod tiny; + /// Stable sort called driftsort by Orson Peters and Lukas Bergdoll. /// Design document: /// @@ -30,25 +39,53 @@ pub fn sort bool, BufT: BufGuard>(v: &mut [T], is_less return; } - // More advanced sorting methods than insertion sort are faster if called in - // a hot loop for small inputs, but for general-purpose code the small - // binary size of insertion sort is more important. The instruction cache in - // modern processors is very valuable, and for a single sort call in general - // purpose code any gains from an advanced method are cancelled by i-cache - // misses during the sort, and thrashing the i-cache for surrounding code. - const MAX_LEN_ALWAYS_INSERTION_SORT: usize = 20; - if intrinsics::likely(len <= MAX_LEN_ALWAYS_INSERTION_SORT) { - insertion_sort_shift_left(v, 1, is_less); - return; - } + cfg_if! { + if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] { + let alloc_len = len / 2; + + cfg_if! { + if #[cfg(target_pointer_width = "16")] { + let mut heap_buf = BufT::with_capacity(alloc_len); + let scratch = heap_buf.as_uninit_slice_mut(); + } else { + // For small inputs 4KiB of stack storage suffices, which allows us to avoid + // calling the (de-)allocator. Benchmarks showed this was quite beneficial. + let mut stack_buf = AlignedStorage::::new(); + let stack_scratch = stack_buf.as_uninit_slice_mut(); + let mut heap_buf; + let scratch = if stack_scratch.len() >= alloc_len { + stack_scratch + } else { + heap_buf = BufT::with_capacity(alloc_len); + heap_buf.as_uninit_slice_mut() + }; + } + } - driftsort_main::(v, is_less); + tiny::mergesort(v, scratch, is_less); + } else { + // More advanced sorting methods than insertion sort are faster if called in + // a hot loop for small inputs, but for general-purpose code the small + // binary size of insertion sort is more important. The instruction cache in + // modern processors is very valuable, and for a single sort call in general + // purpose code any gains from an advanced method are cancelled by i-cache + // misses during the sort, and thrashing the i-cache for surrounding code. + const MAX_LEN_ALWAYS_INSERTION_SORT: usize = 20; + if intrinsics::likely(len <= MAX_LEN_ALWAYS_INSERTION_SORT) { + insertion_sort_shift_left(v, 1, is_less); + return; + } + + driftsort_main::(v, is_less); + } + } } /// See [`sort`] /// /// Deliberately don't inline the main sorting routine entrypoint to ensure the /// inlined insertion sort i-cache footprint remains minimal. +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] #[inline(never)] fn driftsort_main bool, BufT: BufGuard>(v: &mut [T], is_less: &mut F) { // By allocating n elements of memory we can ensure the entire input can diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs index 3319d67ab52fa..0c8308bfce00e 100644 --- a/library/core/src/slice/sort/stable/quicksort.rs +++ b/library/core/src/slice/sort/stable/quicksort.rs @@ -1,9 +1,9 @@ //! This module contains a stable quicksort and partition implementation. use crate::mem::{self, ManuallyDrop, MaybeUninit}; +use crate::slice::sort::shared::FreezeMarker; use crate::slice::sort::shared::pivot::choose_pivot; use crate::slice::sort::shared::smallsort::StableSmallSortTypeImpl; -use crate::slice::sort::shared::FreezeMarker; use crate::{intrinsics, ptr}; /// Sorts `v` recursively using quicksort. diff --git a/library/core/src/slice/sort/stable/tiny.rs b/library/core/src/slice/sort/stable/tiny.rs new file mode 100644 index 0000000000000..071ab8e107fe3 --- /dev/null +++ b/library/core/src/slice/sort/stable/tiny.rs @@ -0,0 +1,41 @@ +//! Binary-size optimized mergesort inspired by https://github.com/voultapher/tiny-sort-rs. + +use crate::mem::MaybeUninit; +use crate::ptr; +use crate::slice::sort::stable::merge; + +/// Tiny recursive top-down merge sort optimized for binary size. It has no adaptiveness whatsoever, +/// no run detection, etc. +#[inline(always)] +pub fn mergesort bool>( + v: &mut [T], + scratch: &mut [MaybeUninit], + is_less: &mut F, +) { + let len = v.len(); + + if len > 2 { + let mid = len / 2; + + // SAFETY: mid is in-bounds. + unsafe { + // Sort the left half recursively. + mergesort(v.get_unchecked_mut(..mid), scratch, is_less); + // Sort the right half recursively. + mergesort(v.get_unchecked_mut(mid..), scratch, is_less); + } + + merge::merge(v, scratch, mid, is_less); + } else if len == 2 { + // SAFETY: We checked the len, the pointers we create are valid and don't overlap. + unsafe { + let v_base = v.as_mut_ptr(); + let v_a = v_base; + let v_b = v_base.add(1); + + if is_less(&*v_b, &*v_a) { + ptr::swap_nonoverlapping(v_a, v_b, 1); + } + } + } +} diff --git a/library/core/src/slice/sort/unstable/heapsort.rs b/library/core/src/slice/sort/unstable/heapsort.rs index 27e2ad588ea09..85231779d031f 100644 --- a/library/core/src/slice/sort/unstable/heapsort.rs +++ b/library/core/src/slice/sort/unstable/heapsort.rs @@ -1,46 +1,46 @@ //! This module contains a branchless heapsort as fallback for unstable quicksort. -use crate::{intrinsics, ptr}; +use crate::{cmp, intrinsics, ptr}; /// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case. /// /// Never inline this, it sits the main hot-loop in `recurse` and is meant as unlikely algorithmic /// fallback. -/// -/// SAFETY: The caller has to guarantee that `v.len()` >= 2. #[inline(never)] -pub(crate) unsafe fn heapsort(v: &mut [T], is_less: &mut F) +pub(crate) fn heapsort(v: &mut [T], is_less: &mut F) where F: FnMut(&T, &T) -> bool, { - // SAFETY: See function safety. - unsafe { - intrinsics::assume(v.len() >= 2); - - // Build the heap in linear time. - for i in (0..v.len() / 2).rev() { - sift_down(v, i, is_less); - } + let len = v.len(); - // Pop maximal elements from the heap. - for i in (1..v.len()).rev() { + for i in (0..len + len / 2).rev() { + let sift_idx = if i >= len { + i - len + } else { v.swap(0, i); - sift_down(&mut v[..i], 0, is_less); + 0 + }; + + // SAFETY: The above calculation ensures that `sift_idx` is either 0 or + // `(len..(len + (len / 2))) - len`, which simplifies to `0..(len / 2)`. + // This guarantees the required `sift_idx <= len`. + unsafe { + sift_down(&mut v[..cmp::min(i, len)], sift_idx, is_less); } } } // This binary heap respects the invariant `parent >= child`. // -// SAFETY: The caller has to guarantee that node < `v.len()`. -#[inline(never)] +// SAFETY: The caller has to guarantee that `node <= v.len()`. +#[inline(always)] unsafe fn sift_down(v: &mut [T], mut node: usize, is_less: &mut F) where F: FnMut(&T, &T) -> bool, { // SAFETY: See function safety. unsafe { - intrinsics::assume(node < v.len()); + intrinsics::assume(node <= v.len()); } let len = v.len(); @@ -69,9 +69,7 @@ where break; } - // Swap `node` with the greater child, move one step down, and continue sifting. This - // could be ptr::swap_nonoverlapping but that adds a significant amount of binary-size. - ptr::swap(v_base.add(node), v_base.add(child)); + ptr::swap_nonoverlapping(v_base.add(node), v_base.add(child), 1); } node = child; diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs index 932e01f4401e5..2eb653c4601a7 100644 --- a/library/core/src/slice/sort/unstable/mod.rs +++ b/library/core/src/slice/sort/unstable/mod.rs @@ -2,7 +2,9 @@ use crate::intrinsics; use crate::mem::SizedTypeProperties; +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::find_existing_run; +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; pub(crate) mod heapsort; @@ -28,25 +30,32 @@ pub fn sort bool>(v: &mut [T], is_less: &mut F) { return; } - // More advanced sorting methods than insertion sort are faster if called in - // a hot loop for small inputs, but for general-purpose code the small - // binary size of insertion sort is more important. The instruction cache in - // modern processors is very valuable, and for a single sort call in general - // purpose code any gains from an advanced method are cancelled by i-cache - // misses during the sort, and thrashing the i-cache for surrounding code. - const MAX_LEN_ALWAYS_INSERTION_SORT: usize = 20; - if intrinsics::likely(len <= MAX_LEN_ALWAYS_INSERTION_SORT) { - insertion_sort_shift_left(v, 1, is_less); - return; - } + cfg_if! { + if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] { + heapsort::heapsort(v, is_less); + } else { + // More advanced sorting methods than insertion sort are faster if called in + // a hot loop for small inputs, but for general-purpose code the small + // binary size of insertion sort is more important. The instruction cache in + // modern processors is very valuable, and for a single sort call in general + // purpose code any gains from an advanced method are cancelled by i-cache + // misses during the sort, and thrashing the i-cache for surrounding code. + const MAX_LEN_ALWAYS_INSERTION_SORT: usize = 20; + if intrinsics::likely(len <= MAX_LEN_ALWAYS_INSERTION_SORT) { + insertion_sort_shift_left(v, 1, is_less); + return; + } - ipnsort(v, is_less); + ipnsort(v, is_less); + } + } } /// See [`sort`] /// /// Deliberately don't inline the main sorting routine entrypoint to ensure the /// inlined insertion sort i-cache footprint remains minimal. +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] #[inline(never)] fn ipnsort(v: &mut [T], is_less: &mut F) where diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs index cd53656e9b4b8..4feef5deeb0fb 100644 --- a/library/core/src/slice/sort/unstable/quicksort.rs +++ b/library/core/src/slice/sort/unstable/quicksort.rs @@ -1,8 +1,12 @@ //! This module contains an unstable quicksort and two partition implementations. use crate::mem::{self, ManuallyDrop}; +#[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::shared::pivot::choose_pivot; +#[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::shared::smallsort::UnstableSmallSortTypeImpl; +#[cfg(not(feature = "optimize_for_size"))] +use crate::slice::sort::unstable::heapsort; use crate::{intrinsics, ptr}; /// Sorts `v` recursively. @@ -11,6 +15,7 @@ use crate::{intrinsics, ptr}; /// /// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero, /// this function will immediately switch to heapsort. +#[cfg(not(feature = "optimize_for_size"))] pub(crate) fn quicksort<'a, T, F>( mut v: &'a mut [T], mut ancestor_pivot: Option<&'a T>, @@ -28,10 +33,7 @@ pub(crate) fn quicksort<'a, T, F>( // If too many bad pivot choices were made, simply fall back to heapsort in order to // guarantee `O(N x log(N))` worst-case. if limit == 0 { - // SAFETY: We assume the `small_sort` threshold is at least 1. - unsafe { - crate::slice::sort::unstable::heapsort::heapsort(v, is_less); - } + heapsort::heapsort(v, is_less); return; } @@ -98,13 +100,15 @@ where return 0; } - // Allows for panic-free code-gen by proving this property to the compiler. if pivot >= len { intrinsics::abort(); } - // Place the pivot at the beginning of slice. - v.swap(0, pivot); + // SAFETY: We checked that `pivot` is in-bounds. + unsafe { + // Place the pivot at the beginning of slice. + v.swap_unchecked(0, pivot); + } let (pivot, v_without_pivot) = v.split_at_mut(1); // Assuming that Rust generates noalias LLVM IR we can be sure that a partition function @@ -118,8 +122,15 @@ where // compile-time by only instantiating the code that is needed. Idea by Frank Steffahn. let num_lt = (const { inst_partition::() })(v_without_pivot, pivot, is_less); - // Place the pivot between the two partitions. - v.swap(0, num_lt); + if num_lt >= len { + intrinsics::abort(); + } + + // SAFETY: We checked that `num_lt` is in-bounds. + unsafe { + // Place the pivot between the two partitions. + v.swap_unchecked(0, num_lt); + } num_lt } @@ -129,7 +140,13 @@ const fn inst_partition bool>() -> fn(&mut [T], &T, &mut if mem::size_of::() <= MAX_BRANCHLESS_PARTITION_SIZE { // Specialize for types that are relatively cheap to copy, where branchless optimizations // have large leverage e.g. `u64` and `String`. - partition_lomuto_branchless_cyclic:: + cfg_if! { + if #[cfg(feature = "optimize_for_size")] { + partition_lomuto_branchless_simple:: + } else { + partition_lomuto_branchless_cyclic:: + } + } } else { partition_hoare_branchy_cyclic:: } @@ -215,6 +232,7 @@ where } } +#[cfg(not(feature = "optimize_for_size"))] struct PartitionState { // The current element that is being looked at, scans left to right through slice. right: *mut T, @@ -225,6 +243,7 @@ struct PartitionState { gap: GapGuardRaw, } +#[cfg(not(feature = "optimize_for_size"))] fn partition_lomuto_branchless_cyclic(v: &mut [T], pivot: &T, is_less: &mut F) -> usize where F: FnMut(&T, &T) -> bool, @@ -316,6 +335,27 @@ where } } +#[cfg(feature = "optimize_for_size")] +fn partition_lomuto_branchless_simple bool>( + v: &mut [T], + pivot: &T, + is_less: &mut F, +) -> usize { + let mut left = 0; + + for right in 0..v.len() { + // SAFETY: `left` can at max be incremented by 1 each loop iteration, which implies that + // left <= right and that both are in-bounds. + unsafe { + let right_is_lt = is_less(v.get_unchecked(right), pivot); + v.swap_unchecked(left, right); + left += right_is_lt as usize; + } + } + + left +} + struct GapGuard { pos: *mut T, value: ManuallyDrop, @@ -333,11 +373,13 @@ impl Drop for GapGuard { /// Ideally this wouldn't be needed and we could just use the regular GapGuard. /// See comment in [`partition_lomuto_branchless_cyclic`]. +#[cfg(not(feature = "optimize_for_size"))] struct GapGuardRaw { pos: *mut T, value: *mut T, } +#[cfg(not(feature = "optimize_for_size"))] impl Drop for GapGuardRaw { fn drop(&mut self) { // SAFETY: `self` MUST be constructed in a way that makes copying the gap value into diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 1956a04829d1d..d6459607221ae 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -1,7 +1,7 @@ //! Ways to create a `str` from bytes slice. -use super::validations::run_utf8_validation; use super::Utf8Error; +use super::validations::run_utf8_validation; use crate::{mem, ptr}; /// Converts a slice of bytes to a string slice. @@ -85,7 +85,7 @@ use crate::{mem, ptr}; #[rustc_allow_const_fn_unstable(str_internals)] #[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { - // FIXME: This should use `?` again, once it's `const` + // FIXME(const-hack): This should use `?` again, once it's `const` match run_utf8_validation(v) { Ok(_) => { // SAFETY: validation succeeded. @@ -129,7 +129,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { - // This should use `?` again, once it's `const` + // FIXME(const-hack): This should use `?` again, once it's `const` match run_utf8_validation(v) { Ok(_) => { // SAFETY: validation succeeded. diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index a11b5add42ebf..4c8231a2286e1 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -100,7 +100,7 @@ impl Utf8Error { #[must_use] #[inline] pub const fn error_len(&self) -> Option { - // FIXME: This should become `map` again, once it's `const` + // FIXME(const-hack): This should become `map` again, once it's `const` match self.error_len { Some(len) => Some(len as usize), None => None, diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 681ec79c0b7bf..425c4eaee28ee 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -3,8 +3,8 @@ use super::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use super::validations::{next_code_point, next_code_point_reverse}; use super::{ - from_utf8_unchecked, BytesIsNotEmpty, CharEscapeDebugContinue, CharEscapeDefault, - CharEscapeUnicode, IsAsciiWhitespace, IsNotEmpty, IsWhitespace, LinesMap, UnsafeBytesToStr, + BytesIsNotEmpty, CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode, + IsAsciiWhitespace, IsNotEmpty, IsWhitespace, LinesMap, UnsafeBytesToStr, from_utf8_unchecked, }; use crate::fmt::{self, Write}; use crate::iter::{ @@ -269,7 +269,7 @@ impl<'a> CharIndices<'a> { /// ``` #[inline] #[must_use] - #[stable(feature = "char_indices_offset", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "char_indices_offset", since = "1.82.0")] pub fn offset(&self) -> usize { self.front_offset } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index cf9f1bfc0eb72..3d535214637f6 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -134,6 +134,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "str_len")] #[must_use] #[inline] pub const fn len(&self) -> usize { @@ -338,9 +339,10 @@ impl str { /// assert_eq!("🍔∈🌏", s); /// ``` #[stable(feature = "str_mut_extras", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_str_as_mut", issue = "130086")] #[must_use] #[inline(always)] - pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { + pub const unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { // SAFETY: the cast from `&str` to `&[u8]` is safe since `str` // has the same layout as `&[u8]` (only std can make this guarantee). // The pointer dereference is safe since it comes from a mutable reference which @@ -383,10 +385,11 @@ impl str { /// It is your responsibility to make sure that the string slice only gets /// modified in a way that it remains valid UTF-8. #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] + #[rustc_const_unstable(feature = "const_str_as_mut", issue = "130086")] #[rustc_never_returns_null_ptr] #[must_use] #[inline(always)] - pub fn as_mut_ptr(&mut self) -> *mut u8 { + pub const fn as_mut_ptr(&mut self) -> *mut u8 { self as *mut str as *mut u8 } @@ -830,6 +833,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "str_chars")] pub fn chars(&self) -> Chars<'_> { Chars { iter: self.as_bytes().iter() } } @@ -1154,6 +1158,7 @@ impl str { /// assert!(bananas.starts_with(&['a', 'b', 'c', 'd'])); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "str_starts_with")] pub fn starts_with(&self, pat: P) -> bool { pat.is_prefix_of(self) } @@ -1178,6 +1183,7 @@ impl str { /// assert!(!bananas.ends_with("nana")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "str_ends_with")] pub fn ends_with(&self, pat: P) -> bool where for<'a> P::Searcher<'a>: ReverseSearcher<'a>, @@ -2467,8 +2473,9 @@ impl str { /// assert_eq!("GRüßE, JüRGEN ❤", s); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_make_ascii", issue = "130698")] #[inline] - pub fn make_ascii_uppercase(&mut self) { + pub const fn make_ascii_uppercase(&mut self) { // SAFETY: changing ASCII letters only does not invalidate UTF-8. let me = unsafe { self.as_bytes_mut() }; me.make_ascii_uppercase() @@ -2494,8 +2501,9 @@ impl str { /// assert_eq!("grÜße, jÜrgen ❤", s); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_make_ascii", issue = "130698")] #[inline] - pub fn make_ascii_lowercase(&mut self) { + pub const fn make_ascii_lowercase(&mut self) { // SAFETY: changing ASCII letters only does not invalidate UTF-8. let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() @@ -2734,6 +2742,17 @@ impl str { pub fn substr_range(&self, substr: &str) -> Option> { self.as_bytes().subslice_range(substr.as_bytes()) } + + /// Returns the same string as a string slice `&str`. + /// + /// This method is redundant when used directly on `&str`, but + /// it helps dereferencing other string-like types to string slices, + /// for example references to `Box` or `Arc`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub fn as_str(&self) -> &str { + self + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 2f1096db8f00c..9f1294d760647 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -1814,7 +1814,7 @@ fn simd_contains(needle: &str, haystack: &str) -> Option { } mask &= !(1 << trailing); } - return false; + false }; let test_chunk = |idx| -> u16 { @@ -1830,7 +1830,7 @@ fn simd_contains(needle: &str, haystack: &str) -> Option { let both = eq_first.bitand(eq_last); let mask = both.to_bitmask() as u16; - return mask; + mask }; let mut i = 0; diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index b69c476ae5e53..77c70b978fd15 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -92,7 +92,6 @@ const fn str_index_overflow_fail() -> ! { /// /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex for ops::RangeFull { type Output = str; #[inline] @@ -157,7 +156,6 @@ unsafe impl SliceIndex for ops::RangeFull { /// // &s[3 .. 100]; /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex for ops::Range { type Output = str; #[inline] @@ -429,7 +427,6 @@ unsafe impl SliceIndex for (ops::Bound, ops::Bound) { /// Panics if `end` does not point to the starting byte offset of a /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex for ops::RangeTo { type Output = str; #[inline] @@ -498,7 +495,6 @@ unsafe impl SliceIndex for ops::RangeTo { /// Panics if `begin` does not point to the starting byte offset of /// a character (as defined by `is_char_boundary`), or if `begin > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex for ops::RangeFrom { type Output = str; #[inline] @@ -625,7 +621,6 @@ unsafe impl SliceIndex for range::RangeFrom { /// to the ending byte offset of a character (`end + 1` is either a starting /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] @@ -714,7 +709,6 @@ unsafe impl SliceIndex for range::RangeInclusive { /// (`end + 1` is either a starting byte offset as defined by /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -#[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 495d9191a9f85..b06a3bd4487d3 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -3570,10 +3570,9 @@ unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { /// An atomic fence. /// -/// Depending on the specified order, a fence prevents the compiler and CPU from -/// reordering certain types of memory operations around it. -/// That creates synchronizes-with relationships between it and atomic operations -/// or fences in other threads. +/// Fences create synchronization between themselves and atomic operations or fences in other +/// threads. To achieve this, a fence prevents the compiler and CPU from reordering certain types of +/// memory operations around it. /// /// A fence 'A' which has (at least) [`Release`] ordering semantics, synchronizes /// with a fence 'B' with (at least) [`Acquire`] semantics, if and only if there @@ -3594,6 +3593,12 @@ unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { /// } /// ``` /// +/// Note that in the example above, it is crucial that the accesses to `x` are atomic. Fences cannot +/// be used to establish synchronization among non-atomic accesses in different threads. However, +/// thanks to the happens-before relationship between A and B, any non-atomic accesses that +/// happen-before A are now also properly synchronized with any non-atomic accesses that +/// happen-after B. +/// /// Atomic operations with [`Release`] or [`Acquire`] semantics can also synchronize /// with a fence. /// @@ -3659,33 +3664,30 @@ pub fn fence(order: Ordering) { } } -/// A compiler memory fence. +/// A "compiler-only" atomic fence. /// -/// `compiler_fence` does not emit any machine code, but restricts the kinds -/// of memory re-ordering the compiler is allowed to do. Specifically, depending on -/// the given [`Ordering`] semantics, the compiler may be disallowed from moving reads -/// or writes from before or after the call to the other side of the call to -/// `compiler_fence`. Note that it does **not** prevent the *hardware* -/// from doing such re-ordering. This is not a problem in a single-threaded, -/// execution context, but when other threads may modify memory at the same -/// time, stronger synchronization primitives such as [`fence`] are required. +/// Like [`fence`], this function establishes synchronization with other atomic operations and +/// fences. However, unlike [`fence`], `compiler_fence` only establishes synchronization with +/// operations *in the same thread*. This may at first sound rather useless, since code within a +/// thread is typically already totally ordered and does not need any further synchronization. +/// However, there are cases where code can run on the same thread without being ordered: +/// - The most common case is that of a *signal handler*: a signal handler runs in the same thread +/// as the code it interrupted, but it is not ordered with respect to that code. `compiler_fence` +/// can be used to establish synchronization between a thread and its signal handler, the same way +/// that `fence` can be used to establish synchronization across threads. +/// - Similar situations can arise in embedded programming with interrupt handlers, or in custom +/// implementations of preemptive green threads. In general, `compiler_fence` can establish +/// synchronization with code that is guaranteed to run on the same hardware CPU. /// -/// The re-ordering prevented by the different ordering semantics are: +/// See [`fence`] for how a fence can be used to achieve synchronization. Note that just like +/// [`fence`], synchronization still requires atomic operations to be used in both threads -- it is +/// not possible to perform synchronization entirely with fences and non-atomic operations. /// -/// - with [`SeqCst`], no re-ordering of reads and writes across this point is allowed. -/// - with [`Release`], preceding reads and writes cannot be moved past subsequent writes. -/// - with [`Acquire`], subsequent reads and writes cannot be moved ahead of preceding reads. -/// - with [`AcqRel`], both of the above rules are enforced. +/// `compiler_fence` does not emit any machine code, but restricts the kinds of memory re-ordering +/// the compiler is allowed to do. `compiler_fence` corresponds to [`atomic_signal_fence`] in C and +/// C++. /// -/// `compiler_fence` is generally only useful for preventing a thread from -/// racing *with itself*. That is, if a given thread is executing one piece -/// of code, and is then interrupted, and starts executing code elsewhere -/// (while still in the same thread, and conceptually still on the same -/// core). In traditional programs, this can only occur when a signal -/// handler is registered. In more low-level code, such situations can also -/// arise when handling interrupts, when implementing green threads with -/// pre-emption, etc. Curious readers are encouraged to read the Linux kernel's -/// discussion of [memory barriers]. +/// [`atomic_signal_fence`]: https://en.cppreference.com/w/cpp/atomic/atomic_signal_fence /// /// # Panics /// @@ -3723,8 +3725,6 @@ pub fn fence(order: Ordering) { /// } /// } /// ``` -/// -/// [memory barriers]: https://www.kernel.org/doc/Documentation/memory-barriers.txt #[inline] #[stable(feature = "compiler_fences", since = "1.21.0")] #[rustc_diagnostic_item = "compiler_fence"] diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 7e5c1574f5367..fc549abd43365 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -2,7 +2,7 @@ use crate::any::Any; use crate::marker::PhantomData; -use crate::mem::{transmute, ManuallyDrop}; +use crate::mem::{ManuallyDrop, transmute}; use crate::panic::AssertUnwindSafe; use crate::{fmt, ptr}; @@ -60,22 +60,6 @@ impl RawWaker { RawWaker { data, vtable } } - /// Gets the `data` pointer used to create this `RawWaker`. - #[inline] - #[must_use] - #[unstable(feature = "waker_getters", issue = "96992")] - pub fn data(&self) -> *const () { - self.data - } - - /// Gets the `vtable` pointer used to create this `RawWaker`. - #[inline] - #[must_use] - #[unstable(feature = "waker_getters", issue = "96992")] - pub fn vtable(&self) -> &'static RawWakerVTable { - self.vtable - } - #[unstable(feature = "noop_waker", issue = "98286")] const NOOP: RawWaker = { const VTABLE: RawWakerVTable = RawWakerVTable::new( @@ -250,7 +234,7 @@ pub struct Context<'a> { impl<'a> Context<'a> { /// Creates a new `Context` from a [`&Waker`](Waker). #[stable(feature = "futures_api", since = "1.36.0")] - #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] #[must_use] #[inline] pub const fn from_waker(waker: &'a Waker) -> Self { @@ -261,7 +245,7 @@ impl<'a> Context<'a> { #[inline] #[must_use] #[stable(feature = "futures_api", since = "1.36.0")] - #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] pub const fn waker(&self) -> &'a Waker { &self.waker } @@ -337,7 +321,7 @@ impl<'a> ContextBuilder<'a> { /// Creates a ContextBuilder from a Waker. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] pub const fn from_waker(waker: &'a Waker) -> Self { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; @@ -395,7 +379,7 @@ impl<'a> ContextBuilder<'a> { /// Builds the `Context`. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] pub const fn build(self) -> Context<'a> { let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self; Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 } @@ -430,6 +414,7 @@ impl<'a> ContextBuilder<'a> { /// [`Wake`]: ../../alloc/task/trait.Wake.html #[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Waker")] pub struct Waker { waker: RawWaker, } @@ -509,6 +494,37 @@ impl Waker { a_data == b_data && ptr::eq(a_vtable, b_vtable) } + /// Creates a new `Waker` from the provided `data` pointer and `vtable`. + /// + /// The `data` pointer can be used to store arbitrary data as required + /// by the executor. This could be e.g. a type-erased pointer to an `Arc` + /// that is associated with the task. + /// The value of this pointer will get passed to all functions that are part + /// of the `vtable` as the first parameter. + /// + /// It is important to consider that the `data` pointer must point to a + /// thread safe type such as an `Arc`. + /// + /// The `vtable` customizes the behavior of a `Waker`. For each operation + /// on the `Waker`, the associated function in the `vtable` will be called. + /// + /// # Safety + /// + /// The behavior of the returned `Waker` is undefined if the contract defined + /// in [`RawWakerVTable`]'s documentation is not upheld. + /// + /// (Authors wishing to avoid unsafe code may implement the [`Wake`] trait instead, at the + /// cost of a required heap allocation.) + /// + /// [`Wake`]: ../../alloc/task/trait.Wake.html + #[inline] + #[must_use] + #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")] + pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self { + Waker { waker: RawWaker { data, vtable } } + } + /// Creates a new `Waker` from [`RawWaker`]. /// /// # Safety @@ -523,7 +539,7 @@ impl Waker { #[inline] #[must_use] #[stable(feature = "futures_api", since = "1.36.0")] - #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] pub const unsafe fn from_raw(waker: RawWaker) -> Waker { Waker { waker } } @@ -565,12 +581,20 @@ impl Waker { WAKER } - /// Gets a reference to the underlying [`RawWaker`]. + /// Gets the `data` pointer used to create this `Waker`. #[inline] #[must_use] - #[unstable(feature = "waker_getters", issue = "96992")] - pub fn as_raw(&self) -> &RawWaker { - &self.waker + #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")] + pub fn data(&self) -> *const () { + self.waker.data + } + + /// Gets the `vtable` pointer used to create this `Waker`. + #[inline] + #[must_use] + #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")] + pub fn vtable(&self) -> &'static RawWakerVTable { + self.waker.vtable } } @@ -778,6 +802,30 @@ impl LocalWaker { a_data == b_data && ptr::eq(a_vtable, b_vtable) } + /// Creates a new `LocalWaker` from the provided `data` pointer and `vtable`. + /// + /// The `data` pointer can be used to store arbitrary data as required + /// by the executor. This could be e.g. a type-erased pointer to an `Arc` + /// that is associated with the task. + /// The value of this pointer will get passed to all functions that are part + /// of the `vtable` as the first parameter. + /// + /// The `vtable` customizes the behavior of a `LocalWaker`. For each + /// operation on the `LocalWaker`, the associated function in the `vtable` + /// will be called. + /// + /// # Safety + /// + /// The behavior of the returned `Waker` is undefined if the contract defined + /// in [`RawWakerVTable`]'s documentation is not upheld. + /// + #[inline] + #[must_use] + #[unstable(feature = "local_waker", issue = "118959")] + pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self { + LocalWaker { waker: RawWaker { data, vtable } } + } + /// Creates a new `LocalWaker` from [`RawWaker`]. /// /// The behavior of the returned `LocalWaker` is undefined if the contract defined @@ -831,12 +879,20 @@ impl LocalWaker { WAKER } - /// Gets a reference to the underlying [`RawWaker`]. + /// Gets the `data` pointer used to create this `LocalWaker`. #[inline] #[must_use] - #[unstable(feature = "waker_getters", issue = "96992")] - pub fn as_raw(&self) -> &RawWaker { - &self.waker + #[unstable(feature = "local_waker", issue = "118959")] + pub fn data(&self) -> *const () { + self.waker.data + } + + /// Gets the `vtable` pointer used to create this `LocalWaker`. + #[inline] + #[must_use] + #[unstable(feature = "local_waker", issue = "118959")] + pub fn vtable(&self) -> &'static RawWakerVTable { + self.waker.vtable } } #[unstable(feature = "local_waker", issue = "118959")] diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 0390bb59a8984..65560dfcf9d2d 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -213,6 +213,7 @@ impl Duration { // SAFETY: nanos < NANOS_PER_SEC, therefore nanos is within the valid range Duration { secs, nanos: unsafe { Nanoseconds(nanos) } } } else { + // FIXME(const-hack): use `.expect` once that is possible. let secs = match secs.checked_add((nanos / NANOS_PER_SEC) as u64) { Some(secs) => secs, None => panic!("overflow in Duration::new"), @@ -250,7 +251,7 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::from_millis(2569); + /// let duration = Duration::from_millis(2_569); /// /// assert_eq!(2, duration.as_secs()); /// assert_eq!(569_000_000, duration.subsec_nanos()); @@ -279,7 +280,7 @@ impl Duration { /// let duration = Duration::from_micros(1_000_002); /// /// assert_eq!(1, duration.as_secs()); - /// assert_eq!(2000, duration.subsec_nanos()); + /// assert_eq!(2_000, duration.subsec_nanos()); /// ``` #[stable(feature = "duration_from_micros", since = "1.27.0")] #[must_use] @@ -472,7 +473,7 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::new(5, 730023852); + /// let duration = Duration::new(5, 730_023_852); /// assert_eq!(duration.as_secs(), 5); /// ``` /// @@ -501,7 +502,7 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::from_millis(5432); + /// let duration = Duration::from_millis(5_432); /// assert_eq!(duration.as_secs(), 5); /// assert_eq!(duration.subsec_millis(), 432); /// ``` @@ -547,7 +548,7 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::from_millis(5010); + /// let duration = Duration::from_millis(5_010); /// assert_eq!(duration.as_secs(), 5); /// assert_eq!(duration.subsec_nanos(), 10_000_000); /// ``` @@ -566,8 +567,8 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::new(5, 730023852); - /// assert_eq!(duration.as_millis(), 5730); + /// let duration = Duration::new(5, 730_023_852); + /// assert_eq!(duration.as_millis(), 5_730); /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] @@ -584,8 +585,8 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::new(5, 730023852); - /// assert_eq!(duration.as_micros(), 5730023); + /// let duration = Duration::new(5, 730_023_852); + /// assert_eq!(duration.as_micros(), 5_730_023); /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] @@ -602,8 +603,8 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::new(5, 730023852); - /// assert_eq!(duration.as_nanos(), 5730023852); + /// let duration = Duration::new(5, 730_023_852); + /// assert_eq!(duration.as_nanos(), 5_730_023_852); /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] @@ -768,6 +769,7 @@ impl Duration { let total_nanos = self.nanos.0 as u64 * rhs as u64; let extra_secs = total_nanos / (NANOS_PER_SEC as u64); let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; + // FIXME(const-hack): use `and_then` once that is possible. if let Some(s) = self.secs.checked_mul(rhs as u64) { if let Some(secs) = s.checked_add(extra_secs) { debug_assert!(nanos < NANOS_PER_SEC); @@ -879,7 +881,7 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 345_678_000); - /// assert_eq!(dur.as_millis_f64(), 2345.678); + /// assert_eq!(dur.as_millis_f64(), 2_345.678); /// ``` #[unstable(feature = "duration_millis_float", issue = "122451")] #[must_use] @@ -900,7 +902,7 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 345_678_000); - /// assert_eq!(dur.as_millis_f32(), 2345.678); + /// assert_eq!(dur.as_millis_f32(), 2_345.678); /// ``` #[unstable(feature = "duration_millis_float", issue = "122451")] #[must_use] @@ -1017,7 +1019,7 @@ impl Duration { /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_641)); - /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0)); + /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 9ec92e2845034..206b5b9e2c24f 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -154,7 +154,7 @@ macro_rules! tuple_impls { // Otherwise, it hides the docs entirely. macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/unicode/printable.rs b/library/core/src/unicode/printable.rs index 33c3ef8083de5..d8fb50e4ed296 100644 --- a/library/core/src/unicode/printable.rs +++ b/library/core/src/unicode/printable.rs @@ -118,7 +118,7 @@ const SINGLETONS0U: &[(u8, u8)] = &[ (0x30, 4), (0x31, 2), (0x32, 1), - (0xa7, 2), + (0xa7, 4), (0xa9, 2), (0xaa, 4), (0xab, 8), @@ -155,17 +155,18 @@ const SINGLETONS0L: &[u8] = &[ 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, 0xff, 0x80, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, - 0xaf, 0x7f, 0xbb, 0xbc, 0x16, 0x17, 0x1e, 0x1f, + 0xaf, 0x4d, 0xbb, 0xbc, 0x16, 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x00, 0x40, 0x97, 0x98, - 0x30, 0x8f, 0x1f, 0xd2, 0xd4, 0xce, 0xff, 0x4e, - 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, - 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, - 0x42, 0x45, 0x90, 0x91, 0x53, 0x67, 0x75, 0xc8, - 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, + 0x30, 0x8f, 0x1f, 0xce, 0xcf, 0xd2, 0xd4, 0xce, + 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, + 0x10, 0x27, 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, + 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, 0x53, 0x67, + 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, + 0xfe, 0xff, ]; #[rustfmt::skip] const SINGLETONS1U: &[(u8, u8)] = &[ @@ -183,7 +184,7 @@ const SINGLETONS1U: &[(u8, u8)] = &[ (0x10, 1), (0x11, 2), (0x12, 5), - (0x13, 17), + (0x13, 28), (0x14, 1), (0x15, 2), (0x17, 2), @@ -211,7 +212,7 @@ const SINGLETONS1U: &[(u8, u8)] = &[ (0xee, 32), (0xf0, 4), (0xf8, 2), - (0xfa, 3), + (0xfa, 4), (0xfb, 1), ]; #[rustfmt::skip] @@ -224,23 +225,24 @@ const SINGLETONS1L: &[u8] = &[ 0xbd, 0x35, 0xe0, 0x12, 0x87, 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, - 0x65, 0x5c, 0xb6, 0xb7, 0x1b, 0x1c, 0x07, 0x08, - 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, - 0xa9, 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, - 0x07, 0x0a, 0x3b, 0x3e, 0x66, 0x69, 0x8f, 0x92, - 0x11, 0x6f, 0x5f, 0xbf, 0xee, 0xef, 0x5a, 0x62, - 0xf4, 0xfc, 0xff, 0x53, 0x54, 0x9a, 0x9b, 0x2e, - 0x2f, 0x27, 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, - 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, 0xc4, 0x06, - 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, - 0xa6, 0xa7, 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, - 0x22, 0x25, 0x3e, 0x3f, 0xe7, 0xec, 0xef, 0xff, - 0xc5, 0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, - 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, - 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, - 0x65, 0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, - 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0xae, 0xaf, - 0x6e, 0x6f, 0xbe, 0x93, + 0x65, 0x8a, 0x8c, 0x8d, 0x8f, 0xb6, 0xc1, 0xc3, + 0xc4, 0xc6, 0xcb, 0xd6, 0x5c, 0xb6, 0xb7, 0x1b, + 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, + 0x39, 0x3a, 0xa8, 0xa9, 0xd8, 0xd9, 0x09, 0x37, + 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x11, 0x6f, 0x5f, 0xbf, 0xee, + 0xef, 0x5a, 0x62, 0xf4, 0xfc, 0xff, 0x53, 0x54, + 0x9a, 0x9b, 0x2e, 0x2f, 0x27, 0x28, 0x55, 0x9d, + 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, + 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, + 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, 0xa0, + 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xe7, + 0xec, 0xef, 0xff, 0xc5, 0xc6, 0x04, 0x20, 0x23, + 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, + 0x4c, 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, + 0x5e, 0x60, 0x63, 0x65, 0x66, 0x6b, 0x73, 0x78, + 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, + 0xd0, 0xae, 0xaf, 0x6e, 0x6f, 0xdd, 0xde, 0x93, ]; #[rustfmt::skip] const NORMAL0: &[u8] = &[ @@ -252,8 +254,8 @@ const NORMAL0: &[u8] = &[ 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x05, - 0x1f, 0x09, - 0x81, 0x1b, 0x03, + 0x1f, 0x08, + 0x81, 0x1c, 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, @@ -318,11 +320,10 @@ const NORMAL0: &[u8] = &[ 0x80, 0xac, 0x06, 0x0a, 0x06, 0x2f, 0x31, - 0x4d, 0x03, - 0x80, 0xa4, 0x08, + 0x80, 0xf4, 0x08, 0x3c, 0x03, 0x0f, 0x03, - 0x3c, 0x07, + 0x3e, 0x05, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, @@ -332,7 +333,7 @@ const NORMAL0: &[u8] = &[ 0x21, 0x0f, 0x21, 0x0f, 0x80, 0x8c, 0x04, - 0x82, 0x97, 0x19, + 0x82, 0x9a, 0x16, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, @@ -343,13 +344,12 @@ const NORMAL0: &[u8] = &[ 0x74, 0x0c, 0x80, 0xd6, 0x1a, 0x81, 0x10, 0x05, - 0x80, 0xdf, 0x0b, + 0x80, 0xe1, 0x09, 0xf2, 0x9e, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, - 0x80, 0xcb, 0x05, - 0x0a, 0x18, + 0x80, 0xdd, 0x15, 0x3b, 0x03, 0x0a, 0x06, 0x38, 0x08, @@ -402,7 +402,8 @@ const NORMAL1: &[u8] = &[ 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, - 0x4e, 0x43, + 0x4e, 0x03, + 0x34, 0x0c, 0x81, 0x37, 0x09, 0x16, 0x0a, 0x08, 0x18, @@ -431,9 +432,13 @@ const NORMAL1: &[u8] = &[ 0x33, 0x0d, 0x33, 0x07, 0x2e, 0x08, - 0x0a, 0x81, 0x26, - 0x52, 0x4b, - 0x2b, 0x08, + 0x0a, 0x06, + 0x26, 0x03, + 0x1d, 0x08, + 0x02, 0x80, 0xd0, + 0x52, 0x10, + 0x03, 0x37, + 0x2c, 0x08, 0x2a, 0x16, 0x1a, 0x26, 0x1c, 0x14, @@ -453,7 +458,9 @@ const NORMAL1: &[u8] = &[ 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, - 0x05, 0x80, 0x8b, + 0x05, 0x0b, + 0x59, 0x08, + 0x02, 0x1d, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, @@ -462,7 +469,8 @@ const NORMAL1: &[u8] = &[ 0x0a, 0x06, 0x0d, 0x13, 0x3a, 0x06, - 0x0a, 0x36, + 0x0a, 0x06, + 0x14, 0x1c, 0x2c, 0x04, 0x17, 0x80, 0xb9, 0x3c, 0x64, @@ -473,7 +481,9 @@ const NORMAL1: &[u8] = &[ 0x48, 0x08, 0x53, 0x0d, 0x49, 0x07, - 0x0a, 0x80, 0xf6, + 0x0a, 0x80, 0xb6, + 0x22, 0x0e, + 0x0a, 0x06, 0x46, 0x0a, 0x1d, 0x03, 0x47, 0x49, @@ -484,7 +494,7 @@ const NORMAL1: &[u8] = &[ 0x0a, 0x81, 0x36, 0x19, 0x07, 0x3b, 0x03, - 0x1c, 0x56, + 0x1d, 0x55, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, @@ -492,15 +502,18 @@ const NORMAL1: &[u8] = &[ 0x80, 0xc4, 0x8a, 0x4c, 0x63, 0x0d, 0x84, 0x30, 0x10, - 0x16, 0x8f, 0xaa, - 0x82, 0x47, 0xa1, 0xb9, + 0x16, 0x0a, + 0x8f, 0x9b, 0x05, + 0x82, 0x47, 0x9a, 0xb9, + 0x3a, 0x86, 0xc6, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x5c, 0x06, 0x26, 0x0a, 0x46, 0x0a, 0x28, 0x05, - 0x13, 0x82, 0xb0, + 0x13, 0x81, 0xb0, + 0x3a, 0x80, 0xc6, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, @@ -508,8 +521,8 @@ const NORMAL1: &[u8] = &[ 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, - 0x84, 0xd6, 0x2a, - 0x09, 0xa2, 0xe7, + 0x84, 0xd6, 0x29, + 0x0a, 0xa2, 0xe7, 0x81, 0x33, 0x0f, 0x01, 0x1d, 0x06, 0x0e, @@ -518,7 +531,9 @@ const NORMAL1: &[u8] = &[ 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, - 0x10, 0x92, 0x60, + 0x10, 0x8f, 0x60, + 0x80, 0xfa, 0x06, + 0x81, 0xb4, 0x4c, 0x47, 0x09, 0x74, 0x3c, 0x80, 0xf6, 0x0a, @@ -543,7 +558,9 @@ const NORMAL1: &[u8] = &[ 0x1f, 0x11, 0x3a, 0x05, 0x01, 0x81, 0xd0, - 0x2a, 0x82, 0xe6, + 0x2a, 0x80, 0xd6, + 0x2b, 0x04, + 0x01, 0x81, 0xe0, 0x80, 0xf7, 0x29, 0x4c, 0x04, 0x0a, 0x04, @@ -575,14 +592,13 @@ const NORMAL1: &[u8] = &[ 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, - 0x22, 0x4e, + 0x2c, 0x04, + 0x02, 0x3e, 0x81, 0x54, 0x0c, 0x1d, 0x03, + 0x0a, 0x05, + 0x38, 0x07, + 0x1c, 0x06, 0x09, 0x07, - 0x36, 0x08, - 0x0e, 0x04, - 0x09, 0x07, - 0x09, 0x07, - 0x80, 0xcb, 0x25, - 0x0a, 0x84, 0x06, + 0x80, 0xfa, 0x84, 0x06, ]; diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index 1b3d6729663b5..db2e3ddd754f5 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -18,16 +18,14 @@ const fn bitset_search< let bucket_idx = (needle / 64) as usize; let chunk_map_idx = bucket_idx / CHUNK_SIZE; let chunk_piece = bucket_idx % CHUNK_SIZE; - // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` - // feature stabilizes. + // FIXME(const-hack): Revert to `slice::get` when slice indexing becomes possible in const. let chunk_idx = if chunk_map_idx < chunk_idx_map.len() { chunk_idx_map[chunk_map_idx] } else { return false; }; let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize; - // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` - // feature stabilizes. + // FIXME(const-hack): Revert to `slice::get` when slice indexing becomes possible in const. let word = if idx < bitset_canonical.len() { bitset_canonical[idx] } else { @@ -99,75 +97,77 @@ fn skip_search( offset_idx % 2 == 1 } -pub const UNICODE_VERSION: (u8, u8, u8) = (15, 1, 0); +pub const UNICODE_VERSION: (u8, u8, u8) = (16, 0, 0); #[rustfmt::skip] pub mod alphabetic { - static SHORT_OFFSET_RUNS: [u32; 54] = [ - 706, 33559113, 872420973, 952114966, 1161831606, 1310731264, 1314926597, 1394619392, - 1444957632, 1447077005, 1451271693, 1459672996, 1648425216, 1658911342, 1661009214, - 1707147904, 1793132343, 1887506048, 2040601600, 2392923872, 2481005466, 2504077200, - 2514564144, 2520859648, 2527151687, 2529257472, 2531355193, 2533453376, 2564917240, - 2596375766, 2600579056, 2606870819, 2621551356, 2642525184, 2644628480, 2665600678, - 2743197440, 2791432848, 2841765072, 2850154464, 2854350336, 2887905584, 3026321408, - 3038947040, 3041048378, 3045248674, 3053644769, 3057839710, 3062036480, 3064134174, - 3066232832, 3068334923, 3070436272, 3075744688, + static SHORT_OFFSET_RUNS: [u32; 53] = [ + 706, 33559113, 876615277, 956309270, 1166025910, 1314925568, 1319120901, 1398813696, + 1449151936, 1451271309, 1455465997, 1463867300, 1652619520, 1663105646, 1665203518, + 1711342208, 1797326647, 1895898848, 2560697242, 2583768976, 2594255920, 2600551419, + 2608940615, 2613141760, 2615240704, 2619435577, 2621533504, 2652997624, 2688650454, + 2692853744, 2699145507, 2713826044, 2734799872, 2736903168, 2757875366, 2835472128, + 2883707536, 2934039760, 2942429152, 2955013632, 2988568880, 3126984704, 3139610336, + 3141711674, 3145911970, 3154308065, 3158503006, 3162699776, 3164797470, 3166896128, + 3168998219, 3171099568, 3176407984, ]; - static OFFSETS: [u8; 1467] = [ - 65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 42, - 5, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39, - 14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10, - 3, 2, 1, 16, 48, 13, 101, 24, 33, 9, 2, 4, 1, 5, 24, 2, 19, 19, 25, 7, 11, 5, 24, 1, 6, 17, - 42, 10, 12, 3, 7, 6, 76, 1, 16, 1, 3, 4, 15, 13, 19, 1, 8, 2, 2, 2, 22, 1, 7, 1, 1, 3, 4, 3, - 8, 2, 2, 2, 2, 1, 1, 8, 1, 4, 2, 1, 5, 12, 2, 10, 1, 4, 3, 1, 6, 4, 2, 2, 22, 1, 7, 1, 2, 1, - 2, 1, 2, 4, 5, 4, 2, 2, 2, 4, 1, 7, 4, 1, 1, 17, 6, 11, 3, 1, 9, 1, 3, 1, 22, 1, 7, 1, 2, 1, - 5, 3, 9, 1, 3, 1, 2, 3, 1, 15, 4, 21, 4, 4, 3, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, - 2, 2, 2, 9, 2, 4, 2, 1, 5, 13, 1, 16, 2, 1, 6, 3, 3, 1, 4, 3, 2, 1, 1, 1, 2, 3, 2, 3, 3, 3, - 12, 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 13, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, 2, 1, 3, - 2, 1, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 6, 2, 1, 4, 13, - 3, 12, 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3, 24, 1, 9, - 1, 1, 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24, 1, 1, 1, - 19, 1, 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 19, 4, 16, 1, 36, 67, 55, 1, 1, - 2, 5, 16, 64, 10, 4, 2, 38, 1, 1, 5, 1, 2, 43, 1, 0, 1, 4, 2, 7, 1, 1, 1, 4, 2, 41, 1, 4, 2, - 33, 1, 4, 2, 7, 1, 1, 1, 4, 2, 15, 1, 57, 1, 4, 2, 67, 37, 16, 16, 86, 2, 6, 3, 0, 2, 17, 1, - 26, 5, 75, 3, 11, 7, 20, 11, 21, 12, 20, 12, 13, 1, 3, 1, 2, 12, 52, 2, 19, 14, 1, 4, 1, 67, - 89, 7, 43, 5, 70, 10, 31, 1, 12, 4, 9, 23, 30, 2, 5, 11, 44, 4, 26, 54, 28, 4, 63, 2, 20, - 50, 1, 23, 2, 11, 3, 49, 52, 1, 15, 1, 8, 51, 42, 2, 4, 10, 44, 1, 11, 14, 55, 22, 3, 10, - 36, 2, 9, 7, 43, 2, 3, 41, 4, 1, 6, 1, 2, 3, 1, 5, 192, 39, 14, 11, 0, 2, 6, 2, 38, 2, 6, 2, - 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1, 7, - 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, 1, 11, 2, 4, - 5, 5, 4, 1, 17, 41, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1, 16, 23, 9, - 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2, 5, 4, 86, - 6, 3, 1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 67, 46, 2, 0, 3, 16, 10, 2, - 20, 47, 5, 8, 3, 113, 39, 9, 2, 103, 2, 64, 5, 2, 1, 1, 1, 5, 24, 20, 1, 33, 24, 52, 12, 68, - 1, 1, 44, 6, 3, 1, 1, 3, 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5, 1, 55, - 9, 14, 18, 23, 3, 69, 1, 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7, 1, 43, - 1, 14, 6, 123, 21, 0, 12, 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5, 1, 1, - 1, 2, 1, 2, 1, 108, 33, 0, 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11, 89, 3, - 6, 2, 6, 2, 6, 2, 3, 35, 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0, 29, 3, - 49, 47, 32, 13, 30, 5, 43, 5, 30, 2, 36, 4, 8, 1, 5, 42, 158, 18, 36, 4, 36, 4, 40, 8, 52, - 12, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 67, 0, 9, 22, 10, 8, 24, 6, 1, 42, 1, - 9, 69, 6, 2, 1, 1, 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, 10, 22, 10, 26, 70, - 56, 6, 2, 64, 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, 27, 54, 10, 22, 10, - 19, 13, 18, 110, 73, 55, 51, 13, 51, 13, 40, 0, 42, 1, 2, 3, 2, 78, 29, 10, 1, 8, 22, 42, - 18, 46, 21, 27, 23, 9, 70, 43, 5, 10, 57, 9, 1, 13, 25, 23, 51, 17, 4, 8, 35, 3, 1, 9, 64, - 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, 4, 62, 7, 1, 1, 1, 4, 1, 15, 1, 10, 7, 57, - 23, 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, 2, 2, 3, 1, 6, 1, 5, 7, 156, 66, 1, - 3, 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1, 3, 1, 59, 54, 2, 1, - 71, 27, 2, 14, 21, 7, 185, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30, 1, 2, 2, 2, 2, 4, - 93, 8, 2, 46, 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 18, 73, 0, 9, 1, 45, 1, 7, 1, - 1, 49, 30, 2, 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1, 1, 2, 2, 24, 6, 1, 2, 1, - 37, 1, 2, 1, 4, 1, 1, 0, 23, 9, 17, 1, 41, 3, 3, 111, 1, 79, 0, 102, 111, 17, 196, 0, 97, - 15, 0, 17, 6, 0, 0, 0, 0, 7, 31, 17, 79, 17, 30, 18, 48, 16, 4, 31, 21, 5, 19, 0, 64, 128, - 75, 4, 57, 7, 17, 64, 2, 1, 1, 12, 2, 14, 0, 8, 0, 42, 9, 0, 4, 1, 7, 1, 2, 1, 0, 15, 1, 29, - 3, 2, 1, 14, 4, 8, 0, 0, 107, 5, 13, 3, 9, 7, 10, 4, 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, - 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, - 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 31, 6, 6, 213, 7, 1, - 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 112, 45, 10, 7, 16, 1, 0, 30, 18, 44, 0, 28, 0, 7, 1, 4, - 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1, - 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, - 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32, - 0, 6, 222, 2, 0, 14, 0, 15, 0, 0, 0, 0, 0, 5, 0, 0, + static OFFSETS: [u8; 1515] = [ + 65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 29, + 18, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, + 39, 14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, + 10, 3, 2, 1, 16, 48, 13, 101, 24, 33, 9, 2, 4, 1, 5, 24, 2, 19, 19, 25, 7, 11, 5, 24, 1, 6, + 8, 1, 8, 42, 10, 12, 3, 7, 6, 76, 1, 16, 1, 3, 4, 15, 13, 19, 1, 8, 2, 2, 2, 22, 1, 7, 1, 1, + 3, 4, 3, 8, 2, 2, 2, 2, 1, 1, 8, 1, 4, 2, 1, 5, 12, 2, 10, 1, 4, 3, 1, 6, 4, 2, 2, 22, 1, 7, + 1, 2, 1, 2, 1, 2, 4, 5, 4, 2, 2, 2, 4, 1, 7, 4, 1, 1, 17, 6, 11, 3, 1, 9, 1, 3, 1, 22, 1, 7, + 1, 2, 1, 5, 3, 9, 1, 3, 1, 2, 3, 1, 15, 4, 21, 4, 4, 3, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, + 3, 8, 2, 2, 2, 2, 9, 2, 4, 2, 1, 5, 13, 1, 16, 2, 1, 6, 3, 3, 1, 4, 3, 2, 1, 1, 1, 2, 3, 2, + 3, 3, 3, 12, 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 13, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, + 2, 1, 3, 2, 1, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 6, 2, 1, + 4, 13, 3, 12, 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3, + 24, 1, 9, 1, 1, 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24, + 1, 1, 1, 19, 1, 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 19, 4, 16, 1, 36, 67, + 55, 1, 1, 2, 5, 16, 64, 10, 4, 2, 38, 1, 1, 5, 1, 2, 43, 1, 0, 1, 4, 2, 7, 1, 1, 1, 4, 2, + 41, 1, 4, 2, 33, 1, 4, 2, 7, 1, 1, 1, 4, 2, 15, 1, 57, 1, 4, 2, 67, 37, 16, 16, 86, 2, 6, 3, + 0, 2, 17, 1, 26, 5, 75, 3, 11, 7, 20, 11, 21, 12, 20, 12, 13, 1, 3, 1, 2, 12, 52, 2, 19, 14, + 1, 4, 1, 67, 89, 7, 43, 5, 70, 10, 31, 1, 12, 4, 9, 23, 30, 2, 5, 11, 44, 4, 26, 54, 28, 4, + 63, 2, 20, 50, 1, 23, 2, 11, 3, 49, 52, 1, 15, 1, 8, 51, 42, 2, 4, 10, 44, 1, 11, 14, 55, + 22, 3, 10, 36, 2, 11, 5, 43, 2, 3, 41, 4, 1, 6, 1, 2, 3, 1, 5, 192, 19, 34, 11, 0, 2, 6, 2, + 38, 2, 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, + 5, 3, 1, 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, + 1, 11, 2, 4, 5, 5, 4, 1, 17, 41, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1, + 16, 23, 9, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2, + 5, 4, 86, 6, 3, 1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 67, 46, 2, 0, 3, 16, + 10, 2, 20, 47, 5, 8, 3, 113, 39, 9, 2, 103, 2, 67, 2, 2, 1, 1, 1, 8, 21, 20, 1, 33, 24, 52, + 12, 68, 1, 1, 44, 6, 3, 1, 1, 3, 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5, + 1, 55, 9, 14, 18, 23, 3, 69, 1, 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7, + 1, 43, 1, 14, 6, 123, 21, 0, 12, 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5, + 1, 1, 1, 2, 1, 2, 1, 108, 33, 0, 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11, + 89, 3, 6, 2, 6, 2, 6, 2, 3, 35, 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0, + 29, 3, 49, 47, 32, 13, 30, 5, 43, 5, 30, 2, 36, 4, 8, 1, 5, 42, 158, 18, 36, 4, 36, 4, 40, + 8, 52, 12, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 3, 52, 12, 0, 9, 22, 10, 8, 24, + 6, 1, 42, 1, 9, 69, 6, 2, 1, 1, 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, 10, 22, + 10, 26, 70, 56, 6, 2, 64, 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, 27, 54, + 10, 22, 10, 19, 13, 18, 110, 73, 55, 51, 13, 51, 13, 40, 34, 28, 3, 1, 5, 23, 250, 42, 1, 2, + 3, 2, 16, 3, 55, 1, 3, 29, 10, 1, 8, 22, 42, 18, 46, 21, 27, 23, 9, 70, 43, 5, 10, 57, 9, 1, + 13, 25, 23, 51, 17, 4, 8, 35, 3, 1, 9, 64, 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, + 4, 62, 7, 1, 1, 1, 4, 1, 15, 1, 10, 7, 57, 23, 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, + 2, 2, 2, 2, 3, 1, 6, 1, 5, 7, 28, 10, 1, 1, 2, 1, 1, 38, 1, 10, 1, 1, 2, 1, 1, 4, 1, 2, 3, + 1, 1, 1, 44, 66, 1, 3, 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1, + 3, 1, 59, 54, 2, 1, 71, 27, 2, 14, 21, 7, 185, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30, + 1, 2, 2, 2, 2, 4, 93, 8, 2, 46, 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 18, 73, 199, + 33, 31, 9, 1, 45, 1, 7, 1, 1, 49, 30, 2, 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1, + 1, 2, 2, 24, 6, 1, 2, 1, 37, 1, 2, 1, 4, 1, 1, 0, 23, 9, 17, 1, 41, 3, 3, 111, 1, 79, 0, + 102, 111, 17, 196, 0, 97, 15, 0, 17, 6, 25, 0, 5, 0, 0, 47, 0, 0, 7, 31, 17, 79, 17, 30, 18, + 48, 16, 4, 31, 21, 5, 19, 0, 45, 211, 64, 128, 75, 4, 57, 7, 17, 64, 2, 1, 1, 12, 2, 14, 0, + 8, 0, 41, 10, 0, 4, 1, 7, 1, 2, 1, 0, 15, 1, 29, 3, 2, 1, 14, 4, 8, 0, 0, 107, 5, 13, 3, 9, + 7, 10, 4, 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, + 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, + 25, 1, 31, 1, 25, 1, 8, 0, 31, 6, 6, 213, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 112, 45, + 10, 7, 16, 1, 0, 30, 18, 44, 0, 28, 228, 30, 2, 1, 0, 7, 1, 4, 1, 2, 1, 15, 1, 197, 59, 68, + 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, + 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, + 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32, 0, 6, 222, 2, 0, 14, 0, 15, 0, + 0, 0, 0, 0, 5, 0, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -180,18 +180,18 @@ pub mod alphabetic { #[rustfmt::skip] pub mod case_ignorable { - static SHORT_OFFSET_RUNS: [u32; 35] = [ + static SHORT_OFFSET_RUNS: [u32; 37] = [ 688, 44045149, 572528402, 576724925, 807414908, 878718981, 903913493, 929080568, 933275148, 937491230, 1138818560, 1147208189, 1210124160, 1222707713, 1235291428, 1260457643, - 1264654383, 1499535675, 1507925040, 1566646003, 1629566000, 1650551536, 1658941263, - 1671540720, 1688321181, 1700908800, 1709298023, 1717688832, 1738661888, 1763828398, - 1797383403, 1805773008, 1809970171, 1819148289, 1824457200, + 1277237295, 1537284411, 1545673776, 1604394739, 1667314736, 1692492062, 1700883184, + 1709272384, 1721855823, 1730260976, 1747041437, 1759629056, 1768018279, 1776409088, + 1797382144, 1822548654, 1856103659, 1864493264, 1872884731, 1882062849, 1887371760, ]; - static OFFSETS: [u8; 875] = [ + static OFFSETS: [u8; 905] = [ 39, 1, 6, 1, 11, 1, 35, 1, 1, 1, 71, 1, 4, 1, 1, 1, 4, 1, 2, 2, 0, 192, 4, 2, 4, 1, 9, 2, 1, 1, 251, 7, 207, 1, 5, 1, 49, 45, 1, 1, 1, 2, 1, 2, 1, 1, 44, 1, 11, 6, 10, 11, 1, 1, 35, 1, 10, 21, 16, 1, 101, 8, 1, 10, 1, 4, 33, 1, 1, 1, 30, 27, 91, 11, 58, 11, 4, 1, 2, 1, 24, - 24, 43, 3, 44, 1, 7, 2, 6, 8, 41, 58, 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 13, 1, 15, 1, + 24, 43, 3, 44, 1, 7, 2, 5, 9, 41, 58, 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 13, 1, 15, 1, 58, 1, 4, 4, 8, 1, 20, 2, 26, 1, 2, 2, 57, 1, 4, 2, 4, 2, 2, 3, 3, 1, 30, 2, 3, 1, 11, 2, 57, 1, 4, 5, 1, 2, 4, 1, 20, 2, 22, 6, 1, 1, 58, 1, 2, 1, 1, 4, 8, 1, 7, 2, 11, 2, 30, 1, 61, 1, 12, 1, 50, 1, 3, 1, 55, 1, 1, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 6, 1, @@ -209,17 +209,18 @@ pub mod case_ignorable { 2, 2, 17, 1, 21, 2, 66, 6, 2, 2, 2, 2, 12, 1, 8, 1, 35, 1, 11, 1, 51, 1, 1, 3, 2, 2, 5, 2, 1, 1, 27, 1, 14, 2, 5, 2, 1, 1, 100, 5, 9, 3, 121, 1, 2, 1, 4, 1, 0, 1, 147, 17, 0, 16, 3, 1, 12, 16, 34, 1, 2, 1, 169, 1, 7, 1, 6, 1, 11, 1, 35, 1, 1, 1, 47, 1, 45, 2, 67, 1, 21, 3, - 0, 1, 226, 1, 149, 5, 0, 6, 1, 42, 1, 9, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2, - 80, 3, 70, 11, 49, 4, 123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2, 1, 4, 1, 10, 1, - 50, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 2, 1, 157, 1, - 3, 8, 21, 2, 57, 2, 3, 1, 37, 7, 3, 5, 195, 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4, 2, 1, 2, - 238, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, 5, - 0, 9, 1, 2, 0, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, - 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, - 3, 1, 1, 1, 0, 2, 11, 2, 52, 5, 5, 1, 1, 1, 0, 17, 6, 15, 0, 5, 59, 7, 9, 4, 0, 1, 63, 17, - 64, 2, 1, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4, 0, 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3, - 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 160, - 14, 0, 1, 61, 4, 0, 5, 0, 7, 109, 8, 0, 5, 0, 1, 30, 96, 128, 240, 0, + 0, 1, 226, 1, 149, 5, 0, 6, 1, 42, 1, 9, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 38, 1, + 26, 5, 1, 1, 0, 2, 79, 4, 70, 11, 49, 4, 123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2, + 1, 4, 1, 10, 1, 50, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, + 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 3, 1, 37, 7, 3, 5, 70, 6, 13, 1, 1, 1, 1, 1, 14, 2, 85, + 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4, 2, 1, 2, 238, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, + 106, 1, 1, 1, 2, 6, 1, 1, 101, 1, 1, 1, 2, 4, 1, 5, 0, 9, 1, 2, 0, 2, 1, 1, 4, 1, 144, 4, 2, + 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, + 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 11, 2, 52, 5, 5, 1, + 1, 1, 23, 1, 0, 17, 6, 15, 0, 12, 3, 3, 0, 5, 59, 7, 9, 4, 0, 3, 40, 2, 0, 1, 63, 17, 64, 2, + 1, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4, 0, 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3, 0, 55, + 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 160, 14, 0, + 1, 61, 4, 0, 5, 254, 2, 0, 7, 109, 8, 0, 5, 0, 1, 30, 96, 128, 240, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -234,22 +235,22 @@ pub mod case_ignorable { pub mod cased { static SHORT_OFFSET_RUNS: [u32; 22] = [ 4256, 115348384, 136322176, 144711446, 163587254, 320875520, 325101120, 350268208, - 392231680, 404815649, 413205504, 421595008, 467733632, 484513952, 492924480, 497144832, - 501339814, 578936576, 627171376, 639756544, 643952944, 649261450, + 392231680, 404815649, 413205504, 421595008, 467733632, 484513952, 501313088, 505533440, + 509728422, 587325184, 635559984, 648145152, 652341552, 657650058, ]; - static OFFSETS: [u8; 315] = [ + static OFFSETS: [u8; 319] = [ 65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 195, 1, 4, 4, 208, 1, 36, 7, 2, 30, 5, 96, 1, 42, 4, 2, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 9, - 41, 0, 38, 1, 1, 5, 1, 2, 43, 1, 4, 0, 86, 2, 6, 0, 9, 7, 43, 2, 3, 64, 192, 64, 0, 2, 6, 2, - 38, 2, 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, - 5, 3, 1, 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, - 1, 6, 4, 1, 2, 4, 5, 5, 4, 1, 17, 32, 3, 2, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, - 0, 46, 18, 30, 132, 102, 3, 4, 1, 59, 5, 2, 1, 1, 1, 5, 24, 5, 1, 3, 0, 43, 1, 14, 6, 80, 0, - 7, 12, 5, 0, 26, 6, 26, 0, 80, 96, 36, 4, 36, 116, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, - 7, 1, 2, 0, 1, 2, 3, 1, 42, 1, 9, 0, 51, 13, 51, 0, 64, 0, 64, 0, 85, 1, 71, 1, 2, 2, 1, 2, - 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, - 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 10, 1, 20, 6, 6, - 0, 62, 0, 68, 0, 26, 6, 26, 6, 26, 0, + 41, 0, 38, 1, 1, 5, 1, 2, 43, 1, 4, 0, 86, 2, 6, 0, 11, 5, 43, 2, 3, 64, 192, 64, 0, 2, 6, + 2, 38, 2, 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, + 13, 5, 3, 1, 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, + 4, 1, 6, 4, 1, 2, 4, 5, 5, 4, 1, 17, 32, 3, 2, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, + 1, 0, 46, 18, 30, 132, 102, 3, 4, 1, 62, 2, 2, 1, 1, 1, 8, 21, 5, 1, 3, 0, 43, 1, 14, 6, 80, + 0, 7, 12, 5, 0, 26, 6, 26, 0, 80, 96, 36, 4, 36, 116, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, + 1, 7, 1, 2, 0, 1, 2, 3, 1, 42, 1, 9, 0, 51, 13, 51, 93, 22, 10, 22, 0, 64, 0, 64, 0, 85, 1, + 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, + 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, + 8, 0, 10, 1, 20, 6, 6, 0, 62, 0, 68, 0, 26, 6, 26, 6, 26, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -279,41 +280,41 @@ pub mod cc { #[rustfmt::skip] pub mod grapheme_extend { - static SHORT_OFFSET_RUNS: [u32; 33] = [ - 768, 2098307, 6292881, 10490717, 522196754, 526393356, 731917551, 740306986, 752920175, - 761309186, 778107678, 908131840, 912326558, 920715773, 924912129, 937495844, 962662059, - 966858799, 1214323760, 1285627635, 1348547648, 1369533168, 1377922895, 1386331293, - 1398918912, 1403113829, 1411504640, 1440866304, 1466032814, 1495393516, 1503783120, - 1508769824, 1518273008, + static SHORT_OFFSET_RUNS: [u32; 34] = [ + 768, 2098307, 6292881, 10490717, 522196754, 526393356, 723528943, 731918378, 744531567, + 752920578, 769719070, 908131840, 912326558, 920715773, 924912129, 937495844, 962662059, + 971053103, 1256266800, 1323376371, 1386296384, 1407279390, 1415670512, 1424060239, + 1432468637, 1449250560, 1453445477, 1461836288, 1487003648, 1512170158, 1541530860, + 1549920464, 1559101472, 1568604656, ]; - static OFFSETS: [u8; 727] = [ + static OFFSETS: [u8; 751] = [ 0, 112, 0, 7, 0, 45, 1, 1, 1, 2, 1, 2, 1, 1, 72, 11, 48, 21, 16, 1, 101, 7, 2, 6, 2, 2, 1, - 4, 35, 1, 30, 27, 91, 11, 58, 9, 9, 1, 24, 4, 1, 9, 1, 3, 1, 5, 43, 3, 60, 8, 42, 24, 1, 32, + 4, 35, 1, 30, 27, 91, 11, 58, 9, 9, 1, 24, 4, 1, 9, 1, 3, 1, 5, 43, 3, 59, 9, 42, 24, 1, 32, 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 29, 1, 58, 1, 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 26, 1, 2, 2, 57, 1, 4, 2, 4, 2, 2, 3, 3, 1, 30, 2, 3, 1, 11, 2, 57, 1, 4, 5, 1, 2, 4, 1, 20, 2, 22, 6, 1, 1, 58, 1, 1, 2, 1, 4, 8, 1, 7, 3, 10, 2, 30, 1, 59, 1, 1, 1, 12, 1, 9, 1, 40, 1, 3, 1, - 55, 1, 1, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 2, 1, 3, 1, 5, 2, 7, 2, 11, 2, 28, + 55, 1, 1, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 2, 1, 1, 3, 3, 1, 4, 7, 2, 11, 2, 28, 2, 57, 2, 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 29, 1, 72, 1, 4, 1, 2, 3, 1, 1, 8, 1, 81, 1, 2, 7, 12, 8, 98, 1, 2, 9, 11, 7, 73, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1, - 102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 0, 3, 0, 3, 29, 2, - 30, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 9, 1, 45, 3, 1, 1, 117, 2, 34, 1, 118, 3, 4, 2, 9, - 1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 48, 31, 49, 4, 48, 7, 1, - 1, 5, 1, 40, 9, 12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3, 58, 8, 2, 2, 152, 3, 1, - 13, 1, 7, 4, 1, 6, 1, 3, 2, 198, 64, 0, 1, 195, 33, 0, 3, 141, 1, 96, 32, 0, 6, 105, 2, 0, - 4, 1, 10, 32, 2, 80, 2, 0, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, - 46, 3, 48, 1, 2, 4, 2, 2, 39, 1, 67, 6, 2, 2, 2, 2, 12, 1, 8, 1, 47, 1, 51, 1, 1, 3, 2, 2, - 5, 2, 1, 1, 42, 2, 8, 1, 238, 1, 2, 1, 4, 1, 0, 1, 0, 16, 16, 16, 0, 2, 0, 1, 226, 1, 149, - 5, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2, 80, 3, 70, 11, 49, 4, 123, 1, 54, 15, - 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 7, 1, 61, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, - 95, 3, 2, 1, 1, 2, 6, 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 1, 1, 1, 1, 22, 1, 14, 7, 3, 5, - 195, 8, 2, 3, 1, 1, 23, 1, 81, 1, 2, 6, 1, 1, 2, 1, 1, 2, 1, 2, 235, 1, 2, 4, 6, 2, 1, 2, - 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, 5, 0, 9, 1, 2, 245, 1, - 10, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, - 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, - 1, 0, 2, 11, 2, 52, 5, 5, 1, 1, 1, 0, 1, 6, 15, 0, 5, 59, 7, 0, 1, 63, 4, 81, 1, 0, 2, 0, - 46, 2, 23, 0, 1, 1, 3, 4, 5, 8, 8, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, - 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 100, 1, 160, 7, 0, 1, 61, 4, 0, 4, 0, 7, 109, 7, 0, 96, - 128, 240, 0, + 102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 0, 3, 0, 4, 28, 3, + 29, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 9, 1, 45, 3, 1, 1, 117, 2, 34, 1, 118, 3, 4, 2, 9, + 1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 48, 31, 49, 4, 48, 10, 4, + 3, 38, 9, 12, 2, 32, 4, 2, 6, 56, 1, 1, 2, 3, 1, 1, 5, 56, 8, 2, 2, 152, 3, 1, 13, 1, 7, 4, + 1, 6, 1, 3, 2, 198, 64, 0, 1, 195, 33, 0, 3, 141, 1, 96, 32, 0, 6, 105, 2, 0, 4, 1, 10, 32, + 2, 80, 2, 0, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, 1, 1, 44, 3, + 48, 1, 2, 4, 2, 2, 2, 1, 36, 1, 67, 6, 2, 2, 2, 2, 12, 1, 8, 1, 47, 1, 51, 1, 1, 3, 2, 2, 5, + 2, 1, 1, 42, 2, 8, 1, 238, 1, 2, 1, 4, 1, 0, 1, 0, 16, 16, 16, 0, 2, 0, 1, 226, 1, 149, 5, + 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 65, 5, 0, 2, 79, 4, 70, 11, 49, 4, 123, 1, 54, + 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 7, 1, 61, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 1, 1, 8, + 4, 2, 1, 95, 3, 2, 4, 6, 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 1, 1, 1, 1, 12, 1, 9, 1, 14, + 7, 3, 5, 67, 1, 2, 6, 1, 1, 2, 1, 1, 3, 4, 3, 1, 1, 14, 2, 85, 8, 2, 3, 1, 1, 23, 1, 81, 1, + 2, 6, 1, 1, 2, 1, 1, 2, 1, 2, 235, 1, 2, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, + 1, 2, 8, 101, 1, 1, 1, 2, 4, 1, 5, 0, 9, 1, 2, 245, 1, 10, 4, 4, 1, 144, 4, 2, 2, 4, 1, 32, + 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, + 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 11, 2, 52, 5, 5, 3, 23, 1, 0, 1, 6, + 15, 0, 12, 3, 3, 0, 5, 59, 7, 0, 1, 63, 4, 81, 1, 11, 2, 0, 2, 0, 46, 2, 23, 0, 5, 3, 6, 8, + 8, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, + 5, 100, 1, 160, 7, 0, 1, 61, 4, 0, 4, 254, 2, 0, 7, 109, 7, 0, 96, 128, 240, 0, ]; #[inline] pub fn lookup(c: char) -> bool { @@ -339,27 +340,27 @@ pub mod lowercase { ]; const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 20] = &[ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 55, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 56, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 43, 0, 51, 47, 49, 33], - [0, 0, 0, 0, 10, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 43, 0, 52, 48, 50, 33], + [0, 0, 0, 0, 10, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 3, 0, 16, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27], - [0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 57, 0, 55, 55, 55, 0, 22, 22, 67, 22, 36, 25, 24, 37], - [0, 5, 68, 0, 29, 15, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 64, 34, 17, 23, 52, 53, 48, 46, 8, 35, 42, 0, 28, 13, 31], - [11, 58, 0, 6, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 32, 0], + [0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 46, 0, 56, 56, 56, 0, 22, 22, 69, 22, 36, 25, 24, 37], + [0, 5, 70, 0, 29, 15, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 66, 34, 17, 23, 53, 54, 49, 47, 8, 35, 42, 0, 28, 13, 31], + [11, 60, 0, 6, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 32, 0], [16, 26, 22, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [16, 50, 2, 21, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [16, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [63, 41, 54, 12, 75, 61, 18, 1, 7, 62, 74, 20, 71, 72, 4, 45], + [16, 51, 2, 21, 68, 9, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [16, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [65, 41, 55, 12, 77, 63, 18, 1, 7, 64, 76, 20, 73, 74, 4, 45], ]; - const BITSET_CANONICAL: &'static [u64; 55] = &[ + const BITSET_CANONICAL: &'static [u64; 56] = &[ 0b0000000000000000000000000000000000000000000000000000000000000000, 0b1111111111111111110000000000000000000000000011111111111111111111, 0b1010101010101010101010101010101010101010101010101010100000000010, @@ -393,7 +394,7 @@ pub mod lowercase { 0b0001101111111011111111111111101111111111100000000000000000000000, 0b0001100100101111101010101010101010101010111000110111111111111111, 0b0000011111111101111111111111111111111111111111111111111110111001, - 0b0000011101011100000000000000000000000010101010100000010100001010, + 0b0000011101011100000000000000000000001010101010100010010100001010, 0b0000010000100000000001000000000000000000000000000000000000000000, 0b0000000111111111111111111111111111111111111011111111111111111111, 0b0000000011111111000000001111111100000000001111110000000011111111, @@ -406,6 +407,7 @@ pub mod lowercase { 0b0000000000000000000000000000000000111010101010101010101010101010, 0b0000000000000000000000000000000000000000111110000000000001111111, 0b0000000000000000000000000000000000000000000000000000101111110111, + 0b0000000000000000000000000000000000000000000000000000010111111111, 0b1001001111111010101010101010101010101010101010101010101010101010, 0b1001010111111111101010101010101010101010101010101010101010101010, 0b1010101000101001101010101010101010110101010101010101001001000000, @@ -416,9 +418,9 @@ pub mod lowercase { 0b1110011001010001001011010010101001001110001001000011000100101001, 0b1110101111000000000000000000000000001111111111111111111111111100, ]; - const BITSET_MAPPING: &'static [(u8, u8); 21] = &[ - (0, 64), (1, 188), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), (1, 70), - (1, 77), (2, 146), (2, 144), (2, 83), (3, 93), (3, 147), (3, 133), (4, 12), (4, 6), + const BITSET_MAPPING: &'static [(u8, u8); 22] = &[ + (0, 64), (1, 188), (1, 186), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), + (1, 70), (1, 77), (2, 146), (2, 144), (2, 83), (3, 93), (3, 147), (3, 133), (4, 12), (4, 6), (5, 187), (6, 78), (7, 132), ]; @@ -436,14 +438,15 @@ pub mod lowercase { #[rustfmt::skip] pub mod n { - static SHORT_OFFSET_RUNS: [u32; 39] = [ + static SHORT_OFFSET_RUNS: [u32; 42] = [ 1632, 18876774, 31461440, 102765417, 111154926, 115349830, 132128880, 165684320, 186656630, 195046653, 199241735, 203436434, 216049184, 241215536, 249605104, 274792208, 278987015, - 283181793, 295766104, 320933114, 383848032, 392238160, 434181712, 442570976, 455154768, - 463544144, 476128256, 484534880, 488730240, 505533120, 509728718, 522314048, 526508784, - 530703600, 534898887, 539094129, 547483904, 568458224, 573766650, + 283181793, 295766104, 320933114, 383848032, 396432464, 438376016, 446765280, 463543280, + 471932752, 488711168, 497115440, 501312096, 505507184, 522284672, 526503152, 530698944, + 534894542, 547479872, 551674608, 555869424, 560064711, 568454257, 576844032, 597818352, + 603126778, ]; - static OFFSETS: [u8; 275] = [ + static OFFSETS: [u8; 289] = [ 48, 10, 120, 2, 5, 1, 2, 3, 0, 10, 134, 10, 198, 10, 0, 10, 118, 10, 4, 6, 108, 10, 118, 10, 118, 10, 2, 6, 110, 13, 115, 10, 8, 7, 103, 10, 104, 7, 7, 19, 109, 10, 96, 10, 118, 10, 70, 20, 0, 10, 70, 10, 0, 20, 0, 3, 239, 10, 6, 10, 22, 10, 0, 10, 128, 11, 165, 10, 6, 10, @@ -451,11 +454,11 @@ pub mod n { 1, 0, 1, 25, 9, 14, 3, 0, 4, 138, 10, 30, 8, 1, 15, 32, 10, 39, 15, 0, 10, 188, 10, 0, 6, 154, 10, 38, 10, 198, 10, 22, 10, 86, 10, 0, 10, 0, 10, 0, 45, 12, 57, 17, 2, 0, 27, 36, 4, 29, 1, 8, 1, 134, 5, 202, 10, 0, 8, 25, 7, 39, 9, 75, 5, 22, 6, 160, 2, 2, 16, 2, 46, 64, 9, - 52, 2, 30, 3, 75, 5, 104, 8, 24, 8, 41, 7, 0, 6, 48, 10, 0, 31, 158, 10, 42, 4, 112, 7, 134, - 30, 128, 10, 60, 10, 144, 10, 7, 20, 251, 10, 0, 10, 118, 10, 0, 10, 102, 10, 102, 12, 0, - 19, 93, 10, 0, 29, 227, 10, 70, 10, 0, 10, 102, 21, 0, 111, 0, 10, 86, 10, 134, 10, 1, 7, 0, - 23, 0, 20, 12, 20, 108, 25, 0, 50, 0, 10, 0, 10, 0, 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, - 76, 45, 1, 15, 0, 13, 0, 10, 0, + 52, 2, 30, 3, 75, 5, 104, 8, 24, 8, 41, 7, 0, 6, 48, 10, 6, 10, 0, 31, 158, 10, 42, 4, 112, + 7, 134, 30, 128, 10, 60, 10, 144, 10, 7, 20, 251, 10, 0, 10, 118, 10, 0, 10, 102, 10, 6, 20, + 76, 12, 0, 19, 93, 10, 0, 10, 86, 29, 227, 10, 70, 10, 0, 10, 102, 21, 0, 111, 0, 10, 0, 10, + 86, 10, 134, 10, 1, 7, 0, 10, 0, 23, 0, 10, 0, 20, 12, 20, 108, 25, 0, 50, 0, 10, 0, 10, 0, + 10, 247, 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, 76, 45, 1, 15, 0, 13, 0, 10, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -476,30 +479,30 @@ pub mod uppercase { 6, 6, 9, 6, 3, ]; const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 17] = &[ - [43, 43, 5, 34, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 1], - [43, 43, 5, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [43, 43, 39, 43, 43, 43, 43, 43, 17, 17, 62, 17, 42, 29, 24, 23], - [43, 43, 43, 43, 9, 8, 44, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [43, 43, 43, 43, 36, 28, 66, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 0, 43, 43, 43], - [43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [43, 43, 43, 43, 43, 43, 43, 43, 43, 54, 43, 43, 43, 43, 43, 43], - [43, 43, 43, 43, 43, 43, 43, 43, 43, 61, 60, 43, 20, 14, 16, 4], - [43, 43, 43, 43, 55, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [43, 43, 58, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [43, 43, 59, 45, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [43, 48, 43, 31, 35, 21, 22, 15, 13, 33, 43, 43, 43, 11, 30, 38], - [51, 53, 26, 49, 12, 7, 25, 50, 40, 52, 6, 3, 65, 64, 63, 67], - [56, 43, 9, 46, 43, 41, 32, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [57, 19, 2, 18, 10, 47, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], - [57, 37, 17, 27, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [44, 44, 5, 35, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 5, 1], + [44, 44, 5, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [44, 44, 40, 44, 44, 44, 44, 44, 17, 17, 63, 17, 43, 29, 24, 23], + [44, 44, 44, 44, 9, 8, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [44, 44, 44, 44, 37, 28, 67, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 44, 44, 44], + [44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [44, 44, 44, 44, 44, 44, 44, 44, 44, 55, 44, 44, 44, 44, 44, 44], + [44, 44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 44, 20, 14, 16, 4], + [44, 44, 44, 44, 56, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [44, 44, 59, 44, 44, 31, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [44, 44, 60, 46, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [44, 49, 44, 32, 36, 21, 22, 15, 13, 34, 44, 44, 44, 11, 30, 39], + [52, 54, 26, 50, 12, 7, 25, 51, 41, 53, 6, 3, 66, 65, 64, 68], + [57, 44, 9, 47, 44, 42, 33, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [58, 19, 2, 18, 10, 48, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [58, 38, 17, 27, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], ]; - const BITSET_CANONICAL: &'static [u64; 43] = &[ + const BITSET_CANONICAL: &'static [u64; 44] = &[ 0b0000011111111111111111111111111000000000000000000000000000000000, 0b0000000000111111111111111111111111111111111111111111111111111111, 0b0101010101010101010101010101010101010101010101010101010000000001, 0b0000011111111111111111111111110000000000000000000000000000000001, - 0b0000000000100000000000000000000000000001010000010000001011110101, + 0b0000000000100000000000000000000000010101010000010001101011110101, 0b1111111111111111111111111111111100000000000000000000000000000000, 0b1111111111111111111111110000000000000000000000000000001111111111, 0b1111111111111111111100000000000000000000000000011111110001011111, @@ -526,6 +529,7 @@ pub mod uppercase { 0b0000000000000000111111111111111100000000000000000000000000100000, 0b0000000000000000111111110000000010101010000000000011111100000000, 0b0000000000000000000011111111101111111111111111101101011101000000, + 0b0000000000000000000000000011111111111111111111110000000000000000, 0b0000000000000000000000000000000001111111011111111111111111111111, 0b0000000000000000000000000000000000000000001101111111011111111111, 0b0000000000000000000000000000000000000000000000000101010101111010, @@ -534,7 +538,7 @@ pub mod uppercase { 0b1100000000001111001111010101000000111110001001110011100010000100, 0b1100000000100101111010101001110100000000000000000000000000000000, 0b1110011010010000010101010101010101010101000111001000000000000000, - 0b1110011111111111111111111111111111111111111111110000000000000000, + 0b1110011111111111111111111111111111111111111111110000001000000000, 0b1111000000000000000000000000001111111111111111111111111100000000, 0b1111011111111111000000000000000000000000000000000000000000000000, 0b1111111100000000111111110000000000111111000000001111111100000000, @@ -751,216 +755,223 @@ pub mod conversions { ('\u{13ea}', 43962), ('\u{13eb}', 43963), ('\u{13ec}', 43964), ('\u{13ed}', 43965), ('\u{13ee}', 43966), ('\u{13ef}', 43967), ('\u{13f0}', 5112), ('\u{13f1}', 5113), ('\u{13f2}', 5114), ('\u{13f3}', 5115), ('\u{13f4}', 5116), ('\u{13f5}', 5117), - ('\u{1c90}', 4304), ('\u{1c91}', 4305), ('\u{1c92}', 4306), ('\u{1c93}', 4307), - ('\u{1c94}', 4308), ('\u{1c95}', 4309), ('\u{1c96}', 4310), ('\u{1c97}', 4311), - ('\u{1c98}', 4312), ('\u{1c99}', 4313), ('\u{1c9a}', 4314), ('\u{1c9b}', 4315), - ('\u{1c9c}', 4316), ('\u{1c9d}', 4317), ('\u{1c9e}', 4318), ('\u{1c9f}', 4319), - ('\u{1ca0}', 4320), ('\u{1ca1}', 4321), ('\u{1ca2}', 4322), ('\u{1ca3}', 4323), - ('\u{1ca4}', 4324), ('\u{1ca5}', 4325), ('\u{1ca6}', 4326), ('\u{1ca7}', 4327), - ('\u{1ca8}', 4328), ('\u{1ca9}', 4329), ('\u{1caa}', 4330), ('\u{1cab}', 4331), - ('\u{1cac}', 4332), ('\u{1cad}', 4333), ('\u{1cae}', 4334), ('\u{1caf}', 4335), - ('\u{1cb0}', 4336), ('\u{1cb1}', 4337), ('\u{1cb2}', 4338), ('\u{1cb3}', 4339), - ('\u{1cb4}', 4340), ('\u{1cb5}', 4341), ('\u{1cb6}', 4342), ('\u{1cb7}', 4343), - ('\u{1cb8}', 4344), ('\u{1cb9}', 4345), ('\u{1cba}', 4346), ('\u{1cbd}', 4349), - ('\u{1cbe}', 4350), ('\u{1cbf}', 4351), ('\u{1e00}', 7681), ('\u{1e02}', 7683), - ('\u{1e04}', 7685), ('\u{1e06}', 7687), ('\u{1e08}', 7689), ('\u{1e0a}', 7691), - ('\u{1e0c}', 7693), ('\u{1e0e}', 7695), ('\u{1e10}', 7697), ('\u{1e12}', 7699), - ('\u{1e14}', 7701), ('\u{1e16}', 7703), ('\u{1e18}', 7705), ('\u{1e1a}', 7707), - ('\u{1e1c}', 7709), ('\u{1e1e}', 7711), ('\u{1e20}', 7713), ('\u{1e22}', 7715), - ('\u{1e24}', 7717), ('\u{1e26}', 7719), ('\u{1e28}', 7721), ('\u{1e2a}', 7723), - ('\u{1e2c}', 7725), ('\u{1e2e}', 7727), ('\u{1e30}', 7729), ('\u{1e32}', 7731), - ('\u{1e34}', 7733), ('\u{1e36}', 7735), ('\u{1e38}', 7737), ('\u{1e3a}', 7739), - ('\u{1e3c}', 7741), ('\u{1e3e}', 7743), ('\u{1e40}', 7745), ('\u{1e42}', 7747), - ('\u{1e44}', 7749), ('\u{1e46}', 7751), ('\u{1e48}', 7753), ('\u{1e4a}', 7755), - ('\u{1e4c}', 7757), ('\u{1e4e}', 7759), ('\u{1e50}', 7761), ('\u{1e52}', 7763), - ('\u{1e54}', 7765), ('\u{1e56}', 7767), ('\u{1e58}', 7769), ('\u{1e5a}', 7771), - ('\u{1e5c}', 7773), ('\u{1e5e}', 7775), ('\u{1e60}', 7777), ('\u{1e62}', 7779), - ('\u{1e64}', 7781), ('\u{1e66}', 7783), ('\u{1e68}', 7785), ('\u{1e6a}', 7787), - ('\u{1e6c}', 7789), ('\u{1e6e}', 7791), ('\u{1e70}', 7793), ('\u{1e72}', 7795), - ('\u{1e74}', 7797), ('\u{1e76}', 7799), ('\u{1e78}', 7801), ('\u{1e7a}', 7803), - ('\u{1e7c}', 7805), ('\u{1e7e}', 7807), ('\u{1e80}', 7809), ('\u{1e82}', 7811), - ('\u{1e84}', 7813), ('\u{1e86}', 7815), ('\u{1e88}', 7817), ('\u{1e8a}', 7819), - ('\u{1e8c}', 7821), ('\u{1e8e}', 7823), ('\u{1e90}', 7825), ('\u{1e92}', 7827), - ('\u{1e94}', 7829), ('\u{1e9e}', 223), ('\u{1ea0}', 7841), ('\u{1ea2}', 7843), - ('\u{1ea4}', 7845), ('\u{1ea6}', 7847), ('\u{1ea8}', 7849), ('\u{1eaa}', 7851), - ('\u{1eac}', 7853), ('\u{1eae}', 7855), ('\u{1eb0}', 7857), ('\u{1eb2}', 7859), - ('\u{1eb4}', 7861), ('\u{1eb6}', 7863), ('\u{1eb8}', 7865), ('\u{1eba}', 7867), - ('\u{1ebc}', 7869), ('\u{1ebe}', 7871), ('\u{1ec0}', 7873), ('\u{1ec2}', 7875), - ('\u{1ec4}', 7877), ('\u{1ec6}', 7879), ('\u{1ec8}', 7881), ('\u{1eca}', 7883), - ('\u{1ecc}', 7885), ('\u{1ece}', 7887), ('\u{1ed0}', 7889), ('\u{1ed2}', 7891), - ('\u{1ed4}', 7893), ('\u{1ed6}', 7895), ('\u{1ed8}', 7897), ('\u{1eda}', 7899), - ('\u{1edc}', 7901), ('\u{1ede}', 7903), ('\u{1ee0}', 7905), ('\u{1ee2}', 7907), - ('\u{1ee4}', 7909), ('\u{1ee6}', 7911), ('\u{1ee8}', 7913), ('\u{1eea}', 7915), - ('\u{1eec}', 7917), ('\u{1eee}', 7919), ('\u{1ef0}', 7921), ('\u{1ef2}', 7923), - ('\u{1ef4}', 7925), ('\u{1ef6}', 7927), ('\u{1ef8}', 7929), ('\u{1efa}', 7931), - ('\u{1efc}', 7933), ('\u{1efe}', 7935), ('\u{1f08}', 7936), ('\u{1f09}', 7937), - ('\u{1f0a}', 7938), ('\u{1f0b}', 7939), ('\u{1f0c}', 7940), ('\u{1f0d}', 7941), - ('\u{1f0e}', 7942), ('\u{1f0f}', 7943), ('\u{1f18}', 7952), ('\u{1f19}', 7953), - ('\u{1f1a}', 7954), ('\u{1f1b}', 7955), ('\u{1f1c}', 7956), ('\u{1f1d}', 7957), - ('\u{1f28}', 7968), ('\u{1f29}', 7969), ('\u{1f2a}', 7970), ('\u{1f2b}', 7971), - ('\u{1f2c}', 7972), ('\u{1f2d}', 7973), ('\u{1f2e}', 7974), ('\u{1f2f}', 7975), - ('\u{1f38}', 7984), ('\u{1f39}', 7985), ('\u{1f3a}', 7986), ('\u{1f3b}', 7987), - ('\u{1f3c}', 7988), ('\u{1f3d}', 7989), ('\u{1f3e}', 7990), ('\u{1f3f}', 7991), - ('\u{1f48}', 8000), ('\u{1f49}', 8001), ('\u{1f4a}', 8002), ('\u{1f4b}', 8003), - ('\u{1f4c}', 8004), ('\u{1f4d}', 8005), ('\u{1f59}', 8017), ('\u{1f5b}', 8019), - ('\u{1f5d}', 8021), ('\u{1f5f}', 8023), ('\u{1f68}', 8032), ('\u{1f69}', 8033), - ('\u{1f6a}', 8034), ('\u{1f6b}', 8035), ('\u{1f6c}', 8036), ('\u{1f6d}', 8037), - ('\u{1f6e}', 8038), ('\u{1f6f}', 8039), ('\u{1f88}', 8064), ('\u{1f89}', 8065), - ('\u{1f8a}', 8066), ('\u{1f8b}', 8067), ('\u{1f8c}', 8068), ('\u{1f8d}', 8069), - ('\u{1f8e}', 8070), ('\u{1f8f}', 8071), ('\u{1f98}', 8080), ('\u{1f99}', 8081), - ('\u{1f9a}', 8082), ('\u{1f9b}', 8083), ('\u{1f9c}', 8084), ('\u{1f9d}', 8085), - ('\u{1f9e}', 8086), ('\u{1f9f}', 8087), ('\u{1fa8}', 8096), ('\u{1fa9}', 8097), - ('\u{1faa}', 8098), ('\u{1fab}', 8099), ('\u{1fac}', 8100), ('\u{1fad}', 8101), - ('\u{1fae}', 8102), ('\u{1faf}', 8103), ('\u{1fb8}', 8112), ('\u{1fb9}', 8113), - ('\u{1fba}', 8048), ('\u{1fbb}', 8049), ('\u{1fbc}', 8115), ('\u{1fc8}', 8050), - ('\u{1fc9}', 8051), ('\u{1fca}', 8052), ('\u{1fcb}', 8053), ('\u{1fcc}', 8131), - ('\u{1fd8}', 8144), ('\u{1fd9}', 8145), ('\u{1fda}', 8054), ('\u{1fdb}', 8055), - ('\u{1fe8}', 8160), ('\u{1fe9}', 8161), ('\u{1fea}', 8058), ('\u{1feb}', 8059), - ('\u{1fec}', 8165), ('\u{1ff8}', 8056), ('\u{1ff9}', 8057), ('\u{1ffa}', 8060), - ('\u{1ffb}', 8061), ('\u{1ffc}', 8179), ('\u{2126}', 969), ('\u{212a}', 107), - ('\u{212b}', 229), ('\u{2132}', 8526), ('\u{2160}', 8560), ('\u{2161}', 8561), - ('\u{2162}', 8562), ('\u{2163}', 8563), ('\u{2164}', 8564), ('\u{2165}', 8565), - ('\u{2166}', 8566), ('\u{2167}', 8567), ('\u{2168}', 8568), ('\u{2169}', 8569), - ('\u{216a}', 8570), ('\u{216b}', 8571), ('\u{216c}', 8572), ('\u{216d}', 8573), - ('\u{216e}', 8574), ('\u{216f}', 8575), ('\u{2183}', 8580), ('\u{24b6}', 9424), - ('\u{24b7}', 9425), ('\u{24b8}', 9426), ('\u{24b9}', 9427), ('\u{24ba}', 9428), - ('\u{24bb}', 9429), ('\u{24bc}', 9430), ('\u{24bd}', 9431), ('\u{24be}', 9432), - ('\u{24bf}', 9433), ('\u{24c0}', 9434), ('\u{24c1}', 9435), ('\u{24c2}', 9436), - ('\u{24c3}', 9437), ('\u{24c4}', 9438), ('\u{24c5}', 9439), ('\u{24c6}', 9440), - ('\u{24c7}', 9441), ('\u{24c8}', 9442), ('\u{24c9}', 9443), ('\u{24ca}', 9444), - ('\u{24cb}', 9445), ('\u{24cc}', 9446), ('\u{24cd}', 9447), ('\u{24ce}', 9448), - ('\u{24cf}', 9449), ('\u{2c00}', 11312), ('\u{2c01}', 11313), ('\u{2c02}', 11314), - ('\u{2c03}', 11315), ('\u{2c04}', 11316), ('\u{2c05}', 11317), ('\u{2c06}', 11318), - ('\u{2c07}', 11319), ('\u{2c08}', 11320), ('\u{2c09}', 11321), ('\u{2c0a}', 11322), - ('\u{2c0b}', 11323), ('\u{2c0c}', 11324), ('\u{2c0d}', 11325), ('\u{2c0e}', 11326), - ('\u{2c0f}', 11327), ('\u{2c10}', 11328), ('\u{2c11}', 11329), ('\u{2c12}', 11330), - ('\u{2c13}', 11331), ('\u{2c14}', 11332), ('\u{2c15}', 11333), ('\u{2c16}', 11334), - ('\u{2c17}', 11335), ('\u{2c18}', 11336), ('\u{2c19}', 11337), ('\u{2c1a}', 11338), - ('\u{2c1b}', 11339), ('\u{2c1c}', 11340), ('\u{2c1d}', 11341), ('\u{2c1e}', 11342), - ('\u{2c1f}', 11343), ('\u{2c20}', 11344), ('\u{2c21}', 11345), ('\u{2c22}', 11346), - ('\u{2c23}', 11347), ('\u{2c24}', 11348), ('\u{2c25}', 11349), ('\u{2c26}', 11350), - ('\u{2c27}', 11351), ('\u{2c28}', 11352), ('\u{2c29}', 11353), ('\u{2c2a}', 11354), - ('\u{2c2b}', 11355), ('\u{2c2c}', 11356), ('\u{2c2d}', 11357), ('\u{2c2e}', 11358), - ('\u{2c2f}', 11359), ('\u{2c60}', 11361), ('\u{2c62}', 619), ('\u{2c63}', 7549), - ('\u{2c64}', 637), ('\u{2c67}', 11368), ('\u{2c69}', 11370), ('\u{2c6b}', 11372), - ('\u{2c6d}', 593), ('\u{2c6e}', 625), ('\u{2c6f}', 592), ('\u{2c70}', 594), - ('\u{2c72}', 11379), ('\u{2c75}', 11382), ('\u{2c7e}', 575), ('\u{2c7f}', 576), - ('\u{2c80}', 11393), ('\u{2c82}', 11395), ('\u{2c84}', 11397), ('\u{2c86}', 11399), - ('\u{2c88}', 11401), ('\u{2c8a}', 11403), ('\u{2c8c}', 11405), ('\u{2c8e}', 11407), - ('\u{2c90}', 11409), ('\u{2c92}', 11411), ('\u{2c94}', 11413), ('\u{2c96}', 11415), - ('\u{2c98}', 11417), ('\u{2c9a}', 11419), ('\u{2c9c}', 11421), ('\u{2c9e}', 11423), - ('\u{2ca0}', 11425), ('\u{2ca2}', 11427), ('\u{2ca4}', 11429), ('\u{2ca6}', 11431), - ('\u{2ca8}', 11433), ('\u{2caa}', 11435), ('\u{2cac}', 11437), ('\u{2cae}', 11439), - ('\u{2cb0}', 11441), ('\u{2cb2}', 11443), ('\u{2cb4}', 11445), ('\u{2cb6}', 11447), - ('\u{2cb8}', 11449), ('\u{2cba}', 11451), ('\u{2cbc}', 11453), ('\u{2cbe}', 11455), - ('\u{2cc0}', 11457), ('\u{2cc2}', 11459), ('\u{2cc4}', 11461), ('\u{2cc6}', 11463), - ('\u{2cc8}', 11465), ('\u{2cca}', 11467), ('\u{2ccc}', 11469), ('\u{2cce}', 11471), - ('\u{2cd0}', 11473), ('\u{2cd2}', 11475), ('\u{2cd4}', 11477), ('\u{2cd6}', 11479), - ('\u{2cd8}', 11481), ('\u{2cda}', 11483), ('\u{2cdc}', 11485), ('\u{2cde}', 11487), - ('\u{2ce0}', 11489), ('\u{2ce2}', 11491), ('\u{2ceb}', 11500), ('\u{2ced}', 11502), - ('\u{2cf2}', 11507), ('\u{a640}', 42561), ('\u{a642}', 42563), ('\u{a644}', 42565), - ('\u{a646}', 42567), ('\u{a648}', 42569), ('\u{a64a}', 42571), ('\u{a64c}', 42573), - ('\u{a64e}', 42575), ('\u{a650}', 42577), ('\u{a652}', 42579), ('\u{a654}', 42581), - ('\u{a656}', 42583), ('\u{a658}', 42585), ('\u{a65a}', 42587), ('\u{a65c}', 42589), - ('\u{a65e}', 42591), ('\u{a660}', 42593), ('\u{a662}', 42595), ('\u{a664}', 42597), - ('\u{a666}', 42599), ('\u{a668}', 42601), ('\u{a66a}', 42603), ('\u{a66c}', 42605), - ('\u{a680}', 42625), ('\u{a682}', 42627), ('\u{a684}', 42629), ('\u{a686}', 42631), - ('\u{a688}', 42633), ('\u{a68a}', 42635), ('\u{a68c}', 42637), ('\u{a68e}', 42639), - ('\u{a690}', 42641), ('\u{a692}', 42643), ('\u{a694}', 42645), ('\u{a696}', 42647), - ('\u{a698}', 42649), ('\u{a69a}', 42651), ('\u{a722}', 42787), ('\u{a724}', 42789), - ('\u{a726}', 42791), ('\u{a728}', 42793), ('\u{a72a}', 42795), ('\u{a72c}', 42797), - ('\u{a72e}', 42799), ('\u{a732}', 42803), ('\u{a734}', 42805), ('\u{a736}', 42807), - ('\u{a738}', 42809), ('\u{a73a}', 42811), ('\u{a73c}', 42813), ('\u{a73e}', 42815), - ('\u{a740}', 42817), ('\u{a742}', 42819), ('\u{a744}', 42821), ('\u{a746}', 42823), - ('\u{a748}', 42825), ('\u{a74a}', 42827), ('\u{a74c}', 42829), ('\u{a74e}', 42831), - ('\u{a750}', 42833), ('\u{a752}', 42835), ('\u{a754}', 42837), ('\u{a756}', 42839), - ('\u{a758}', 42841), ('\u{a75a}', 42843), ('\u{a75c}', 42845), ('\u{a75e}', 42847), - ('\u{a760}', 42849), ('\u{a762}', 42851), ('\u{a764}', 42853), ('\u{a766}', 42855), - ('\u{a768}', 42857), ('\u{a76a}', 42859), ('\u{a76c}', 42861), ('\u{a76e}', 42863), - ('\u{a779}', 42874), ('\u{a77b}', 42876), ('\u{a77d}', 7545), ('\u{a77e}', 42879), - ('\u{a780}', 42881), ('\u{a782}', 42883), ('\u{a784}', 42885), ('\u{a786}', 42887), - ('\u{a78b}', 42892), ('\u{a78d}', 613), ('\u{a790}', 42897), ('\u{a792}', 42899), - ('\u{a796}', 42903), ('\u{a798}', 42905), ('\u{a79a}', 42907), ('\u{a79c}', 42909), - ('\u{a79e}', 42911), ('\u{a7a0}', 42913), ('\u{a7a2}', 42915), ('\u{a7a4}', 42917), - ('\u{a7a6}', 42919), ('\u{a7a8}', 42921), ('\u{a7aa}', 614), ('\u{a7ab}', 604), - ('\u{a7ac}', 609), ('\u{a7ad}', 620), ('\u{a7ae}', 618), ('\u{a7b0}', 670), - ('\u{a7b1}', 647), ('\u{a7b2}', 669), ('\u{a7b3}', 43859), ('\u{a7b4}', 42933), - ('\u{a7b6}', 42935), ('\u{a7b8}', 42937), ('\u{a7ba}', 42939), ('\u{a7bc}', 42941), - ('\u{a7be}', 42943), ('\u{a7c0}', 42945), ('\u{a7c2}', 42947), ('\u{a7c4}', 42900), - ('\u{a7c5}', 642), ('\u{a7c6}', 7566), ('\u{a7c7}', 42952), ('\u{a7c9}', 42954), - ('\u{a7d0}', 42961), ('\u{a7d6}', 42967), ('\u{a7d8}', 42969), ('\u{a7f5}', 42998), - ('\u{ff21}', 65345), ('\u{ff22}', 65346), ('\u{ff23}', 65347), ('\u{ff24}', 65348), - ('\u{ff25}', 65349), ('\u{ff26}', 65350), ('\u{ff27}', 65351), ('\u{ff28}', 65352), - ('\u{ff29}', 65353), ('\u{ff2a}', 65354), ('\u{ff2b}', 65355), ('\u{ff2c}', 65356), - ('\u{ff2d}', 65357), ('\u{ff2e}', 65358), ('\u{ff2f}', 65359), ('\u{ff30}', 65360), - ('\u{ff31}', 65361), ('\u{ff32}', 65362), ('\u{ff33}', 65363), ('\u{ff34}', 65364), - ('\u{ff35}', 65365), ('\u{ff36}', 65366), ('\u{ff37}', 65367), ('\u{ff38}', 65368), - ('\u{ff39}', 65369), ('\u{ff3a}', 65370), ('\u{10400}', 66600), ('\u{10401}', 66601), - ('\u{10402}', 66602), ('\u{10403}', 66603), ('\u{10404}', 66604), ('\u{10405}', 66605), - ('\u{10406}', 66606), ('\u{10407}', 66607), ('\u{10408}', 66608), ('\u{10409}', 66609), - ('\u{1040a}', 66610), ('\u{1040b}', 66611), ('\u{1040c}', 66612), ('\u{1040d}', 66613), - ('\u{1040e}', 66614), ('\u{1040f}', 66615), ('\u{10410}', 66616), ('\u{10411}', 66617), - ('\u{10412}', 66618), ('\u{10413}', 66619), ('\u{10414}', 66620), ('\u{10415}', 66621), - ('\u{10416}', 66622), ('\u{10417}', 66623), ('\u{10418}', 66624), ('\u{10419}', 66625), - ('\u{1041a}', 66626), ('\u{1041b}', 66627), ('\u{1041c}', 66628), ('\u{1041d}', 66629), - ('\u{1041e}', 66630), ('\u{1041f}', 66631), ('\u{10420}', 66632), ('\u{10421}', 66633), - ('\u{10422}', 66634), ('\u{10423}', 66635), ('\u{10424}', 66636), ('\u{10425}', 66637), - ('\u{10426}', 66638), ('\u{10427}', 66639), ('\u{104b0}', 66776), ('\u{104b1}', 66777), - ('\u{104b2}', 66778), ('\u{104b3}', 66779), ('\u{104b4}', 66780), ('\u{104b5}', 66781), - ('\u{104b6}', 66782), ('\u{104b7}', 66783), ('\u{104b8}', 66784), ('\u{104b9}', 66785), - ('\u{104ba}', 66786), ('\u{104bb}', 66787), ('\u{104bc}', 66788), ('\u{104bd}', 66789), - ('\u{104be}', 66790), ('\u{104bf}', 66791), ('\u{104c0}', 66792), ('\u{104c1}', 66793), - ('\u{104c2}', 66794), ('\u{104c3}', 66795), ('\u{104c4}', 66796), ('\u{104c5}', 66797), - ('\u{104c6}', 66798), ('\u{104c7}', 66799), ('\u{104c8}', 66800), ('\u{104c9}', 66801), - ('\u{104ca}', 66802), ('\u{104cb}', 66803), ('\u{104cc}', 66804), ('\u{104cd}', 66805), - ('\u{104ce}', 66806), ('\u{104cf}', 66807), ('\u{104d0}', 66808), ('\u{104d1}', 66809), - ('\u{104d2}', 66810), ('\u{104d3}', 66811), ('\u{10570}', 66967), ('\u{10571}', 66968), - ('\u{10572}', 66969), ('\u{10573}', 66970), ('\u{10574}', 66971), ('\u{10575}', 66972), - ('\u{10576}', 66973), ('\u{10577}', 66974), ('\u{10578}', 66975), ('\u{10579}', 66976), - ('\u{1057a}', 66977), ('\u{1057c}', 66979), ('\u{1057d}', 66980), ('\u{1057e}', 66981), - ('\u{1057f}', 66982), ('\u{10580}', 66983), ('\u{10581}', 66984), ('\u{10582}', 66985), - ('\u{10583}', 66986), ('\u{10584}', 66987), ('\u{10585}', 66988), ('\u{10586}', 66989), - ('\u{10587}', 66990), ('\u{10588}', 66991), ('\u{10589}', 66992), ('\u{1058a}', 66993), - ('\u{1058c}', 66995), ('\u{1058d}', 66996), ('\u{1058e}', 66997), ('\u{1058f}', 66998), - ('\u{10590}', 66999), ('\u{10591}', 67000), ('\u{10592}', 67001), ('\u{10594}', 67003), - ('\u{10595}', 67004), ('\u{10c80}', 68800), ('\u{10c81}', 68801), ('\u{10c82}', 68802), - ('\u{10c83}', 68803), ('\u{10c84}', 68804), ('\u{10c85}', 68805), ('\u{10c86}', 68806), - ('\u{10c87}', 68807), ('\u{10c88}', 68808), ('\u{10c89}', 68809), ('\u{10c8a}', 68810), - ('\u{10c8b}', 68811), ('\u{10c8c}', 68812), ('\u{10c8d}', 68813), ('\u{10c8e}', 68814), - ('\u{10c8f}', 68815), ('\u{10c90}', 68816), ('\u{10c91}', 68817), ('\u{10c92}', 68818), - ('\u{10c93}', 68819), ('\u{10c94}', 68820), ('\u{10c95}', 68821), ('\u{10c96}', 68822), - ('\u{10c97}', 68823), ('\u{10c98}', 68824), ('\u{10c99}', 68825), ('\u{10c9a}', 68826), - ('\u{10c9b}', 68827), ('\u{10c9c}', 68828), ('\u{10c9d}', 68829), ('\u{10c9e}', 68830), - ('\u{10c9f}', 68831), ('\u{10ca0}', 68832), ('\u{10ca1}', 68833), ('\u{10ca2}', 68834), - ('\u{10ca3}', 68835), ('\u{10ca4}', 68836), ('\u{10ca5}', 68837), ('\u{10ca6}', 68838), - ('\u{10ca7}', 68839), ('\u{10ca8}', 68840), ('\u{10ca9}', 68841), ('\u{10caa}', 68842), - ('\u{10cab}', 68843), ('\u{10cac}', 68844), ('\u{10cad}', 68845), ('\u{10cae}', 68846), - ('\u{10caf}', 68847), ('\u{10cb0}', 68848), ('\u{10cb1}', 68849), ('\u{10cb2}', 68850), - ('\u{118a0}', 71872), ('\u{118a1}', 71873), ('\u{118a2}', 71874), ('\u{118a3}', 71875), - ('\u{118a4}', 71876), ('\u{118a5}', 71877), ('\u{118a6}', 71878), ('\u{118a7}', 71879), - ('\u{118a8}', 71880), ('\u{118a9}', 71881), ('\u{118aa}', 71882), ('\u{118ab}', 71883), - ('\u{118ac}', 71884), ('\u{118ad}', 71885), ('\u{118ae}', 71886), ('\u{118af}', 71887), - ('\u{118b0}', 71888), ('\u{118b1}', 71889), ('\u{118b2}', 71890), ('\u{118b3}', 71891), - ('\u{118b4}', 71892), ('\u{118b5}', 71893), ('\u{118b6}', 71894), ('\u{118b7}', 71895), - ('\u{118b8}', 71896), ('\u{118b9}', 71897), ('\u{118ba}', 71898), ('\u{118bb}', 71899), - ('\u{118bc}', 71900), ('\u{118bd}', 71901), ('\u{118be}', 71902), ('\u{118bf}', 71903), - ('\u{16e40}', 93792), ('\u{16e41}', 93793), ('\u{16e42}', 93794), ('\u{16e43}', 93795), - ('\u{16e44}', 93796), ('\u{16e45}', 93797), ('\u{16e46}', 93798), ('\u{16e47}', 93799), - ('\u{16e48}', 93800), ('\u{16e49}', 93801), ('\u{16e4a}', 93802), ('\u{16e4b}', 93803), - ('\u{16e4c}', 93804), ('\u{16e4d}', 93805), ('\u{16e4e}', 93806), ('\u{16e4f}', 93807), - ('\u{16e50}', 93808), ('\u{16e51}', 93809), ('\u{16e52}', 93810), ('\u{16e53}', 93811), - ('\u{16e54}', 93812), ('\u{16e55}', 93813), ('\u{16e56}', 93814), ('\u{16e57}', 93815), - ('\u{16e58}', 93816), ('\u{16e59}', 93817), ('\u{16e5a}', 93818), ('\u{16e5b}', 93819), - ('\u{16e5c}', 93820), ('\u{16e5d}', 93821), ('\u{16e5e}', 93822), ('\u{16e5f}', 93823), - ('\u{1e900}', 125218), ('\u{1e901}', 125219), ('\u{1e902}', 125220), ('\u{1e903}', 125221), - ('\u{1e904}', 125222), ('\u{1e905}', 125223), ('\u{1e906}', 125224), ('\u{1e907}', 125225), - ('\u{1e908}', 125226), ('\u{1e909}', 125227), ('\u{1e90a}', 125228), ('\u{1e90b}', 125229), - ('\u{1e90c}', 125230), ('\u{1e90d}', 125231), ('\u{1e90e}', 125232), ('\u{1e90f}', 125233), - ('\u{1e910}', 125234), ('\u{1e911}', 125235), ('\u{1e912}', 125236), ('\u{1e913}', 125237), - ('\u{1e914}', 125238), ('\u{1e915}', 125239), ('\u{1e916}', 125240), ('\u{1e917}', 125241), - ('\u{1e918}', 125242), ('\u{1e919}', 125243), ('\u{1e91a}', 125244), ('\u{1e91b}', 125245), - ('\u{1e91c}', 125246), ('\u{1e91d}', 125247), ('\u{1e91e}', 125248), ('\u{1e91f}', 125249), - ('\u{1e920}', 125250), ('\u{1e921}', 125251), + ('\u{1c89}', 7306), ('\u{1c90}', 4304), ('\u{1c91}', 4305), ('\u{1c92}', 4306), + ('\u{1c93}', 4307), ('\u{1c94}', 4308), ('\u{1c95}', 4309), ('\u{1c96}', 4310), + ('\u{1c97}', 4311), ('\u{1c98}', 4312), ('\u{1c99}', 4313), ('\u{1c9a}', 4314), + ('\u{1c9b}', 4315), ('\u{1c9c}', 4316), ('\u{1c9d}', 4317), ('\u{1c9e}', 4318), + ('\u{1c9f}', 4319), ('\u{1ca0}', 4320), ('\u{1ca1}', 4321), ('\u{1ca2}', 4322), + ('\u{1ca3}', 4323), ('\u{1ca4}', 4324), ('\u{1ca5}', 4325), ('\u{1ca6}', 4326), + ('\u{1ca7}', 4327), ('\u{1ca8}', 4328), ('\u{1ca9}', 4329), ('\u{1caa}', 4330), + ('\u{1cab}', 4331), ('\u{1cac}', 4332), ('\u{1cad}', 4333), ('\u{1cae}', 4334), + ('\u{1caf}', 4335), ('\u{1cb0}', 4336), ('\u{1cb1}', 4337), ('\u{1cb2}', 4338), + ('\u{1cb3}', 4339), ('\u{1cb4}', 4340), ('\u{1cb5}', 4341), ('\u{1cb6}', 4342), + ('\u{1cb7}', 4343), ('\u{1cb8}', 4344), ('\u{1cb9}', 4345), ('\u{1cba}', 4346), + ('\u{1cbd}', 4349), ('\u{1cbe}', 4350), ('\u{1cbf}', 4351), ('\u{1e00}', 7681), + ('\u{1e02}', 7683), ('\u{1e04}', 7685), ('\u{1e06}', 7687), ('\u{1e08}', 7689), + ('\u{1e0a}', 7691), ('\u{1e0c}', 7693), ('\u{1e0e}', 7695), ('\u{1e10}', 7697), + ('\u{1e12}', 7699), ('\u{1e14}', 7701), ('\u{1e16}', 7703), ('\u{1e18}', 7705), + ('\u{1e1a}', 7707), ('\u{1e1c}', 7709), ('\u{1e1e}', 7711), ('\u{1e20}', 7713), + ('\u{1e22}', 7715), ('\u{1e24}', 7717), ('\u{1e26}', 7719), ('\u{1e28}', 7721), + ('\u{1e2a}', 7723), ('\u{1e2c}', 7725), ('\u{1e2e}', 7727), ('\u{1e30}', 7729), + ('\u{1e32}', 7731), ('\u{1e34}', 7733), ('\u{1e36}', 7735), ('\u{1e38}', 7737), + ('\u{1e3a}', 7739), ('\u{1e3c}', 7741), ('\u{1e3e}', 7743), ('\u{1e40}', 7745), + ('\u{1e42}', 7747), ('\u{1e44}', 7749), ('\u{1e46}', 7751), ('\u{1e48}', 7753), + ('\u{1e4a}', 7755), ('\u{1e4c}', 7757), ('\u{1e4e}', 7759), ('\u{1e50}', 7761), + ('\u{1e52}', 7763), ('\u{1e54}', 7765), ('\u{1e56}', 7767), ('\u{1e58}', 7769), + ('\u{1e5a}', 7771), ('\u{1e5c}', 7773), ('\u{1e5e}', 7775), ('\u{1e60}', 7777), + ('\u{1e62}', 7779), ('\u{1e64}', 7781), ('\u{1e66}', 7783), ('\u{1e68}', 7785), + ('\u{1e6a}', 7787), ('\u{1e6c}', 7789), ('\u{1e6e}', 7791), ('\u{1e70}', 7793), + ('\u{1e72}', 7795), ('\u{1e74}', 7797), ('\u{1e76}', 7799), ('\u{1e78}', 7801), + ('\u{1e7a}', 7803), ('\u{1e7c}', 7805), ('\u{1e7e}', 7807), ('\u{1e80}', 7809), + ('\u{1e82}', 7811), ('\u{1e84}', 7813), ('\u{1e86}', 7815), ('\u{1e88}', 7817), + ('\u{1e8a}', 7819), ('\u{1e8c}', 7821), ('\u{1e8e}', 7823), ('\u{1e90}', 7825), + ('\u{1e92}', 7827), ('\u{1e94}', 7829), ('\u{1e9e}', 223), ('\u{1ea0}', 7841), + ('\u{1ea2}', 7843), ('\u{1ea4}', 7845), ('\u{1ea6}', 7847), ('\u{1ea8}', 7849), + ('\u{1eaa}', 7851), ('\u{1eac}', 7853), ('\u{1eae}', 7855), ('\u{1eb0}', 7857), + ('\u{1eb2}', 7859), ('\u{1eb4}', 7861), ('\u{1eb6}', 7863), ('\u{1eb8}', 7865), + ('\u{1eba}', 7867), ('\u{1ebc}', 7869), ('\u{1ebe}', 7871), ('\u{1ec0}', 7873), + ('\u{1ec2}', 7875), ('\u{1ec4}', 7877), ('\u{1ec6}', 7879), ('\u{1ec8}', 7881), + ('\u{1eca}', 7883), ('\u{1ecc}', 7885), ('\u{1ece}', 7887), ('\u{1ed0}', 7889), + ('\u{1ed2}', 7891), ('\u{1ed4}', 7893), ('\u{1ed6}', 7895), ('\u{1ed8}', 7897), + ('\u{1eda}', 7899), ('\u{1edc}', 7901), ('\u{1ede}', 7903), ('\u{1ee0}', 7905), + ('\u{1ee2}', 7907), ('\u{1ee4}', 7909), ('\u{1ee6}', 7911), ('\u{1ee8}', 7913), + ('\u{1eea}', 7915), ('\u{1eec}', 7917), ('\u{1eee}', 7919), ('\u{1ef0}', 7921), + ('\u{1ef2}', 7923), ('\u{1ef4}', 7925), ('\u{1ef6}', 7927), ('\u{1ef8}', 7929), + ('\u{1efa}', 7931), ('\u{1efc}', 7933), ('\u{1efe}', 7935), ('\u{1f08}', 7936), + ('\u{1f09}', 7937), ('\u{1f0a}', 7938), ('\u{1f0b}', 7939), ('\u{1f0c}', 7940), + ('\u{1f0d}', 7941), ('\u{1f0e}', 7942), ('\u{1f0f}', 7943), ('\u{1f18}', 7952), + ('\u{1f19}', 7953), ('\u{1f1a}', 7954), ('\u{1f1b}', 7955), ('\u{1f1c}', 7956), + ('\u{1f1d}', 7957), ('\u{1f28}', 7968), ('\u{1f29}', 7969), ('\u{1f2a}', 7970), + ('\u{1f2b}', 7971), ('\u{1f2c}', 7972), ('\u{1f2d}', 7973), ('\u{1f2e}', 7974), + ('\u{1f2f}', 7975), ('\u{1f38}', 7984), ('\u{1f39}', 7985), ('\u{1f3a}', 7986), + ('\u{1f3b}', 7987), ('\u{1f3c}', 7988), ('\u{1f3d}', 7989), ('\u{1f3e}', 7990), + ('\u{1f3f}', 7991), ('\u{1f48}', 8000), ('\u{1f49}', 8001), ('\u{1f4a}', 8002), + ('\u{1f4b}', 8003), ('\u{1f4c}', 8004), ('\u{1f4d}', 8005), ('\u{1f59}', 8017), + ('\u{1f5b}', 8019), ('\u{1f5d}', 8021), ('\u{1f5f}', 8023), ('\u{1f68}', 8032), + ('\u{1f69}', 8033), ('\u{1f6a}', 8034), ('\u{1f6b}', 8035), ('\u{1f6c}', 8036), + ('\u{1f6d}', 8037), ('\u{1f6e}', 8038), ('\u{1f6f}', 8039), ('\u{1f88}', 8064), + ('\u{1f89}', 8065), ('\u{1f8a}', 8066), ('\u{1f8b}', 8067), ('\u{1f8c}', 8068), + ('\u{1f8d}', 8069), ('\u{1f8e}', 8070), ('\u{1f8f}', 8071), ('\u{1f98}', 8080), + ('\u{1f99}', 8081), ('\u{1f9a}', 8082), ('\u{1f9b}', 8083), ('\u{1f9c}', 8084), + ('\u{1f9d}', 8085), ('\u{1f9e}', 8086), ('\u{1f9f}', 8087), ('\u{1fa8}', 8096), + ('\u{1fa9}', 8097), ('\u{1faa}', 8098), ('\u{1fab}', 8099), ('\u{1fac}', 8100), + ('\u{1fad}', 8101), ('\u{1fae}', 8102), ('\u{1faf}', 8103), ('\u{1fb8}', 8112), + ('\u{1fb9}', 8113), ('\u{1fba}', 8048), ('\u{1fbb}', 8049), ('\u{1fbc}', 8115), + ('\u{1fc8}', 8050), ('\u{1fc9}', 8051), ('\u{1fca}', 8052), ('\u{1fcb}', 8053), + ('\u{1fcc}', 8131), ('\u{1fd8}', 8144), ('\u{1fd9}', 8145), ('\u{1fda}', 8054), + ('\u{1fdb}', 8055), ('\u{1fe8}', 8160), ('\u{1fe9}', 8161), ('\u{1fea}', 8058), + ('\u{1feb}', 8059), ('\u{1fec}', 8165), ('\u{1ff8}', 8056), ('\u{1ff9}', 8057), + ('\u{1ffa}', 8060), ('\u{1ffb}', 8061), ('\u{1ffc}', 8179), ('\u{2126}', 969), + ('\u{212a}', 107), ('\u{212b}', 229), ('\u{2132}', 8526), ('\u{2160}', 8560), + ('\u{2161}', 8561), ('\u{2162}', 8562), ('\u{2163}', 8563), ('\u{2164}', 8564), + ('\u{2165}', 8565), ('\u{2166}', 8566), ('\u{2167}', 8567), ('\u{2168}', 8568), + ('\u{2169}', 8569), ('\u{216a}', 8570), ('\u{216b}', 8571), ('\u{216c}', 8572), + ('\u{216d}', 8573), ('\u{216e}', 8574), ('\u{216f}', 8575), ('\u{2183}', 8580), + ('\u{24b6}', 9424), ('\u{24b7}', 9425), ('\u{24b8}', 9426), ('\u{24b9}', 9427), + ('\u{24ba}', 9428), ('\u{24bb}', 9429), ('\u{24bc}', 9430), ('\u{24bd}', 9431), + ('\u{24be}', 9432), ('\u{24bf}', 9433), ('\u{24c0}', 9434), ('\u{24c1}', 9435), + ('\u{24c2}', 9436), ('\u{24c3}', 9437), ('\u{24c4}', 9438), ('\u{24c5}', 9439), + ('\u{24c6}', 9440), ('\u{24c7}', 9441), ('\u{24c8}', 9442), ('\u{24c9}', 9443), + ('\u{24ca}', 9444), ('\u{24cb}', 9445), ('\u{24cc}', 9446), ('\u{24cd}', 9447), + ('\u{24ce}', 9448), ('\u{24cf}', 9449), ('\u{2c00}', 11312), ('\u{2c01}', 11313), + ('\u{2c02}', 11314), ('\u{2c03}', 11315), ('\u{2c04}', 11316), ('\u{2c05}', 11317), + ('\u{2c06}', 11318), ('\u{2c07}', 11319), ('\u{2c08}', 11320), ('\u{2c09}', 11321), + ('\u{2c0a}', 11322), ('\u{2c0b}', 11323), ('\u{2c0c}', 11324), ('\u{2c0d}', 11325), + ('\u{2c0e}', 11326), ('\u{2c0f}', 11327), ('\u{2c10}', 11328), ('\u{2c11}', 11329), + ('\u{2c12}', 11330), ('\u{2c13}', 11331), ('\u{2c14}', 11332), ('\u{2c15}', 11333), + ('\u{2c16}', 11334), ('\u{2c17}', 11335), ('\u{2c18}', 11336), ('\u{2c19}', 11337), + ('\u{2c1a}', 11338), ('\u{2c1b}', 11339), ('\u{2c1c}', 11340), ('\u{2c1d}', 11341), + ('\u{2c1e}', 11342), ('\u{2c1f}', 11343), ('\u{2c20}', 11344), ('\u{2c21}', 11345), + ('\u{2c22}', 11346), ('\u{2c23}', 11347), ('\u{2c24}', 11348), ('\u{2c25}', 11349), + ('\u{2c26}', 11350), ('\u{2c27}', 11351), ('\u{2c28}', 11352), ('\u{2c29}', 11353), + ('\u{2c2a}', 11354), ('\u{2c2b}', 11355), ('\u{2c2c}', 11356), ('\u{2c2d}', 11357), + ('\u{2c2e}', 11358), ('\u{2c2f}', 11359), ('\u{2c60}', 11361), ('\u{2c62}', 619), + ('\u{2c63}', 7549), ('\u{2c64}', 637), ('\u{2c67}', 11368), ('\u{2c69}', 11370), + ('\u{2c6b}', 11372), ('\u{2c6d}', 593), ('\u{2c6e}', 625), ('\u{2c6f}', 592), + ('\u{2c70}', 594), ('\u{2c72}', 11379), ('\u{2c75}', 11382), ('\u{2c7e}', 575), + ('\u{2c7f}', 576), ('\u{2c80}', 11393), ('\u{2c82}', 11395), ('\u{2c84}', 11397), + ('\u{2c86}', 11399), ('\u{2c88}', 11401), ('\u{2c8a}', 11403), ('\u{2c8c}', 11405), + ('\u{2c8e}', 11407), ('\u{2c90}', 11409), ('\u{2c92}', 11411), ('\u{2c94}', 11413), + ('\u{2c96}', 11415), ('\u{2c98}', 11417), ('\u{2c9a}', 11419), ('\u{2c9c}', 11421), + ('\u{2c9e}', 11423), ('\u{2ca0}', 11425), ('\u{2ca2}', 11427), ('\u{2ca4}', 11429), + ('\u{2ca6}', 11431), ('\u{2ca8}', 11433), ('\u{2caa}', 11435), ('\u{2cac}', 11437), + ('\u{2cae}', 11439), ('\u{2cb0}', 11441), ('\u{2cb2}', 11443), ('\u{2cb4}', 11445), + ('\u{2cb6}', 11447), ('\u{2cb8}', 11449), ('\u{2cba}', 11451), ('\u{2cbc}', 11453), + ('\u{2cbe}', 11455), ('\u{2cc0}', 11457), ('\u{2cc2}', 11459), ('\u{2cc4}', 11461), + ('\u{2cc6}', 11463), ('\u{2cc8}', 11465), ('\u{2cca}', 11467), ('\u{2ccc}', 11469), + ('\u{2cce}', 11471), ('\u{2cd0}', 11473), ('\u{2cd2}', 11475), ('\u{2cd4}', 11477), + ('\u{2cd6}', 11479), ('\u{2cd8}', 11481), ('\u{2cda}', 11483), ('\u{2cdc}', 11485), + ('\u{2cde}', 11487), ('\u{2ce0}', 11489), ('\u{2ce2}', 11491), ('\u{2ceb}', 11500), + ('\u{2ced}', 11502), ('\u{2cf2}', 11507), ('\u{a640}', 42561), ('\u{a642}', 42563), + ('\u{a644}', 42565), ('\u{a646}', 42567), ('\u{a648}', 42569), ('\u{a64a}', 42571), + ('\u{a64c}', 42573), ('\u{a64e}', 42575), ('\u{a650}', 42577), ('\u{a652}', 42579), + ('\u{a654}', 42581), ('\u{a656}', 42583), ('\u{a658}', 42585), ('\u{a65a}', 42587), + ('\u{a65c}', 42589), ('\u{a65e}', 42591), ('\u{a660}', 42593), ('\u{a662}', 42595), + ('\u{a664}', 42597), ('\u{a666}', 42599), ('\u{a668}', 42601), ('\u{a66a}', 42603), + ('\u{a66c}', 42605), ('\u{a680}', 42625), ('\u{a682}', 42627), ('\u{a684}', 42629), + ('\u{a686}', 42631), ('\u{a688}', 42633), ('\u{a68a}', 42635), ('\u{a68c}', 42637), + ('\u{a68e}', 42639), ('\u{a690}', 42641), ('\u{a692}', 42643), ('\u{a694}', 42645), + ('\u{a696}', 42647), ('\u{a698}', 42649), ('\u{a69a}', 42651), ('\u{a722}', 42787), + ('\u{a724}', 42789), ('\u{a726}', 42791), ('\u{a728}', 42793), ('\u{a72a}', 42795), + ('\u{a72c}', 42797), ('\u{a72e}', 42799), ('\u{a732}', 42803), ('\u{a734}', 42805), + ('\u{a736}', 42807), ('\u{a738}', 42809), ('\u{a73a}', 42811), ('\u{a73c}', 42813), + ('\u{a73e}', 42815), ('\u{a740}', 42817), ('\u{a742}', 42819), ('\u{a744}', 42821), + ('\u{a746}', 42823), ('\u{a748}', 42825), ('\u{a74a}', 42827), ('\u{a74c}', 42829), + ('\u{a74e}', 42831), ('\u{a750}', 42833), ('\u{a752}', 42835), ('\u{a754}', 42837), + ('\u{a756}', 42839), ('\u{a758}', 42841), ('\u{a75a}', 42843), ('\u{a75c}', 42845), + ('\u{a75e}', 42847), ('\u{a760}', 42849), ('\u{a762}', 42851), ('\u{a764}', 42853), + ('\u{a766}', 42855), ('\u{a768}', 42857), ('\u{a76a}', 42859), ('\u{a76c}', 42861), + ('\u{a76e}', 42863), ('\u{a779}', 42874), ('\u{a77b}', 42876), ('\u{a77d}', 7545), + ('\u{a77e}', 42879), ('\u{a780}', 42881), ('\u{a782}', 42883), ('\u{a784}', 42885), + ('\u{a786}', 42887), ('\u{a78b}', 42892), ('\u{a78d}', 613), ('\u{a790}', 42897), + ('\u{a792}', 42899), ('\u{a796}', 42903), ('\u{a798}', 42905), ('\u{a79a}', 42907), + ('\u{a79c}', 42909), ('\u{a79e}', 42911), ('\u{a7a0}', 42913), ('\u{a7a2}', 42915), + ('\u{a7a4}', 42917), ('\u{a7a6}', 42919), ('\u{a7a8}', 42921), ('\u{a7aa}', 614), + ('\u{a7ab}', 604), ('\u{a7ac}', 609), ('\u{a7ad}', 620), ('\u{a7ae}', 618), + ('\u{a7b0}', 670), ('\u{a7b1}', 647), ('\u{a7b2}', 669), ('\u{a7b3}', 43859), + ('\u{a7b4}', 42933), ('\u{a7b6}', 42935), ('\u{a7b8}', 42937), ('\u{a7ba}', 42939), + ('\u{a7bc}', 42941), ('\u{a7be}', 42943), ('\u{a7c0}', 42945), ('\u{a7c2}', 42947), + ('\u{a7c4}', 42900), ('\u{a7c5}', 642), ('\u{a7c6}', 7566), ('\u{a7c7}', 42952), + ('\u{a7c9}', 42954), ('\u{a7cb}', 612), ('\u{a7cc}', 42957), ('\u{a7d0}', 42961), + ('\u{a7d6}', 42967), ('\u{a7d8}', 42969), ('\u{a7da}', 42971), ('\u{a7dc}', 411), + ('\u{a7f5}', 42998), ('\u{ff21}', 65345), ('\u{ff22}', 65346), ('\u{ff23}', 65347), + ('\u{ff24}', 65348), ('\u{ff25}', 65349), ('\u{ff26}', 65350), ('\u{ff27}', 65351), + ('\u{ff28}', 65352), ('\u{ff29}', 65353), ('\u{ff2a}', 65354), ('\u{ff2b}', 65355), + ('\u{ff2c}', 65356), ('\u{ff2d}', 65357), ('\u{ff2e}', 65358), ('\u{ff2f}', 65359), + ('\u{ff30}', 65360), ('\u{ff31}', 65361), ('\u{ff32}', 65362), ('\u{ff33}', 65363), + ('\u{ff34}', 65364), ('\u{ff35}', 65365), ('\u{ff36}', 65366), ('\u{ff37}', 65367), + ('\u{ff38}', 65368), ('\u{ff39}', 65369), ('\u{ff3a}', 65370), ('\u{10400}', 66600), + ('\u{10401}', 66601), ('\u{10402}', 66602), ('\u{10403}', 66603), ('\u{10404}', 66604), + ('\u{10405}', 66605), ('\u{10406}', 66606), ('\u{10407}', 66607), ('\u{10408}', 66608), + ('\u{10409}', 66609), ('\u{1040a}', 66610), ('\u{1040b}', 66611), ('\u{1040c}', 66612), + ('\u{1040d}', 66613), ('\u{1040e}', 66614), ('\u{1040f}', 66615), ('\u{10410}', 66616), + ('\u{10411}', 66617), ('\u{10412}', 66618), ('\u{10413}', 66619), ('\u{10414}', 66620), + ('\u{10415}', 66621), ('\u{10416}', 66622), ('\u{10417}', 66623), ('\u{10418}', 66624), + ('\u{10419}', 66625), ('\u{1041a}', 66626), ('\u{1041b}', 66627), ('\u{1041c}', 66628), + ('\u{1041d}', 66629), ('\u{1041e}', 66630), ('\u{1041f}', 66631), ('\u{10420}', 66632), + ('\u{10421}', 66633), ('\u{10422}', 66634), ('\u{10423}', 66635), ('\u{10424}', 66636), + ('\u{10425}', 66637), ('\u{10426}', 66638), ('\u{10427}', 66639), ('\u{104b0}', 66776), + ('\u{104b1}', 66777), ('\u{104b2}', 66778), ('\u{104b3}', 66779), ('\u{104b4}', 66780), + ('\u{104b5}', 66781), ('\u{104b6}', 66782), ('\u{104b7}', 66783), ('\u{104b8}', 66784), + ('\u{104b9}', 66785), ('\u{104ba}', 66786), ('\u{104bb}', 66787), ('\u{104bc}', 66788), + ('\u{104bd}', 66789), ('\u{104be}', 66790), ('\u{104bf}', 66791), ('\u{104c0}', 66792), + ('\u{104c1}', 66793), ('\u{104c2}', 66794), ('\u{104c3}', 66795), ('\u{104c4}', 66796), + ('\u{104c5}', 66797), ('\u{104c6}', 66798), ('\u{104c7}', 66799), ('\u{104c8}', 66800), + ('\u{104c9}', 66801), ('\u{104ca}', 66802), ('\u{104cb}', 66803), ('\u{104cc}', 66804), + ('\u{104cd}', 66805), ('\u{104ce}', 66806), ('\u{104cf}', 66807), ('\u{104d0}', 66808), + ('\u{104d1}', 66809), ('\u{104d2}', 66810), ('\u{104d3}', 66811), ('\u{10570}', 66967), + ('\u{10571}', 66968), ('\u{10572}', 66969), ('\u{10573}', 66970), ('\u{10574}', 66971), + ('\u{10575}', 66972), ('\u{10576}', 66973), ('\u{10577}', 66974), ('\u{10578}', 66975), + ('\u{10579}', 66976), ('\u{1057a}', 66977), ('\u{1057c}', 66979), ('\u{1057d}', 66980), + ('\u{1057e}', 66981), ('\u{1057f}', 66982), ('\u{10580}', 66983), ('\u{10581}', 66984), + ('\u{10582}', 66985), ('\u{10583}', 66986), ('\u{10584}', 66987), ('\u{10585}', 66988), + ('\u{10586}', 66989), ('\u{10587}', 66990), ('\u{10588}', 66991), ('\u{10589}', 66992), + ('\u{1058a}', 66993), ('\u{1058c}', 66995), ('\u{1058d}', 66996), ('\u{1058e}', 66997), + ('\u{1058f}', 66998), ('\u{10590}', 66999), ('\u{10591}', 67000), ('\u{10592}', 67001), + ('\u{10594}', 67003), ('\u{10595}', 67004), ('\u{10c80}', 68800), ('\u{10c81}', 68801), + ('\u{10c82}', 68802), ('\u{10c83}', 68803), ('\u{10c84}', 68804), ('\u{10c85}', 68805), + ('\u{10c86}', 68806), ('\u{10c87}', 68807), ('\u{10c88}', 68808), ('\u{10c89}', 68809), + ('\u{10c8a}', 68810), ('\u{10c8b}', 68811), ('\u{10c8c}', 68812), ('\u{10c8d}', 68813), + ('\u{10c8e}', 68814), ('\u{10c8f}', 68815), ('\u{10c90}', 68816), ('\u{10c91}', 68817), + ('\u{10c92}', 68818), ('\u{10c93}', 68819), ('\u{10c94}', 68820), ('\u{10c95}', 68821), + ('\u{10c96}', 68822), ('\u{10c97}', 68823), ('\u{10c98}', 68824), ('\u{10c99}', 68825), + ('\u{10c9a}', 68826), ('\u{10c9b}', 68827), ('\u{10c9c}', 68828), ('\u{10c9d}', 68829), + ('\u{10c9e}', 68830), ('\u{10c9f}', 68831), ('\u{10ca0}', 68832), ('\u{10ca1}', 68833), + ('\u{10ca2}', 68834), ('\u{10ca3}', 68835), ('\u{10ca4}', 68836), ('\u{10ca5}', 68837), + ('\u{10ca6}', 68838), ('\u{10ca7}', 68839), ('\u{10ca8}', 68840), ('\u{10ca9}', 68841), + ('\u{10caa}', 68842), ('\u{10cab}', 68843), ('\u{10cac}', 68844), ('\u{10cad}', 68845), + ('\u{10cae}', 68846), ('\u{10caf}', 68847), ('\u{10cb0}', 68848), ('\u{10cb1}', 68849), + ('\u{10cb2}', 68850), ('\u{10d50}', 68976), ('\u{10d51}', 68977), ('\u{10d52}', 68978), + ('\u{10d53}', 68979), ('\u{10d54}', 68980), ('\u{10d55}', 68981), ('\u{10d56}', 68982), + ('\u{10d57}', 68983), ('\u{10d58}', 68984), ('\u{10d59}', 68985), ('\u{10d5a}', 68986), + ('\u{10d5b}', 68987), ('\u{10d5c}', 68988), ('\u{10d5d}', 68989), ('\u{10d5e}', 68990), + ('\u{10d5f}', 68991), ('\u{10d60}', 68992), ('\u{10d61}', 68993), ('\u{10d62}', 68994), + ('\u{10d63}', 68995), ('\u{10d64}', 68996), ('\u{10d65}', 68997), ('\u{118a0}', 71872), + ('\u{118a1}', 71873), ('\u{118a2}', 71874), ('\u{118a3}', 71875), ('\u{118a4}', 71876), + ('\u{118a5}', 71877), ('\u{118a6}', 71878), ('\u{118a7}', 71879), ('\u{118a8}', 71880), + ('\u{118a9}', 71881), ('\u{118aa}', 71882), ('\u{118ab}', 71883), ('\u{118ac}', 71884), + ('\u{118ad}', 71885), ('\u{118ae}', 71886), ('\u{118af}', 71887), ('\u{118b0}', 71888), + ('\u{118b1}', 71889), ('\u{118b2}', 71890), ('\u{118b3}', 71891), ('\u{118b4}', 71892), + ('\u{118b5}', 71893), ('\u{118b6}', 71894), ('\u{118b7}', 71895), ('\u{118b8}', 71896), + ('\u{118b9}', 71897), ('\u{118ba}', 71898), ('\u{118bb}', 71899), ('\u{118bc}', 71900), + ('\u{118bd}', 71901), ('\u{118be}', 71902), ('\u{118bf}', 71903), ('\u{16e40}', 93792), + ('\u{16e41}', 93793), ('\u{16e42}', 93794), ('\u{16e43}', 93795), ('\u{16e44}', 93796), + ('\u{16e45}', 93797), ('\u{16e46}', 93798), ('\u{16e47}', 93799), ('\u{16e48}', 93800), + ('\u{16e49}', 93801), ('\u{16e4a}', 93802), ('\u{16e4b}', 93803), ('\u{16e4c}', 93804), + ('\u{16e4d}', 93805), ('\u{16e4e}', 93806), ('\u{16e4f}', 93807), ('\u{16e50}', 93808), + ('\u{16e51}', 93809), ('\u{16e52}', 93810), ('\u{16e53}', 93811), ('\u{16e54}', 93812), + ('\u{16e55}', 93813), ('\u{16e56}', 93814), ('\u{16e57}', 93815), ('\u{16e58}', 93816), + ('\u{16e59}', 93817), ('\u{16e5a}', 93818), ('\u{16e5b}', 93819), ('\u{16e5c}', 93820), + ('\u{16e5d}', 93821), ('\u{16e5e}', 93822), ('\u{16e5f}', 93823), ('\u{1e900}', 125218), + ('\u{1e901}', 125219), ('\u{1e902}', 125220), ('\u{1e903}', 125221), ('\u{1e904}', 125222), + ('\u{1e905}', 125223), ('\u{1e906}', 125224), ('\u{1e907}', 125225), ('\u{1e908}', 125226), + ('\u{1e909}', 125227), ('\u{1e90a}', 125228), ('\u{1e90b}', 125229), ('\u{1e90c}', 125230), + ('\u{1e90d}', 125231), ('\u{1e90e}', 125232), ('\u{1e90f}', 125233), ('\u{1e910}', 125234), + ('\u{1e911}', 125235), ('\u{1e912}', 125236), ('\u{1e913}', 125237), ('\u{1e914}', 125238), + ('\u{1e915}', 125239), ('\u{1e916}', 125240), ('\u{1e917}', 125241), ('\u{1e918}', 125242), + ('\u{1e919}', 125243), ('\u{1e91a}', 125244), ('\u{1e91b}', 125245), ('\u{1e91c}', 125246), + ('\u{1e91d}', 125247), ('\u{1e91e}', 125248), ('\u{1e91f}', 125249), ('\u{1e920}', 125250), + ('\u{1e921}', 125251), ]; static LOWERCASE_TABLE_MULTI: &[[char; 3]] = &[ @@ -989,14 +1000,14 @@ pub mod conversions { ('\u{16f}', 366), ('\u{171}', 368), ('\u{173}', 370), ('\u{175}', 372), ('\u{177}', 374), ('\u{17a}', 377), ('\u{17c}', 379), ('\u{17e}', 381), ('\u{17f}', 83), ('\u{180}', 579), ('\u{183}', 386), ('\u{185}', 388), ('\u{188}', 391), ('\u{18c}', 395), ('\u{192}', 401), - ('\u{195}', 502), ('\u{199}', 408), ('\u{19a}', 573), ('\u{19e}', 544), ('\u{1a1}', 416), - ('\u{1a3}', 418), ('\u{1a5}', 420), ('\u{1a8}', 423), ('\u{1ad}', 428), ('\u{1b0}', 431), - ('\u{1b4}', 435), ('\u{1b6}', 437), ('\u{1b9}', 440), ('\u{1bd}', 444), ('\u{1bf}', 503), - ('\u{1c5}', 452), ('\u{1c6}', 452), ('\u{1c8}', 455), ('\u{1c9}', 455), ('\u{1cb}', 458), - ('\u{1cc}', 458), ('\u{1ce}', 461), ('\u{1d0}', 463), ('\u{1d2}', 465), ('\u{1d4}', 467), - ('\u{1d6}', 469), ('\u{1d8}', 471), ('\u{1da}', 473), ('\u{1dc}', 475), ('\u{1dd}', 398), - ('\u{1df}', 478), ('\u{1e1}', 480), ('\u{1e3}', 482), ('\u{1e5}', 484), ('\u{1e7}', 486), - ('\u{1e9}', 488), ('\u{1eb}', 490), ('\u{1ed}', 492), ('\u{1ef}', 494), + ('\u{195}', 502), ('\u{199}', 408), ('\u{19a}', 573), ('\u{19b}', 42972), ('\u{19e}', 544), + ('\u{1a1}', 416), ('\u{1a3}', 418), ('\u{1a5}', 420), ('\u{1a8}', 423), ('\u{1ad}', 428), + ('\u{1b0}', 431), ('\u{1b4}', 435), ('\u{1b6}', 437), ('\u{1b9}', 440), ('\u{1bd}', 444), + ('\u{1bf}', 503), ('\u{1c5}', 452), ('\u{1c6}', 452), ('\u{1c8}', 455), ('\u{1c9}', 455), + ('\u{1cb}', 458), ('\u{1cc}', 458), ('\u{1ce}', 461), ('\u{1d0}', 463), ('\u{1d2}', 465), + ('\u{1d4}', 467), ('\u{1d6}', 469), ('\u{1d8}', 471), ('\u{1da}', 473), ('\u{1dc}', 475), + ('\u{1dd}', 398), ('\u{1df}', 478), ('\u{1e1}', 480), ('\u{1e3}', 482), ('\u{1e5}', 484), + ('\u{1e7}', 486), ('\u{1e9}', 488), ('\u{1eb}', 490), ('\u{1ed}', 492), ('\u{1ef}', 494), ('\u{1f0}', 4194306), ('\u{1f2}', 497), ('\u{1f3}', 497), ('\u{1f5}', 500), ('\u{1f9}', 504), ('\u{1fb}', 506), ('\u{1fd}', 508), ('\u{1ff}', 510), ('\u{201}', 512), ('\u{203}', 514), ('\u{205}', 516), ('\u{207}', 518), ('\u{209}', 520), ('\u{20b}', 522), @@ -1008,25 +1019,25 @@ pub mod conversions { ('\u{249}', 584), ('\u{24b}', 586), ('\u{24d}', 588), ('\u{24f}', 590), ('\u{250}', 11375), ('\u{251}', 11373), ('\u{252}', 11376), ('\u{253}', 385), ('\u{254}', 390), ('\u{256}', 393), ('\u{257}', 394), ('\u{259}', 399), ('\u{25b}', 400), ('\u{25c}', 42923), - ('\u{260}', 403), ('\u{261}', 42924), ('\u{263}', 404), ('\u{265}', 42893), - ('\u{266}', 42922), ('\u{268}', 407), ('\u{269}', 406), ('\u{26a}', 42926), - ('\u{26b}', 11362), ('\u{26c}', 42925), ('\u{26f}', 412), ('\u{271}', 11374), - ('\u{272}', 413), ('\u{275}', 415), ('\u{27d}', 11364), ('\u{280}', 422), - ('\u{282}', 42949), ('\u{283}', 425), ('\u{287}', 42929), ('\u{288}', 430), - ('\u{289}', 580), ('\u{28a}', 433), ('\u{28b}', 434), ('\u{28c}', 581), ('\u{292}', 439), - ('\u{29d}', 42930), ('\u{29e}', 42928), ('\u{345}', 921), ('\u{371}', 880), - ('\u{373}', 882), ('\u{377}', 886), ('\u{37b}', 1021), ('\u{37c}', 1022), ('\u{37d}', 1023), - ('\u{390}', 4194307), ('\u{3ac}', 902), ('\u{3ad}', 904), ('\u{3ae}', 905), - ('\u{3af}', 906), ('\u{3b0}', 4194308), ('\u{3b1}', 913), ('\u{3b2}', 914), - ('\u{3b3}', 915), ('\u{3b4}', 916), ('\u{3b5}', 917), ('\u{3b6}', 918), ('\u{3b7}', 919), - ('\u{3b8}', 920), ('\u{3b9}', 921), ('\u{3ba}', 922), ('\u{3bb}', 923), ('\u{3bc}', 924), - ('\u{3bd}', 925), ('\u{3be}', 926), ('\u{3bf}', 927), ('\u{3c0}', 928), ('\u{3c1}', 929), - ('\u{3c2}', 931), ('\u{3c3}', 931), ('\u{3c4}', 932), ('\u{3c5}', 933), ('\u{3c6}', 934), - ('\u{3c7}', 935), ('\u{3c8}', 936), ('\u{3c9}', 937), ('\u{3ca}', 938), ('\u{3cb}', 939), - ('\u{3cc}', 908), ('\u{3cd}', 910), ('\u{3ce}', 911), ('\u{3d0}', 914), ('\u{3d1}', 920), - ('\u{3d5}', 934), ('\u{3d6}', 928), ('\u{3d7}', 975), ('\u{3d9}', 984), ('\u{3db}', 986), - ('\u{3dd}', 988), ('\u{3df}', 990), ('\u{3e1}', 992), ('\u{3e3}', 994), ('\u{3e5}', 996), - ('\u{3e7}', 998), ('\u{3e9}', 1000), ('\u{3eb}', 1002), ('\u{3ed}', 1004), + ('\u{260}', 403), ('\u{261}', 42924), ('\u{263}', 404), ('\u{264}', 42955), + ('\u{265}', 42893), ('\u{266}', 42922), ('\u{268}', 407), ('\u{269}', 406), + ('\u{26a}', 42926), ('\u{26b}', 11362), ('\u{26c}', 42925), ('\u{26f}', 412), + ('\u{271}', 11374), ('\u{272}', 413), ('\u{275}', 415), ('\u{27d}', 11364), + ('\u{280}', 422), ('\u{282}', 42949), ('\u{283}', 425), ('\u{287}', 42929), + ('\u{288}', 430), ('\u{289}', 580), ('\u{28a}', 433), ('\u{28b}', 434), ('\u{28c}', 581), + ('\u{292}', 439), ('\u{29d}', 42930), ('\u{29e}', 42928), ('\u{345}', 921), + ('\u{371}', 880), ('\u{373}', 882), ('\u{377}', 886), ('\u{37b}', 1021), ('\u{37c}', 1022), + ('\u{37d}', 1023), ('\u{390}', 4194307), ('\u{3ac}', 902), ('\u{3ad}', 904), + ('\u{3ae}', 905), ('\u{3af}', 906), ('\u{3b0}', 4194308), ('\u{3b1}', 913), + ('\u{3b2}', 914), ('\u{3b3}', 915), ('\u{3b4}', 916), ('\u{3b5}', 917), ('\u{3b6}', 918), + ('\u{3b7}', 919), ('\u{3b8}', 920), ('\u{3b9}', 921), ('\u{3ba}', 922), ('\u{3bb}', 923), + ('\u{3bc}', 924), ('\u{3bd}', 925), ('\u{3be}', 926), ('\u{3bf}', 927), ('\u{3c0}', 928), + ('\u{3c1}', 929), ('\u{3c2}', 931), ('\u{3c3}', 931), ('\u{3c4}', 932), ('\u{3c5}', 933), + ('\u{3c6}', 934), ('\u{3c7}', 935), ('\u{3c8}', 936), ('\u{3c9}', 937), ('\u{3ca}', 938), + ('\u{3cb}', 939), ('\u{3cc}', 908), ('\u{3cd}', 910), ('\u{3ce}', 911), ('\u{3d0}', 914), + ('\u{3d1}', 920), ('\u{3d5}', 934), ('\u{3d6}', 928), ('\u{3d7}', 975), ('\u{3d9}', 984), + ('\u{3db}', 986), ('\u{3dd}', 988), ('\u{3df}', 990), ('\u{3e1}', 992), ('\u{3e3}', 994), + ('\u{3e5}', 996), ('\u{3e7}', 998), ('\u{3e9}', 1000), ('\u{3eb}', 1002), ('\u{3ed}', 1004), ('\u{3ef}', 1006), ('\u{3f0}', 922), ('\u{3f1}', 929), ('\u{3f2}', 1017), ('\u{3f3}', 895), ('\u{3f5}', 917), ('\u{3f8}', 1015), ('\u{3fb}', 1018), ('\u{430}', 1040), ('\u{431}', 1041), ('\u{432}', 1042), ('\u{433}', 1043), ('\u{434}', 1044), @@ -1090,248 +1101,254 @@ pub mod conversions { ('\u{13f8}', 5104), ('\u{13f9}', 5105), ('\u{13fa}', 5106), ('\u{13fb}', 5107), ('\u{13fc}', 5108), ('\u{13fd}', 5109), ('\u{1c80}', 1042), ('\u{1c81}', 1044), ('\u{1c82}', 1054), ('\u{1c83}', 1057), ('\u{1c84}', 1058), ('\u{1c85}', 1058), - ('\u{1c86}', 1066), ('\u{1c87}', 1122), ('\u{1c88}', 42570), ('\u{1d79}', 42877), - ('\u{1d7d}', 11363), ('\u{1d8e}', 42950), ('\u{1e01}', 7680), ('\u{1e03}', 7682), - ('\u{1e05}', 7684), ('\u{1e07}', 7686), ('\u{1e09}', 7688), ('\u{1e0b}', 7690), - ('\u{1e0d}', 7692), ('\u{1e0f}', 7694), ('\u{1e11}', 7696), ('\u{1e13}', 7698), - ('\u{1e15}', 7700), ('\u{1e17}', 7702), ('\u{1e19}', 7704), ('\u{1e1b}', 7706), - ('\u{1e1d}', 7708), ('\u{1e1f}', 7710), ('\u{1e21}', 7712), ('\u{1e23}', 7714), - ('\u{1e25}', 7716), ('\u{1e27}', 7718), ('\u{1e29}', 7720), ('\u{1e2b}', 7722), - ('\u{1e2d}', 7724), ('\u{1e2f}', 7726), ('\u{1e31}', 7728), ('\u{1e33}', 7730), - ('\u{1e35}', 7732), ('\u{1e37}', 7734), ('\u{1e39}', 7736), ('\u{1e3b}', 7738), - ('\u{1e3d}', 7740), ('\u{1e3f}', 7742), ('\u{1e41}', 7744), ('\u{1e43}', 7746), - ('\u{1e45}', 7748), ('\u{1e47}', 7750), ('\u{1e49}', 7752), ('\u{1e4b}', 7754), - ('\u{1e4d}', 7756), ('\u{1e4f}', 7758), ('\u{1e51}', 7760), ('\u{1e53}', 7762), - ('\u{1e55}', 7764), ('\u{1e57}', 7766), ('\u{1e59}', 7768), ('\u{1e5b}', 7770), - ('\u{1e5d}', 7772), ('\u{1e5f}', 7774), ('\u{1e61}', 7776), ('\u{1e63}', 7778), - ('\u{1e65}', 7780), ('\u{1e67}', 7782), ('\u{1e69}', 7784), ('\u{1e6b}', 7786), - ('\u{1e6d}', 7788), ('\u{1e6f}', 7790), ('\u{1e71}', 7792), ('\u{1e73}', 7794), - ('\u{1e75}', 7796), ('\u{1e77}', 7798), ('\u{1e79}', 7800), ('\u{1e7b}', 7802), - ('\u{1e7d}', 7804), ('\u{1e7f}', 7806), ('\u{1e81}', 7808), ('\u{1e83}', 7810), - ('\u{1e85}', 7812), ('\u{1e87}', 7814), ('\u{1e89}', 7816), ('\u{1e8b}', 7818), - ('\u{1e8d}', 7820), ('\u{1e8f}', 7822), ('\u{1e91}', 7824), ('\u{1e93}', 7826), - ('\u{1e95}', 7828), ('\u{1e96}', 4194310), ('\u{1e97}', 4194311), ('\u{1e98}', 4194312), - ('\u{1e99}', 4194313), ('\u{1e9a}', 4194314), ('\u{1e9b}', 7776), ('\u{1ea1}', 7840), - ('\u{1ea3}', 7842), ('\u{1ea5}', 7844), ('\u{1ea7}', 7846), ('\u{1ea9}', 7848), - ('\u{1eab}', 7850), ('\u{1ead}', 7852), ('\u{1eaf}', 7854), ('\u{1eb1}', 7856), - ('\u{1eb3}', 7858), ('\u{1eb5}', 7860), ('\u{1eb7}', 7862), ('\u{1eb9}', 7864), - ('\u{1ebb}', 7866), ('\u{1ebd}', 7868), ('\u{1ebf}', 7870), ('\u{1ec1}', 7872), - ('\u{1ec3}', 7874), ('\u{1ec5}', 7876), ('\u{1ec7}', 7878), ('\u{1ec9}', 7880), - ('\u{1ecb}', 7882), ('\u{1ecd}', 7884), ('\u{1ecf}', 7886), ('\u{1ed1}', 7888), - ('\u{1ed3}', 7890), ('\u{1ed5}', 7892), ('\u{1ed7}', 7894), ('\u{1ed9}', 7896), - ('\u{1edb}', 7898), ('\u{1edd}', 7900), ('\u{1edf}', 7902), ('\u{1ee1}', 7904), - ('\u{1ee3}', 7906), ('\u{1ee5}', 7908), ('\u{1ee7}', 7910), ('\u{1ee9}', 7912), - ('\u{1eeb}', 7914), ('\u{1eed}', 7916), ('\u{1eef}', 7918), ('\u{1ef1}', 7920), - ('\u{1ef3}', 7922), ('\u{1ef5}', 7924), ('\u{1ef7}', 7926), ('\u{1ef9}', 7928), - ('\u{1efb}', 7930), ('\u{1efd}', 7932), ('\u{1eff}', 7934), ('\u{1f00}', 7944), - ('\u{1f01}', 7945), ('\u{1f02}', 7946), ('\u{1f03}', 7947), ('\u{1f04}', 7948), - ('\u{1f05}', 7949), ('\u{1f06}', 7950), ('\u{1f07}', 7951), ('\u{1f10}', 7960), - ('\u{1f11}', 7961), ('\u{1f12}', 7962), ('\u{1f13}', 7963), ('\u{1f14}', 7964), - ('\u{1f15}', 7965), ('\u{1f20}', 7976), ('\u{1f21}', 7977), ('\u{1f22}', 7978), - ('\u{1f23}', 7979), ('\u{1f24}', 7980), ('\u{1f25}', 7981), ('\u{1f26}', 7982), - ('\u{1f27}', 7983), ('\u{1f30}', 7992), ('\u{1f31}', 7993), ('\u{1f32}', 7994), - ('\u{1f33}', 7995), ('\u{1f34}', 7996), ('\u{1f35}', 7997), ('\u{1f36}', 7998), - ('\u{1f37}', 7999), ('\u{1f40}', 8008), ('\u{1f41}', 8009), ('\u{1f42}', 8010), - ('\u{1f43}', 8011), ('\u{1f44}', 8012), ('\u{1f45}', 8013), ('\u{1f50}', 4194315), - ('\u{1f51}', 8025), ('\u{1f52}', 4194316), ('\u{1f53}', 8027), ('\u{1f54}', 4194317), - ('\u{1f55}', 8029), ('\u{1f56}', 4194318), ('\u{1f57}', 8031), ('\u{1f60}', 8040), - ('\u{1f61}', 8041), ('\u{1f62}', 8042), ('\u{1f63}', 8043), ('\u{1f64}', 8044), - ('\u{1f65}', 8045), ('\u{1f66}', 8046), ('\u{1f67}', 8047), ('\u{1f70}', 8122), - ('\u{1f71}', 8123), ('\u{1f72}', 8136), ('\u{1f73}', 8137), ('\u{1f74}', 8138), - ('\u{1f75}', 8139), ('\u{1f76}', 8154), ('\u{1f77}', 8155), ('\u{1f78}', 8184), - ('\u{1f79}', 8185), ('\u{1f7a}', 8170), ('\u{1f7b}', 8171), ('\u{1f7c}', 8186), - ('\u{1f7d}', 8187), ('\u{1f80}', 4194319), ('\u{1f81}', 4194320), ('\u{1f82}', 4194321), - ('\u{1f83}', 4194322), ('\u{1f84}', 4194323), ('\u{1f85}', 4194324), ('\u{1f86}', 4194325), - ('\u{1f87}', 4194326), ('\u{1f88}', 4194327), ('\u{1f89}', 4194328), ('\u{1f8a}', 4194329), - ('\u{1f8b}', 4194330), ('\u{1f8c}', 4194331), ('\u{1f8d}', 4194332), ('\u{1f8e}', 4194333), - ('\u{1f8f}', 4194334), ('\u{1f90}', 4194335), ('\u{1f91}', 4194336), ('\u{1f92}', 4194337), - ('\u{1f93}', 4194338), ('\u{1f94}', 4194339), ('\u{1f95}', 4194340), ('\u{1f96}', 4194341), - ('\u{1f97}', 4194342), ('\u{1f98}', 4194343), ('\u{1f99}', 4194344), ('\u{1f9a}', 4194345), - ('\u{1f9b}', 4194346), ('\u{1f9c}', 4194347), ('\u{1f9d}', 4194348), ('\u{1f9e}', 4194349), - ('\u{1f9f}', 4194350), ('\u{1fa0}', 4194351), ('\u{1fa1}', 4194352), ('\u{1fa2}', 4194353), - ('\u{1fa3}', 4194354), ('\u{1fa4}', 4194355), ('\u{1fa5}', 4194356), ('\u{1fa6}', 4194357), - ('\u{1fa7}', 4194358), ('\u{1fa8}', 4194359), ('\u{1fa9}', 4194360), ('\u{1faa}', 4194361), - ('\u{1fab}', 4194362), ('\u{1fac}', 4194363), ('\u{1fad}', 4194364), ('\u{1fae}', 4194365), - ('\u{1faf}', 4194366), ('\u{1fb0}', 8120), ('\u{1fb1}', 8121), ('\u{1fb2}', 4194367), - ('\u{1fb3}', 4194368), ('\u{1fb4}', 4194369), ('\u{1fb6}', 4194370), ('\u{1fb7}', 4194371), - ('\u{1fbc}', 4194372), ('\u{1fbe}', 921), ('\u{1fc2}', 4194373), ('\u{1fc3}', 4194374), - ('\u{1fc4}', 4194375), ('\u{1fc6}', 4194376), ('\u{1fc7}', 4194377), ('\u{1fcc}', 4194378), - ('\u{1fd0}', 8152), ('\u{1fd1}', 8153), ('\u{1fd2}', 4194379), ('\u{1fd3}', 4194380), - ('\u{1fd6}', 4194381), ('\u{1fd7}', 4194382), ('\u{1fe0}', 8168), ('\u{1fe1}', 8169), - ('\u{1fe2}', 4194383), ('\u{1fe3}', 4194384), ('\u{1fe4}', 4194385), ('\u{1fe5}', 8172), - ('\u{1fe6}', 4194386), ('\u{1fe7}', 4194387), ('\u{1ff2}', 4194388), ('\u{1ff3}', 4194389), - ('\u{1ff4}', 4194390), ('\u{1ff6}', 4194391), ('\u{1ff7}', 4194392), ('\u{1ffc}', 4194393), - ('\u{214e}', 8498), ('\u{2170}', 8544), ('\u{2171}', 8545), ('\u{2172}', 8546), - ('\u{2173}', 8547), ('\u{2174}', 8548), ('\u{2175}', 8549), ('\u{2176}', 8550), - ('\u{2177}', 8551), ('\u{2178}', 8552), ('\u{2179}', 8553), ('\u{217a}', 8554), - ('\u{217b}', 8555), ('\u{217c}', 8556), ('\u{217d}', 8557), ('\u{217e}', 8558), - ('\u{217f}', 8559), ('\u{2184}', 8579), ('\u{24d0}', 9398), ('\u{24d1}', 9399), - ('\u{24d2}', 9400), ('\u{24d3}', 9401), ('\u{24d4}', 9402), ('\u{24d5}', 9403), - ('\u{24d6}', 9404), ('\u{24d7}', 9405), ('\u{24d8}', 9406), ('\u{24d9}', 9407), - ('\u{24da}', 9408), ('\u{24db}', 9409), ('\u{24dc}', 9410), ('\u{24dd}', 9411), - ('\u{24de}', 9412), ('\u{24df}', 9413), ('\u{24e0}', 9414), ('\u{24e1}', 9415), - ('\u{24e2}', 9416), ('\u{24e3}', 9417), ('\u{24e4}', 9418), ('\u{24e5}', 9419), - ('\u{24e6}', 9420), ('\u{24e7}', 9421), ('\u{24e8}', 9422), ('\u{24e9}', 9423), - ('\u{2c30}', 11264), ('\u{2c31}', 11265), ('\u{2c32}', 11266), ('\u{2c33}', 11267), - ('\u{2c34}', 11268), ('\u{2c35}', 11269), ('\u{2c36}', 11270), ('\u{2c37}', 11271), - ('\u{2c38}', 11272), ('\u{2c39}', 11273), ('\u{2c3a}', 11274), ('\u{2c3b}', 11275), - ('\u{2c3c}', 11276), ('\u{2c3d}', 11277), ('\u{2c3e}', 11278), ('\u{2c3f}', 11279), - ('\u{2c40}', 11280), ('\u{2c41}', 11281), ('\u{2c42}', 11282), ('\u{2c43}', 11283), - ('\u{2c44}', 11284), ('\u{2c45}', 11285), ('\u{2c46}', 11286), ('\u{2c47}', 11287), - ('\u{2c48}', 11288), ('\u{2c49}', 11289), ('\u{2c4a}', 11290), ('\u{2c4b}', 11291), - ('\u{2c4c}', 11292), ('\u{2c4d}', 11293), ('\u{2c4e}', 11294), ('\u{2c4f}', 11295), - ('\u{2c50}', 11296), ('\u{2c51}', 11297), ('\u{2c52}', 11298), ('\u{2c53}', 11299), - ('\u{2c54}', 11300), ('\u{2c55}', 11301), ('\u{2c56}', 11302), ('\u{2c57}', 11303), - ('\u{2c58}', 11304), ('\u{2c59}', 11305), ('\u{2c5a}', 11306), ('\u{2c5b}', 11307), - ('\u{2c5c}', 11308), ('\u{2c5d}', 11309), ('\u{2c5e}', 11310), ('\u{2c5f}', 11311), - ('\u{2c61}', 11360), ('\u{2c65}', 570), ('\u{2c66}', 574), ('\u{2c68}', 11367), - ('\u{2c6a}', 11369), ('\u{2c6c}', 11371), ('\u{2c73}', 11378), ('\u{2c76}', 11381), - ('\u{2c81}', 11392), ('\u{2c83}', 11394), ('\u{2c85}', 11396), ('\u{2c87}', 11398), - ('\u{2c89}', 11400), ('\u{2c8b}', 11402), ('\u{2c8d}', 11404), ('\u{2c8f}', 11406), - ('\u{2c91}', 11408), ('\u{2c93}', 11410), ('\u{2c95}', 11412), ('\u{2c97}', 11414), - ('\u{2c99}', 11416), ('\u{2c9b}', 11418), ('\u{2c9d}', 11420), ('\u{2c9f}', 11422), - ('\u{2ca1}', 11424), ('\u{2ca3}', 11426), ('\u{2ca5}', 11428), ('\u{2ca7}', 11430), - ('\u{2ca9}', 11432), ('\u{2cab}', 11434), ('\u{2cad}', 11436), ('\u{2caf}', 11438), - ('\u{2cb1}', 11440), ('\u{2cb3}', 11442), ('\u{2cb5}', 11444), ('\u{2cb7}', 11446), - ('\u{2cb9}', 11448), ('\u{2cbb}', 11450), ('\u{2cbd}', 11452), ('\u{2cbf}', 11454), - ('\u{2cc1}', 11456), ('\u{2cc3}', 11458), ('\u{2cc5}', 11460), ('\u{2cc7}', 11462), - ('\u{2cc9}', 11464), ('\u{2ccb}', 11466), ('\u{2ccd}', 11468), ('\u{2ccf}', 11470), - ('\u{2cd1}', 11472), ('\u{2cd3}', 11474), ('\u{2cd5}', 11476), ('\u{2cd7}', 11478), - ('\u{2cd9}', 11480), ('\u{2cdb}', 11482), ('\u{2cdd}', 11484), ('\u{2cdf}', 11486), - ('\u{2ce1}', 11488), ('\u{2ce3}', 11490), ('\u{2cec}', 11499), ('\u{2cee}', 11501), - ('\u{2cf3}', 11506), ('\u{2d00}', 4256), ('\u{2d01}', 4257), ('\u{2d02}', 4258), - ('\u{2d03}', 4259), ('\u{2d04}', 4260), ('\u{2d05}', 4261), ('\u{2d06}', 4262), - ('\u{2d07}', 4263), ('\u{2d08}', 4264), ('\u{2d09}', 4265), ('\u{2d0a}', 4266), - ('\u{2d0b}', 4267), ('\u{2d0c}', 4268), ('\u{2d0d}', 4269), ('\u{2d0e}', 4270), - ('\u{2d0f}', 4271), ('\u{2d10}', 4272), ('\u{2d11}', 4273), ('\u{2d12}', 4274), - ('\u{2d13}', 4275), ('\u{2d14}', 4276), ('\u{2d15}', 4277), ('\u{2d16}', 4278), - ('\u{2d17}', 4279), ('\u{2d18}', 4280), ('\u{2d19}', 4281), ('\u{2d1a}', 4282), - ('\u{2d1b}', 4283), ('\u{2d1c}', 4284), ('\u{2d1d}', 4285), ('\u{2d1e}', 4286), - ('\u{2d1f}', 4287), ('\u{2d20}', 4288), ('\u{2d21}', 4289), ('\u{2d22}', 4290), - ('\u{2d23}', 4291), ('\u{2d24}', 4292), ('\u{2d25}', 4293), ('\u{2d27}', 4295), - ('\u{2d2d}', 4301), ('\u{a641}', 42560), ('\u{a643}', 42562), ('\u{a645}', 42564), - ('\u{a647}', 42566), ('\u{a649}', 42568), ('\u{a64b}', 42570), ('\u{a64d}', 42572), - ('\u{a64f}', 42574), ('\u{a651}', 42576), ('\u{a653}', 42578), ('\u{a655}', 42580), - ('\u{a657}', 42582), ('\u{a659}', 42584), ('\u{a65b}', 42586), ('\u{a65d}', 42588), - ('\u{a65f}', 42590), ('\u{a661}', 42592), ('\u{a663}', 42594), ('\u{a665}', 42596), - ('\u{a667}', 42598), ('\u{a669}', 42600), ('\u{a66b}', 42602), ('\u{a66d}', 42604), - ('\u{a681}', 42624), ('\u{a683}', 42626), ('\u{a685}', 42628), ('\u{a687}', 42630), - ('\u{a689}', 42632), ('\u{a68b}', 42634), ('\u{a68d}', 42636), ('\u{a68f}', 42638), - ('\u{a691}', 42640), ('\u{a693}', 42642), ('\u{a695}', 42644), ('\u{a697}', 42646), - ('\u{a699}', 42648), ('\u{a69b}', 42650), ('\u{a723}', 42786), ('\u{a725}', 42788), - ('\u{a727}', 42790), ('\u{a729}', 42792), ('\u{a72b}', 42794), ('\u{a72d}', 42796), - ('\u{a72f}', 42798), ('\u{a733}', 42802), ('\u{a735}', 42804), ('\u{a737}', 42806), - ('\u{a739}', 42808), ('\u{a73b}', 42810), ('\u{a73d}', 42812), ('\u{a73f}', 42814), - ('\u{a741}', 42816), ('\u{a743}', 42818), ('\u{a745}', 42820), ('\u{a747}', 42822), - ('\u{a749}', 42824), ('\u{a74b}', 42826), ('\u{a74d}', 42828), ('\u{a74f}', 42830), - ('\u{a751}', 42832), ('\u{a753}', 42834), ('\u{a755}', 42836), ('\u{a757}', 42838), - ('\u{a759}', 42840), ('\u{a75b}', 42842), ('\u{a75d}', 42844), ('\u{a75f}', 42846), - ('\u{a761}', 42848), ('\u{a763}', 42850), ('\u{a765}', 42852), ('\u{a767}', 42854), - ('\u{a769}', 42856), ('\u{a76b}', 42858), ('\u{a76d}', 42860), ('\u{a76f}', 42862), - ('\u{a77a}', 42873), ('\u{a77c}', 42875), ('\u{a77f}', 42878), ('\u{a781}', 42880), - ('\u{a783}', 42882), ('\u{a785}', 42884), ('\u{a787}', 42886), ('\u{a78c}', 42891), - ('\u{a791}', 42896), ('\u{a793}', 42898), ('\u{a794}', 42948), ('\u{a797}', 42902), - ('\u{a799}', 42904), ('\u{a79b}', 42906), ('\u{a79d}', 42908), ('\u{a79f}', 42910), - ('\u{a7a1}', 42912), ('\u{a7a3}', 42914), ('\u{a7a5}', 42916), ('\u{a7a7}', 42918), - ('\u{a7a9}', 42920), ('\u{a7b5}', 42932), ('\u{a7b7}', 42934), ('\u{a7b9}', 42936), - ('\u{a7bb}', 42938), ('\u{a7bd}', 42940), ('\u{a7bf}', 42942), ('\u{a7c1}', 42944), - ('\u{a7c3}', 42946), ('\u{a7c8}', 42951), ('\u{a7ca}', 42953), ('\u{a7d1}', 42960), - ('\u{a7d7}', 42966), ('\u{a7d9}', 42968), ('\u{a7f6}', 42997), ('\u{ab53}', 42931), - ('\u{ab70}', 5024), ('\u{ab71}', 5025), ('\u{ab72}', 5026), ('\u{ab73}', 5027), - ('\u{ab74}', 5028), ('\u{ab75}', 5029), ('\u{ab76}', 5030), ('\u{ab77}', 5031), - ('\u{ab78}', 5032), ('\u{ab79}', 5033), ('\u{ab7a}', 5034), ('\u{ab7b}', 5035), - ('\u{ab7c}', 5036), ('\u{ab7d}', 5037), ('\u{ab7e}', 5038), ('\u{ab7f}', 5039), - ('\u{ab80}', 5040), ('\u{ab81}', 5041), ('\u{ab82}', 5042), ('\u{ab83}', 5043), - ('\u{ab84}', 5044), ('\u{ab85}', 5045), ('\u{ab86}', 5046), ('\u{ab87}', 5047), - ('\u{ab88}', 5048), ('\u{ab89}', 5049), ('\u{ab8a}', 5050), ('\u{ab8b}', 5051), - ('\u{ab8c}', 5052), ('\u{ab8d}', 5053), ('\u{ab8e}', 5054), ('\u{ab8f}', 5055), - ('\u{ab90}', 5056), ('\u{ab91}', 5057), ('\u{ab92}', 5058), ('\u{ab93}', 5059), - ('\u{ab94}', 5060), ('\u{ab95}', 5061), ('\u{ab96}', 5062), ('\u{ab97}', 5063), - ('\u{ab98}', 5064), ('\u{ab99}', 5065), ('\u{ab9a}', 5066), ('\u{ab9b}', 5067), - ('\u{ab9c}', 5068), ('\u{ab9d}', 5069), ('\u{ab9e}', 5070), ('\u{ab9f}', 5071), - ('\u{aba0}', 5072), ('\u{aba1}', 5073), ('\u{aba2}', 5074), ('\u{aba3}', 5075), - ('\u{aba4}', 5076), ('\u{aba5}', 5077), ('\u{aba6}', 5078), ('\u{aba7}', 5079), - ('\u{aba8}', 5080), ('\u{aba9}', 5081), ('\u{abaa}', 5082), ('\u{abab}', 5083), - ('\u{abac}', 5084), ('\u{abad}', 5085), ('\u{abae}', 5086), ('\u{abaf}', 5087), - ('\u{abb0}', 5088), ('\u{abb1}', 5089), ('\u{abb2}', 5090), ('\u{abb3}', 5091), - ('\u{abb4}', 5092), ('\u{abb5}', 5093), ('\u{abb6}', 5094), ('\u{abb7}', 5095), - ('\u{abb8}', 5096), ('\u{abb9}', 5097), ('\u{abba}', 5098), ('\u{abbb}', 5099), - ('\u{abbc}', 5100), ('\u{abbd}', 5101), ('\u{abbe}', 5102), ('\u{abbf}', 5103), - ('\u{fb00}', 4194394), ('\u{fb01}', 4194395), ('\u{fb02}', 4194396), ('\u{fb03}', 4194397), - ('\u{fb04}', 4194398), ('\u{fb05}', 4194399), ('\u{fb06}', 4194400), ('\u{fb13}', 4194401), - ('\u{fb14}', 4194402), ('\u{fb15}', 4194403), ('\u{fb16}', 4194404), ('\u{fb17}', 4194405), - ('\u{ff41}', 65313), ('\u{ff42}', 65314), ('\u{ff43}', 65315), ('\u{ff44}', 65316), - ('\u{ff45}', 65317), ('\u{ff46}', 65318), ('\u{ff47}', 65319), ('\u{ff48}', 65320), - ('\u{ff49}', 65321), ('\u{ff4a}', 65322), ('\u{ff4b}', 65323), ('\u{ff4c}', 65324), - ('\u{ff4d}', 65325), ('\u{ff4e}', 65326), ('\u{ff4f}', 65327), ('\u{ff50}', 65328), - ('\u{ff51}', 65329), ('\u{ff52}', 65330), ('\u{ff53}', 65331), ('\u{ff54}', 65332), - ('\u{ff55}', 65333), ('\u{ff56}', 65334), ('\u{ff57}', 65335), ('\u{ff58}', 65336), - ('\u{ff59}', 65337), ('\u{ff5a}', 65338), ('\u{10428}', 66560), ('\u{10429}', 66561), - ('\u{1042a}', 66562), ('\u{1042b}', 66563), ('\u{1042c}', 66564), ('\u{1042d}', 66565), - ('\u{1042e}', 66566), ('\u{1042f}', 66567), ('\u{10430}', 66568), ('\u{10431}', 66569), - ('\u{10432}', 66570), ('\u{10433}', 66571), ('\u{10434}', 66572), ('\u{10435}', 66573), - ('\u{10436}', 66574), ('\u{10437}', 66575), ('\u{10438}', 66576), ('\u{10439}', 66577), - ('\u{1043a}', 66578), ('\u{1043b}', 66579), ('\u{1043c}', 66580), ('\u{1043d}', 66581), - ('\u{1043e}', 66582), ('\u{1043f}', 66583), ('\u{10440}', 66584), ('\u{10441}', 66585), - ('\u{10442}', 66586), ('\u{10443}', 66587), ('\u{10444}', 66588), ('\u{10445}', 66589), - ('\u{10446}', 66590), ('\u{10447}', 66591), ('\u{10448}', 66592), ('\u{10449}', 66593), - ('\u{1044a}', 66594), ('\u{1044b}', 66595), ('\u{1044c}', 66596), ('\u{1044d}', 66597), - ('\u{1044e}', 66598), ('\u{1044f}', 66599), ('\u{104d8}', 66736), ('\u{104d9}', 66737), - ('\u{104da}', 66738), ('\u{104db}', 66739), ('\u{104dc}', 66740), ('\u{104dd}', 66741), - ('\u{104de}', 66742), ('\u{104df}', 66743), ('\u{104e0}', 66744), ('\u{104e1}', 66745), - ('\u{104e2}', 66746), ('\u{104e3}', 66747), ('\u{104e4}', 66748), ('\u{104e5}', 66749), - ('\u{104e6}', 66750), ('\u{104e7}', 66751), ('\u{104e8}', 66752), ('\u{104e9}', 66753), - ('\u{104ea}', 66754), ('\u{104eb}', 66755), ('\u{104ec}', 66756), ('\u{104ed}', 66757), - ('\u{104ee}', 66758), ('\u{104ef}', 66759), ('\u{104f0}', 66760), ('\u{104f1}', 66761), - ('\u{104f2}', 66762), ('\u{104f3}', 66763), ('\u{104f4}', 66764), ('\u{104f5}', 66765), - ('\u{104f6}', 66766), ('\u{104f7}', 66767), ('\u{104f8}', 66768), ('\u{104f9}', 66769), - ('\u{104fa}', 66770), ('\u{104fb}', 66771), ('\u{10597}', 66928), ('\u{10598}', 66929), - ('\u{10599}', 66930), ('\u{1059a}', 66931), ('\u{1059b}', 66932), ('\u{1059c}', 66933), - ('\u{1059d}', 66934), ('\u{1059e}', 66935), ('\u{1059f}', 66936), ('\u{105a0}', 66937), - ('\u{105a1}', 66938), ('\u{105a3}', 66940), ('\u{105a4}', 66941), ('\u{105a5}', 66942), - ('\u{105a6}', 66943), ('\u{105a7}', 66944), ('\u{105a8}', 66945), ('\u{105a9}', 66946), - ('\u{105aa}', 66947), ('\u{105ab}', 66948), ('\u{105ac}', 66949), ('\u{105ad}', 66950), - ('\u{105ae}', 66951), ('\u{105af}', 66952), ('\u{105b0}', 66953), ('\u{105b1}', 66954), - ('\u{105b3}', 66956), ('\u{105b4}', 66957), ('\u{105b5}', 66958), ('\u{105b6}', 66959), - ('\u{105b7}', 66960), ('\u{105b8}', 66961), ('\u{105b9}', 66962), ('\u{105bb}', 66964), - ('\u{105bc}', 66965), ('\u{10cc0}', 68736), ('\u{10cc1}', 68737), ('\u{10cc2}', 68738), - ('\u{10cc3}', 68739), ('\u{10cc4}', 68740), ('\u{10cc5}', 68741), ('\u{10cc6}', 68742), - ('\u{10cc7}', 68743), ('\u{10cc8}', 68744), ('\u{10cc9}', 68745), ('\u{10cca}', 68746), - ('\u{10ccb}', 68747), ('\u{10ccc}', 68748), ('\u{10ccd}', 68749), ('\u{10cce}', 68750), - ('\u{10ccf}', 68751), ('\u{10cd0}', 68752), ('\u{10cd1}', 68753), ('\u{10cd2}', 68754), - ('\u{10cd3}', 68755), ('\u{10cd4}', 68756), ('\u{10cd5}', 68757), ('\u{10cd6}', 68758), - ('\u{10cd7}', 68759), ('\u{10cd8}', 68760), ('\u{10cd9}', 68761), ('\u{10cda}', 68762), - ('\u{10cdb}', 68763), ('\u{10cdc}', 68764), ('\u{10cdd}', 68765), ('\u{10cde}', 68766), - ('\u{10cdf}', 68767), ('\u{10ce0}', 68768), ('\u{10ce1}', 68769), ('\u{10ce2}', 68770), - ('\u{10ce3}', 68771), ('\u{10ce4}', 68772), ('\u{10ce5}', 68773), ('\u{10ce6}', 68774), - ('\u{10ce7}', 68775), ('\u{10ce8}', 68776), ('\u{10ce9}', 68777), ('\u{10cea}', 68778), - ('\u{10ceb}', 68779), ('\u{10cec}', 68780), ('\u{10ced}', 68781), ('\u{10cee}', 68782), - ('\u{10cef}', 68783), ('\u{10cf0}', 68784), ('\u{10cf1}', 68785), ('\u{10cf2}', 68786), - ('\u{118c0}', 71840), ('\u{118c1}', 71841), ('\u{118c2}', 71842), ('\u{118c3}', 71843), - ('\u{118c4}', 71844), ('\u{118c5}', 71845), ('\u{118c6}', 71846), ('\u{118c7}', 71847), - ('\u{118c8}', 71848), ('\u{118c9}', 71849), ('\u{118ca}', 71850), ('\u{118cb}', 71851), - ('\u{118cc}', 71852), ('\u{118cd}', 71853), ('\u{118ce}', 71854), ('\u{118cf}', 71855), - ('\u{118d0}', 71856), ('\u{118d1}', 71857), ('\u{118d2}', 71858), ('\u{118d3}', 71859), - ('\u{118d4}', 71860), ('\u{118d5}', 71861), ('\u{118d6}', 71862), ('\u{118d7}', 71863), - ('\u{118d8}', 71864), ('\u{118d9}', 71865), ('\u{118da}', 71866), ('\u{118db}', 71867), - ('\u{118dc}', 71868), ('\u{118dd}', 71869), ('\u{118de}', 71870), ('\u{118df}', 71871), - ('\u{16e60}', 93760), ('\u{16e61}', 93761), ('\u{16e62}', 93762), ('\u{16e63}', 93763), - ('\u{16e64}', 93764), ('\u{16e65}', 93765), ('\u{16e66}', 93766), ('\u{16e67}', 93767), - ('\u{16e68}', 93768), ('\u{16e69}', 93769), ('\u{16e6a}', 93770), ('\u{16e6b}', 93771), - ('\u{16e6c}', 93772), ('\u{16e6d}', 93773), ('\u{16e6e}', 93774), ('\u{16e6f}', 93775), - ('\u{16e70}', 93776), ('\u{16e71}', 93777), ('\u{16e72}', 93778), ('\u{16e73}', 93779), - ('\u{16e74}', 93780), ('\u{16e75}', 93781), ('\u{16e76}', 93782), ('\u{16e77}', 93783), - ('\u{16e78}', 93784), ('\u{16e79}', 93785), ('\u{16e7a}', 93786), ('\u{16e7b}', 93787), - ('\u{16e7c}', 93788), ('\u{16e7d}', 93789), ('\u{16e7e}', 93790), ('\u{16e7f}', 93791), - ('\u{1e922}', 125184), ('\u{1e923}', 125185), ('\u{1e924}', 125186), ('\u{1e925}', 125187), - ('\u{1e926}', 125188), ('\u{1e927}', 125189), ('\u{1e928}', 125190), ('\u{1e929}', 125191), - ('\u{1e92a}', 125192), ('\u{1e92b}', 125193), ('\u{1e92c}', 125194), ('\u{1e92d}', 125195), - ('\u{1e92e}', 125196), ('\u{1e92f}', 125197), ('\u{1e930}', 125198), ('\u{1e931}', 125199), - ('\u{1e932}', 125200), ('\u{1e933}', 125201), ('\u{1e934}', 125202), ('\u{1e935}', 125203), - ('\u{1e936}', 125204), ('\u{1e937}', 125205), ('\u{1e938}', 125206), ('\u{1e939}', 125207), - ('\u{1e93a}', 125208), ('\u{1e93b}', 125209), ('\u{1e93c}', 125210), ('\u{1e93d}', 125211), - ('\u{1e93e}', 125212), ('\u{1e93f}', 125213), ('\u{1e940}', 125214), ('\u{1e941}', 125215), - ('\u{1e942}', 125216), ('\u{1e943}', 125217), + ('\u{1c86}', 1066), ('\u{1c87}', 1122), ('\u{1c88}', 42570), ('\u{1c8a}', 7305), + ('\u{1d79}', 42877), ('\u{1d7d}', 11363), ('\u{1d8e}', 42950), ('\u{1e01}', 7680), + ('\u{1e03}', 7682), ('\u{1e05}', 7684), ('\u{1e07}', 7686), ('\u{1e09}', 7688), + ('\u{1e0b}', 7690), ('\u{1e0d}', 7692), ('\u{1e0f}', 7694), ('\u{1e11}', 7696), + ('\u{1e13}', 7698), ('\u{1e15}', 7700), ('\u{1e17}', 7702), ('\u{1e19}', 7704), + ('\u{1e1b}', 7706), ('\u{1e1d}', 7708), ('\u{1e1f}', 7710), ('\u{1e21}', 7712), + ('\u{1e23}', 7714), ('\u{1e25}', 7716), ('\u{1e27}', 7718), ('\u{1e29}', 7720), + ('\u{1e2b}', 7722), ('\u{1e2d}', 7724), ('\u{1e2f}', 7726), ('\u{1e31}', 7728), + ('\u{1e33}', 7730), ('\u{1e35}', 7732), ('\u{1e37}', 7734), ('\u{1e39}', 7736), + ('\u{1e3b}', 7738), ('\u{1e3d}', 7740), ('\u{1e3f}', 7742), ('\u{1e41}', 7744), + ('\u{1e43}', 7746), ('\u{1e45}', 7748), ('\u{1e47}', 7750), ('\u{1e49}', 7752), + ('\u{1e4b}', 7754), ('\u{1e4d}', 7756), ('\u{1e4f}', 7758), ('\u{1e51}', 7760), + ('\u{1e53}', 7762), ('\u{1e55}', 7764), ('\u{1e57}', 7766), ('\u{1e59}', 7768), + ('\u{1e5b}', 7770), ('\u{1e5d}', 7772), ('\u{1e5f}', 7774), ('\u{1e61}', 7776), + ('\u{1e63}', 7778), ('\u{1e65}', 7780), ('\u{1e67}', 7782), ('\u{1e69}', 7784), + ('\u{1e6b}', 7786), ('\u{1e6d}', 7788), ('\u{1e6f}', 7790), ('\u{1e71}', 7792), + ('\u{1e73}', 7794), ('\u{1e75}', 7796), ('\u{1e77}', 7798), ('\u{1e79}', 7800), + ('\u{1e7b}', 7802), ('\u{1e7d}', 7804), ('\u{1e7f}', 7806), ('\u{1e81}', 7808), + ('\u{1e83}', 7810), ('\u{1e85}', 7812), ('\u{1e87}', 7814), ('\u{1e89}', 7816), + ('\u{1e8b}', 7818), ('\u{1e8d}', 7820), ('\u{1e8f}', 7822), ('\u{1e91}', 7824), + ('\u{1e93}', 7826), ('\u{1e95}', 7828), ('\u{1e96}', 4194310), ('\u{1e97}', 4194311), + ('\u{1e98}', 4194312), ('\u{1e99}', 4194313), ('\u{1e9a}', 4194314), ('\u{1e9b}', 7776), + ('\u{1ea1}', 7840), ('\u{1ea3}', 7842), ('\u{1ea5}', 7844), ('\u{1ea7}', 7846), + ('\u{1ea9}', 7848), ('\u{1eab}', 7850), ('\u{1ead}', 7852), ('\u{1eaf}', 7854), + ('\u{1eb1}', 7856), ('\u{1eb3}', 7858), ('\u{1eb5}', 7860), ('\u{1eb7}', 7862), + ('\u{1eb9}', 7864), ('\u{1ebb}', 7866), ('\u{1ebd}', 7868), ('\u{1ebf}', 7870), + ('\u{1ec1}', 7872), ('\u{1ec3}', 7874), ('\u{1ec5}', 7876), ('\u{1ec7}', 7878), + ('\u{1ec9}', 7880), ('\u{1ecb}', 7882), ('\u{1ecd}', 7884), ('\u{1ecf}', 7886), + ('\u{1ed1}', 7888), ('\u{1ed3}', 7890), ('\u{1ed5}', 7892), ('\u{1ed7}', 7894), + ('\u{1ed9}', 7896), ('\u{1edb}', 7898), ('\u{1edd}', 7900), ('\u{1edf}', 7902), + ('\u{1ee1}', 7904), ('\u{1ee3}', 7906), ('\u{1ee5}', 7908), ('\u{1ee7}', 7910), + ('\u{1ee9}', 7912), ('\u{1eeb}', 7914), ('\u{1eed}', 7916), ('\u{1eef}', 7918), + ('\u{1ef1}', 7920), ('\u{1ef3}', 7922), ('\u{1ef5}', 7924), ('\u{1ef7}', 7926), + ('\u{1ef9}', 7928), ('\u{1efb}', 7930), ('\u{1efd}', 7932), ('\u{1eff}', 7934), + ('\u{1f00}', 7944), ('\u{1f01}', 7945), ('\u{1f02}', 7946), ('\u{1f03}', 7947), + ('\u{1f04}', 7948), ('\u{1f05}', 7949), ('\u{1f06}', 7950), ('\u{1f07}', 7951), + ('\u{1f10}', 7960), ('\u{1f11}', 7961), ('\u{1f12}', 7962), ('\u{1f13}', 7963), + ('\u{1f14}', 7964), ('\u{1f15}', 7965), ('\u{1f20}', 7976), ('\u{1f21}', 7977), + ('\u{1f22}', 7978), ('\u{1f23}', 7979), ('\u{1f24}', 7980), ('\u{1f25}', 7981), + ('\u{1f26}', 7982), ('\u{1f27}', 7983), ('\u{1f30}', 7992), ('\u{1f31}', 7993), + ('\u{1f32}', 7994), ('\u{1f33}', 7995), ('\u{1f34}', 7996), ('\u{1f35}', 7997), + ('\u{1f36}', 7998), ('\u{1f37}', 7999), ('\u{1f40}', 8008), ('\u{1f41}', 8009), + ('\u{1f42}', 8010), ('\u{1f43}', 8011), ('\u{1f44}', 8012), ('\u{1f45}', 8013), + ('\u{1f50}', 4194315), ('\u{1f51}', 8025), ('\u{1f52}', 4194316), ('\u{1f53}', 8027), + ('\u{1f54}', 4194317), ('\u{1f55}', 8029), ('\u{1f56}', 4194318), ('\u{1f57}', 8031), + ('\u{1f60}', 8040), ('\u{1f61}', 8041), ('\u{1f62}', 8042), ('\u{1f63}', 8043), + ('\u{1f64}', 8044), ('\u{1f65}', 8045), ('\u{1f66}', 8046), ('\u{1f67}', 8047), + ('\u{1f70}', 8122), ('\u{1f71}', 8123), ('\u{1f72}', 8136), ('\u{1f73}', 8137), + ('\u{1f74}', 8138), ('\u{1f75}', 8139), ('\u{1f76}', 8154), ('\u{1f77}', 8155), + ('\u{1f78}', 8184), ('\u{1f79}', 8185), ('\u{1f7a}', 8170), ('\u{1f7b}', 8171), + ('\u{1f7c}', 8186), ('\u{1f7d}', 8187), ('\u{1f80}', 4194319), ('\u{1f81}', 4194320), + ('\u{1f82}', 4194321), ('\u{1f83}', 4194322), ('\u{1f84}', 4194323), ('\u{1f85}', 4194324), + ('\u{1f86}', 4194325), ('\u{1f87}', 4194326), ('\u{1f88}', 4194327), ('\u{1f89}', 4194328), + ('\u{1f8a}', 4194329), ('\u{1f8b}', 4194330), ('\u{1f8c}', 4194331), ('\u{1f8d}', 4194332), + ('\u{1f8e}', 4194333), ('\u{1f8f}', 4194334), ('\u{1f90}', 4194335), ('\u{1f91}', 4194336), + ('\u{1f92}', 4194337), ('\u{1f93}', 4194338), ('\u{1f94}', 4194339), ('\u{1f95}', 4194340), + ('\u{1f96}', 4194341), ('\u{1f97}', 4194342), ('\u{1f98}', 4194343), ('\u{1f99}', 4194344), + ('\u{1f9a}', 4194345), ('\u{1f9b}', 4194346), ('\u{1f9c}', 4194347), ('\u{1f9d}', 4194348), + ('\u{1f9e}', 4194349), ('\u{1f9f}', 4194350), ('\u{1fa0}', 4194351), ('\u{1fa1}', 4194352), + ('\u{1fa2}', 4194353), ('\u{1fa3}', 4194354), ('\u{1fa4}', 4194355), ('\u{1fa5}', 4194356), + ('\u{1fa6}', 4194357), ('\u{1fa7}', 4194358), ('\u{1fa8}', 4194359), ('\u{1fa9}', 4194360), + ('\u{1faa}', 4194361), ('\u{1fab}', 4194362), ('\u{1fac}', 4194363), ('\u{1fad}', 4194364), + ('\u{1fae}', 4194365), ('\u{1faf}', 4194366), ('\u{1fb0}', 8120), ('\u{1fb1}', 8121), + ('\u{1fb2}', 4194367), ('\u{1fb3}', 4194368), ('\u{1fb4}', 4194369), ('\u{1fb6}', 4194370), + ('\u{1fb7}', 4194371), ('\u{1fbc}', 4194372), ('\u{1fbe}', 921), ('\u{1fc2}', 4194373), + ('\u{1fc3}', 4194374), ('\u{1fc4}', 4194375), ('\u{1fc6}', 4194376), ('\u{1fc7}', 4194377), + ('\u{1fcc}', 4194378), ('\u{1fd0}', 8152), ('\u{1fd1}', 8153), ('\u{1fd2}', 4194379), + ('\u{1fd3}', 4194380), ('\u{1fd6}', 4194381), ('\u{1fd7}', 4194382), ('\u{1fe0}', 8168), + ('\u{1fe1}', 8169), ('\u{1fe2}', 4194383), ('\u{1fe3}', 4194384), ('\u{1fe4}', 4194385), + ('\u{1fe5}', 8172), ('\u{1fe6}', 4194386), ('\u{1fe7}', 4194387), ('\u{1ff2}', 4194388), + ('\u{1ff3}', 4194389), ('\u{1ff4}', 4194390), ('\u{1ff6}', 4194391), ('\u{1ff7}', 4194392), + ('\u{1ffc}', 4194393), ('\u{214e}', 8498), ('\u{2170}', 8544), ('\u{2171}', 8545), + ('\u{2172}', 8546), ('\u{2173}', 8547), ('\u{2174}', 8548), ('\u{2175}', 8549), + ('\u{2176}', 8550), ('\u{2177}', 8551), ('\u{2178}', 8552), ('\u{2179}', 8553), + ('\u{217a}', 8554), ('\u{217b}', 8555), ('\u{217c}', 8556), ('\u{217d}', 8557), + ('\u{217e}', 8558), ('\u{217f}', 8559), ('\u{2184}', 8579), ('\u{24d0}', 9398), + ('\u{24d1}', 9399), ('\u{24d2}', 9400), ('\u{24d3}', 9401), ('\u{24d4}', 9402), + ('\u{24d5}', 9403), ('\u{24d6}', 9404), ('\u{24d7}', 9405), ('\u{24d8}', 9406), + ('\u{24d9}', 9407), ('\u{24da}', 9408), ('\u{24db}', 9409), ('\u{24dc}', 9410), + ('\u{24dd}', 9411), ('\u{24de}', 9412), ('\u{24df}', 9413), ('\u{24e0}', 9414), + ('\u{24e1}', 9415), ('\u{24e2}', 9416), ('\u{24e3}', 9417), ('\u{24e4}', 9418), + ('\u{24e5}', 9419), ('\u{24e6}', 9420), ('\u{24e7}', 9421), ('\u{24e8}', 9422), + ('\u{24e9}', 9423), ('\u{2c30}', 11264), ('\u{2c31}', 11265), ('\u{2c32}', 11266), + ('\u{2c33}', 11267), ('\u{2c34}', 11268), ('\u{2c35}', 11269), ('\u{2c36}', 11270), + ('\u{2c37}', 11271), ('\u{2c38}', 11272), ('\u{2c39}', 11273), ('\u{2c3a}', 11274), + ('\u{2c3b}', 11275), ('\u{2c3c}', 11276), ('\u{2c3d}', 11277), ('\u{2c3e}', 11278), + ('\u{2c3f}', 11279), ('\u{2c40}', 11280), ('\u{2c41}', 11281), ('\u{2c42}', 11282), + ('\u{2c43}', 11283), ('\u{2c44}', 11284), ('\u{2c45}', 11285), ('\u{2c46}', 11286), + ('\u{2c47}', 11287), ('\u{2c48}', 11288), ('\u{2c49}', 11289), ('\u{2c4a}', 11290), + ('\u{2c4b}', 11291), ('\u{2c4c}', 11292), ('\u{2c4d}', 11293), ('\u{2c4e}', 11294), + ('\u{2c4f}', 11295), ('\u{2c50}', 11296), ('\u{2c51}', 11297), ('\u{2c52}', 11298), + ('\u{2c53}', 11299), ('\u{2c54}', 11300), ('\u{2c55}', 11301), ('\u{2c56}', 11302), + ('\u{2c57}', 11303), ('\u{2c58}', 11304), ('\u{2c59}', 11305), ('\u{2c5a}', 11306), + ('\u{2c5b}', 11307), ('\u{2c5c}', 11308), ('\u{2c5d}', 11309), ('\u{2c5e}', 11310), + ('\u{2c5f}', 11311), ('\u{2c61}', 11360), ('\u{2c65}', 570), ('\u{2c66}', 574), + ('\u{2c68}', 11367), ('\u{2c6a}', 11369), ('\u{2c6c}', 11371), ('\u{2c73}', 11378), + ('\u{2c76}', 11381), ('\u{2c81}', 11392), ('\u{2c83}', 11394), ('\u{2c85}', 11396), + ('\u{2c87}', 11398), ('\u{2c89}', 11400), ('\u{2c8b}', 11402), ('\u{2c8d}', 11404), + ('\u{2c8f}', 11406), ('\u{2c91}', 11408), ('\u{2c93}', 11410), ('\u{2c95}', 11412), + ('\u{2c97}', 11414), ('\u{2c99}', 11416), ('\u{2c9b}', 11418), ('\u{2c9d}', 11420), + ('\u{2c9f}', 11422), ('\u{2ca1}', 11424), ('\u{2ca3}', 11426), ('\u{2ca5}', 11428), + ('\u{2ca7}', 11430), ('\u{2ca9}', 11432), ('\u{2cab}', 11434), ('\u{2cad}', 11436), + ('\u{2caf}', 11438), ('\u{2cb1}', 11440), ('\u{2cb3}', 11442), ('\u{2cb5}', 11444), + ('\u{2cb7}', 11446), ('\u{2cb9}', 11448), ('\u{2cbb}', 11450), ('\u{2cbd}', 11452), + ('\u{2cbf}', 11454), ('\u{2cc1}', 11456), ('\u{2cc3}', 11458), ('\u{2cc5}', 11460), + ('\u{2cc7}', 11462), ('\u{2cc9}', 11464), ('\u{2ccb}', 11466), ('\u{2ccd}', 11468), + ('\u{2ccf}', 11470), ('\u{2cd1}', 11472), ('\u{2cd3}', 11474), ('\u{2cd5}', 11476), + ('\u{2cd7}', 11478), ('\u{2cd9}', 11480), ('\u{2cdb}', 11482), ('\u{2cdd}', 11484), + ('\u{2cdf}', 11486), ('\u{2ce1}', 11488), ('\u{2ce3}', 11490), ('\u{2cec}', 11499), + ('\u{2cee}', 11501), ('\u{2cf3}', 11506), ('\u{2d00}', 4256), ('\u{2d01}', 4257), + ('\u{2d02}', 4258), ('\u{2d03}', 4259), ('\u{2d04}', 4260), ('\u{2d05}', 4261), + ('\u{2d06}', 4262), ('\u{2d07}', 4263), ('\u{2d08}', 4264), ('\u{2d09}', 4265), + ('\u{2d0a}', 4266), ('\u{2d0b}', 4267), ('\u{2d0c}', 4268), ('\u{2d0d}', 4269), + ('\u{2d0e}', 4270), ('\u{2d0f}', 4271), ('\u{2d10}', 4272), ('\u{2d11}', 4273), + ('\u{2d12}', 4274), ('\u{2d13}', 4275), ('\u{2d14}', 4276), ('\u{2d15}', 4277), + ('\u{2d16}', 4278), ('\u{2d17}', 4279), ('\u{2d18}', 4280), ('\u{2d19}', 4281), + ('\u{2d1a}', 4282), ('\u{2d1b}', 4283), ('\u{2d1c}', 4284), ('\u{2d1d}', 4285), + ('\u{2d1e}', 4286), ('\u{2d1f}', 4287), ('\u{2d20}', 4288), ('\u{2d21}', 4289), + ('\u{2d22}', 4290), ('\u{2d23}', 4291), ('\u{2d24}', 4292), ('\u{2d25}', 4293), + ('\u{2d27}', 4295), ('\u{2d2d}', 4301), ('\u{a641}', 42560), ('\u{a643}', 42562), + ('\u{a645}', 42564), ('\u{a647}', 42566), ('\u{a649}', 42568), ('\u{a64b}', 42570), + ('\u{a64d}', 42572), ('\u{a64f}', 42574), ('\u{a651}', 42576), ('\u{a653}', 42578), + ('\u{a655}', 42580), ('\u{a657}', 42582), ('\u{a659}', 42584), ('\u{a65b}', 42586), + ('\u{a65d}', 42588), ('\u{a65f}', 42590), ('\u{a661}', 42592), ('\u{a663}', 42594), + ('\u{a665}', 42596), ('\u{a667}', 42598), ('\u{a669}', 42600), ('\u{a66b}', 42602), + ('\u{a66d}', 42604), ('\u{a681}', 42624), ('\u{a683}', 42626), ('\u{a685}', 42628), + ('\u{a687}', 42630), ('\u{a689}', 42632), ('\u{a68b}', 42634), ('\u{a68d}', 42636), + ('\u{a68f}', 42638), ('\u{a691}', 42640), ('\u{a693}', 42642), ('\u{a695}', 42644), + ('\u{a697}', 42646), ('\u{a699}', 42648), ('\u{a69b}', 42650), ('\u{a723}', 42786), + ('\u{a725}', 42788), ('\u{a727}', 42790), ('\u{a729}', 42792), ('\u{a72b}', 42794), + ('\u{a72d}', 42796), ('\u{a72f}', 42798), ('\u{a733}', 42802), ('\u{a735}', 42804), + ('\u{a737}', 42806), ('\u{a739}', 42808), ('\u{a73b}', 42810), ('\u{a73d}', 42812), + ('\u{a73f}', 42814), ('\u{a741}', 42816), ('\u{a743}', 42818), ('\u{a745}', 42820), + ('\u{a747}', 42822), ('\u{a749}', 42824), ('\u{a74b}', 42826), ('\u{a74d}', 42828), + ('\u{a74f}', 42830), ('\u{a751}', 42832), ('\u{a753}', 42834), ('\u{a755}', 42836), + ('\u{a757}', 42838), ('\u{a759}', 42840), ('\u{a75b}', 42842), ('\u{a75d}', 42844), + ('\u{a75f}', 42846), ('\u{a761}', 42848), ('\u{a763}', 42850), ('\u{a765}', 42852), + ('\u{a767}', 42854), ('\u{a769}', 42856), ('\u{a76b}', 42858), ('\u{a76d}', 42860), + ('\u{a76f}', 42862), ('\u{a77a}', 42873), ('\u{a77c}', 42875), ('\u{a77f}', 42878), + ('\u{a781}', 42880), ('\u{a783}', 42882), ('\u{a785}', 42884), ('\u{a787}', 42886), + ('\u{a78c}', 42891), ('\u{a791}', 42896), ('\u{a793}', 42898), ('\u{a794}', 42948), + ('\u{a797}', 42902), ('\u{a799}', 42904), ('\u{a79b}', 42906), ('\u{a79d}', 42908), + ('\u{a79f}', 42910), ('\u{a7a1}', 42912), ('\u{a7a3}', 42914), ('\u{a7a5}', 42916), + ('\u{a7a7}', 42918), ('\u{a7a9}', 42920), ('\u{a7b5}', 42932), ('\u{a7b7}', 42934), + ('\u{a7b9}', 42936), ('\u{a7bb}', 42938), ('\u{a7bd}', 42940), ('\u{a7bf}', 42942), + ('\u{a7c1}', 42944), ('\u{a7c3}', 42946), ('\u{a7c8}', 42951), ('\u{a7ca}', 42953), + ('\u{a7cd}', 42956), ('\u{a7d1}', 42960), ('\u{a7d7}', 42966), ('\u{a7d9}', 42968), + ('\u{a7db}', 42970), ('\u{a7f6}', 42997), ('\u{ab53}', 42931), ('\u{ab70}', 5024), + ('\u{ab71}', 5025), ('\u{ab72}', 5026), ('\u{ab73}', 5027), ('\u{ab74}', 5028), + ('\u{ab75}', 5029), ('\u{ab76}', 5030), ('\u{ab77}', 5031), ('\u{ab78}', 5032), + ('\u{ab79}', 5033), ('\u{ab7a}', 5034), ('\u{ab7b}', 5035), ('\u{ab7c}', 5036), + ('\u{ab7d}', 5037), ('\u{ab7e}', 5038), ('\u{ab7f}', 5039), ('\u{ab80}', 5040), + ('\u{ab81}', 5041), ('\u{ab82}', 5042), ('\u{ab83}', 5043), ('\u{ab84}', 5044), + ('\u{ab85}', 5045), ('\u{ab86}', 5046), ('\u{ab87}', 5047), ('\u{ab88}', 5048), + ('\u{ab89}', 5049), ('\u{ab8a}', 5050), ('\u{ab8b}', 5051), ('\u{ab8c}', 5052), + ('\u{ab8d}', 5053), ('\u{ab8e}', 5054), ('\u{ab8f}', 5055), ('\u{ab90}', 5056), + ('\u{ab91}', 5057), ('\u{ab92}', 5058), ('\u{ab93}', 5059), ('\u{ab94}', 5060), + ('\u{ab95}', 5061), ('\u{ab96}', 5062), ('\u{ab97}', 5063), ('\u{ab98}', 5064), + ('\u{ab99}', 5065), ('\u{ab9a}', 5066), ('\u{ab9b}', 5067), ('\u{ab9c}', 5068), + ('\u{ab9d}', 5069), ('\u{ab9e}', 5070), ('\u{ab9f}', 5071), ('\u{aba0}', 5072), + ('\u{aba1}', 5073), ('\u{aba2}', 5074), ('\u{aba3}', 5075), ('\u{aba4}', 5076), + ('\u{aba5}', 5077), ('\u{aba6}', 5078), ('\u{aba7}', 5079), ('\u{aba8}', 5080), + ('\u{aba9}', 5081), ('\u{abaa}', 5082), ('\u{abab}', 5083), ('\u{abac}', 5084), + ('\u{abad}', 5085), ('\u{abae}', 5086), ('\u{abaf}', 5087), ('\u{abb0}', 5088), + ('\u{abb1}', 5089), ('\u{abb2}', 5090), ('\u{abb3}', 5091), ('\u{abb4}', 5092), + ('\u{abb5}', 5093), ('\u{abb6}', 5094), ('\u{abb7}', 5095), ('\u{abb8}', 5096), + ('\u{abb9}', 5097), ('\u{abba}', 5098), ('\u{abbb}', 5099), ('\u{abbc}', 5100), + ('\u{abbd}', 5101), ('\u{abbe}', 5102), ('\u{abbf}', 5103), ('\u{fb00}', 4194394), + ('\u{fb01}', 4194395), ('\u{fb02}', 4194396), ('\u{fb03}', 4194397), ('\u{fb04}', 4194398), + ('\u{fb05}', 4194399), ('\u{fb06}', 4194400), ('\u{fb13}', 4194401), ('\u{fb14}', 4194402), + ('\u{fb15}', 4194403), ('\u{fb16}', 4194404), ('\u{fb17}', 4194405), ('\u{ff41}', 65313), + ('\u{ff42}', 65314), ('\u{ff43}', 65315), ('\u{ff44}', 65316), ('\u{ff45}', 65317), + ('\u{ff46}', 65318), ('\u{ff47}', 65319), ('\u{ff48}', 65320), ('\u{ff49}', 65321), + ('\u{ff4a}', 65322), ('\u{ff4b}', 65323), ('\u{ff4c}', 65324), ('\u{ff4d}', 65325), + ('\u{ff4e}', 65326), ('\u{ff4f}', 65327), ('\u{ff50}', 65328), ('\u{ff51}', 65329), + ('\u{ff52}', 65330), ('\u{ff53}', 65331), ('\u{ff54}', 65332), ('\u{ff55}', 65333), + ('\u{ff56}', 65334), ('\u{ff57}', 65335), ('\u{ff58}', 65336), ('\u{ff59}', 65337), + ('\u{ff5a}', 65338), ('\u{10428}', 66560), ('\u{10429}', 66561), ('\u{1042a}', 66562), + ('\u{1042b}', 66563), ('\u{1042c}', 66564), ('\u{1042d}', 66565), ('\u{1042e}', 66566), + ('\u{1042f}', 66567), ('\u{10430}', 66568), ('\u{10431}', 66569), ('\u{10432}', 66570), + ('\u{10433}', 66571), ('\u{10434}', 66572), ('\u{10435}', 66573), ('\u{10436}', 66574), + ('\u{10437}', 66575), ('\u{10438}', 66576), ('\u{10439}', 66577), ('\u{1043a}', 66578), + ('\u{1043b}', 66579), ('\u{1043c}', 66580), ('\u{1043d}', 66581), ('\u{1043e}', 66582), + ('\u{1043f}', 66583), ('\u{10440}', 66584), ('\u{10441}', 66585), ('\u{10442}', 66586), + ('\u{10443}', 66587), ('\u{10444}', 66588), ('\u{10445}', 66589), ('\u{10446}', 66590), + ('\u{10447}', 66591), ('\u{10448}', 66592), ('\u{10449}', 66593), ('\u{1044a}', 66594), + ('\u{1044b}', 66595), ('\u{1044c}', 66596), ('\u{1044d}', 66597), ('\u{1044e}', 66598), + ('\u{1044f}', 66599), ('\u{104d8}', 66736), ('\u{104d9}', 66737), ('\u{104da}', 66738), + ('\u{104db}', 66739), ('\u{104dc}', 66740), ('\u{104dd}', 66741), ('\u{104de}', 66742), + ('\u{104df}', 66743), ('\u{104e0}', 66744), ('\u{104e1}', 66745), ('\u{104e2}', 66746), + ('\u{104e3}', 66747), ('\u{104e4}', 66748), ('\u{104e5}', 66749), ('\u{104e6}', 66750), + ('\u{104e7}', 66751), ('\u{104e8}', 66752), ('\u{104e9}', 66753), ('\u{104ea}', 66754), + ('\u{104eb}', 66755), ('\u{104ec}', 66756), ('\u{104ed}', 66757), ('\u{104ee}', 66758), + ('\u{104ef}', 66759), ('\u{104f0}', 66760), ('\u{104f1}', 66761), ('\u{104f2}', 66762), + ('\u{104f3}', 66763), ('\u{104f4}', 66764), ('\u{104f5}', 66765), ('\u{104f6}', 66766), + ('\u{104f7}', 66767), ('\u{104f8}', 66768), ('\u{104f9}', 66769), ('\u{104fa}', 66770), + ('\u{104fb}', 66771), ('\u{10597}', 66928), ('\u{10598}', 66929), ('\u{10599}', 66930), + ('\u{1059a}', 66931), ('\u{1059b}', 66932), ('\u{1059c}', 66933), ('\u{1059d}', 66934), + ('\u{1059e}', 66935), ('\u{1059f}', 66936), ('\u{105a0}', 66937), ('\u{105a1}', 66938), + ('\u{105a3}', 66940), ('\u{105a4}', 66941), ('\u{105a5}', 66942), ('\u{105a6}', 66943), + ('\u{105a7}', 66944), ('\u{105a8}', 66945), ('\u{105a9}', 66946), ('\u{105aa}', 66947), + ('\u{105ab}', 66948), ('\u{105ac}', 66949), ('\u{105ad}', 66950), ('\u{105ae}', 66951), + ('\u{105af}', 66952), ('\u{105b0}', 66953), ('\u{105b1}', 66954), ('\u{105b3}', 66956), + ('\u{105b4}', 66957), ('\u{105b5}', 66958), ('\u{105b6}', 66959), ('\u{105b7}', 66960), + ('\u{105b8}', 66961), ('\u{105b9}', 66962), ('\u{105bb}', 66964), ('\u{105bc}', 66965), + ('\u{10cc0}', 68736), ('\u{10cc1}', 68737), ('\u{10cc2}', 68738), ('\u{10cc3}', 68739), + ('\u{10cc4}', 68740), ('\u{10cc5}', 68741), ('\u{10cc6}', 68742), ('\u{10cc7}', 68743), + ('\u{10cc8}', 68744), ('\u{10cc9}', 68745), ('\u{10cca}', 68746), ('\u{10ccb}', 68747), + ('\u{10ccc}', 68748), ('\u{10ccd}', 68749), ('\u{10cce}', 68750), ('\u{10ccf}', 68751), + ('\u{10cd0}', 68752), ('\u{10cd1}', 68753), ('\u{10cd2}', 68754), ('\u{10cd3}', 68755), + ('\u{10cd4}', 68756), ('\u{10cd5}', 68757), ('\u{10cd6}', 68758), ('\u{10cd7}', 68759), + ('\u{10cd8}', 68760), ('\u{10cd9}', 68761), ('\u{10cda}', 68762), ('\u{10cdb}', 68763), + ('\u{10cdc}', 68764), ('\u{10cdd}', 68765), ('\u{10cde}', 68766), ('\u{10cdf}', 68767), + ('\u{10ce0}', 68768), ('\u{10ce1}', 68769), ('\u{10ce2}', 68770), ('\u{10ce3}', 68771), + ('\u{10ce4}', 68772), ('\u{10ce5}', 68773), ('\u{10ce6}', 68774), ('\u{10ce7}', 68775), + ('\u{10ce8}', 68776), ('\u{10ce9}', 68777), ('\u{10cea}', 68778), ('\u{10ceb}', 68779), + ('\u{10cec}', 68780), ('\u{10ced}', 68781), ('\u{10cee}', 68782), ('\u{10cef}', 68783), + ('\u{10cf0}', 68784), ('\u{10cf1}', 68785), ('\u{10cf2}', 68786), ('\u{10d70}', 68944), + ('\u{10d71}', 68945), ('\u{10d72}', 68946), ('\u{10d73}', 68947), ('\u{10d74}', 68948), + ('\u{10d75}', 68949), ('\u{10d76}', 68950), ('\u{10d77}', 68951), ('\u{10d78}', 68952), + ('\u{10d79}', 68953), ('\u{10d7a}', 68954), ('\u{10d7b}', 68955), ('\u{10d7c}', 68956), + ('\u{10d7d}', 68957), ('\u{10d7e}', 68958), ('\u{10d7f}', 68959), ('\u{10d80}', 68960), + ('\u{10d81}', 68961), ('\u{10d82}', 68962), ('\u{10d83}', 68963), ('\u{10d84}', 68964), + ('\u{10d85}', 68965), ('\u{118c0}', 71840), ('\u{118c1}', 71841), ('\u{118c2}', 71842), + ('\u{118c3}', 71843), ('\u{118c4}', 71844), ('\u{118c5}', 71845), ('\u{118c6}', 71846), + ('\u{118c7}', 71847), ('\u{118c8}', 71848), ('\u{118c9}', 71849), ('\u{118ca}', 71850), + ('\u{118cb}', 71851), ('\u{118cc}', 71852), ('\u{118cd}', 71853), ('\u{118ce}', 71854), + ('\u{118cf}', 71855), ('\u{118d0}', 71856), ('\u{118d1}', 71857), ('\u{118d2}', 71858), + ('\u{118d3}', 71859), ('\u{118d4}', 71860), ('\u{118d5}', 71861), ('\u{118d6}', 71862), + ('\u{118d7}', 71863), ('\u{118d8}', 71864), ('\u{118d9}', 71865), ('\u{118da}', 71866), + ('\u{118db}', 71867), ('\u{118dc}', 71868), ('\u{118dd}', 71869), ('\u{118de}', 71870), + ('\u{118df}', 71871), ('\u{16e60}', 93760), ('\u{16e61}', 93761), ('\u{16e62}', 93762), + ('\u{16e63}', 93763), ('\u{16e64}', 93764), ('\u{16e65}', 93765), ('\u{16e66}', 93766), + ('\u{16e67}', 93767), ('\u{16e68}', 93768), ('\u{16e69}', 93769), ('\u{16e6a}', 93770), + ('\u{16e6b}', 93771), ('\u{16e6c}', 93772), ('\u{16e6d}', 93773), ('\u{16e6e}', 93774), + ('\u{16e6f}', 93775), ('\u{16e70}', 93776), ('\u{16e71}', 93777), ('\u{16e72}', 93778), + ('\u{16e73}', 93779), ('\u{16e74}', 93780), ('\u{16e75}', 93781), ('\u{16e76}', 93782), + ('\u{16e77}', 93783), ('\u{16e78}', 93784), ('\u{16e79}', 93785), ('\u{16e7a}', 93786), + ('\u{16e7b}', 93787), ('\u{16e7c}', 93788), ('\u{16e7d}', 93789), ('\u{16e7e}', 93790), + ('\u{16e7f}', 93791), ('\u{1e922}', 125184), ('\u{1e923}', 125185), ('\u{1e924}', 125186), + ('\u{1e925}', 125187), ('\u{1e926}', 125188), ('\u{1e927}', 125189), ('\u{1e928}', 125190), + ('\u{1e929}', 125191), ('\u{1e92a}', 125192), ('\u{1e92b}', 125193), ('\u{1e92c}', 125194), + ('\u{1e92d}', 125195), ('\u{1e92e}', 125196), ('\u{1e92f}', 125197), ('\u{1e930}', 125198), + ('\u{1e931}', 125199), ('\u{1e932}', 125200), ('\u{1e933}', 125201), ('\u{1e934}', 125202), + ('\u{1e935}', 125203), ('\u{1e936}', 125204), ('\u{1e937}', 125205), ('\u{1e938}', 125206), + ('\u{1e939}', 125207), ('\u{1e93a}', 125208), ('\u{1e93b}', 125209), ('\u{1e93c}', 125210), + ('\u{1e93d}', 125211), ('\u{1e93e}', 125212), ('\u{1e93f}', 125213), ('\u{1e940}', 125214), + ('\u{1e941}', 125215), ('\u{1e942}', 125216), ('\u{1e943}', 125217), ]; static UPPERCASE_TABLE_MULTI: &[[char; 3]] = &[ diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 0d1c72a689291..2bdaeb3845a72 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -228,6 +228,8 @@ fn static_init() { } #[test] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#[cfg_attr(not(bootstrap), allow(static_mut_refs))] fn atomic_access_bool() { static mut ATOMIC: AtomicBool = AtomicBool::new(false); diff --git a/library/core/tests/error.rs b/library/core/tests/error.rs index 5e20c34ca6ced..996566d3848bd 100644 --- a/library/core/tests/error.rs +++ b/library/core/tests/error.rs @@ -1,4 +1,4 @@ -use core::error::{request_ref, request_value, Request}; +use core::error::{Request, request_ref, request_value}; // Test the `Request` API. #[derive(Debug)] diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs index 93aca72d59082..ebfe5a0a66dc5 100644 --- a/library/core/tests/future.rs +++ b/library/core/tests/future.rs @@ -1,4 +1,4 @@ -use std::future::{join, Future}; +use std::future::{Future, join}; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll, Wake}; diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs index bdd1c2579ded8..03826fc4c92cd 100644 --- a/library/core/tests/hash/mod.rs +++ b/library/core/tests/hash/mod.rs @@ -16,11 +16,8 @@ impl Default for MyHasher { impl Hasher for MyHasher { fn write(&mut self, buf: &[u8]) { - // FIXME(const_trait_impl): change to for loop - let mut i = 0; - while i < buf.len() { - self.hash += buf[i] as u64; - i += 1; + for byte in buf { + self.hash += *byte as u64; } } fn write_str(&mut self, s: &str) { diff --git a/library/core/tests/iter/adapters/map_windows.rs b/library/core/tests/iter/adapters/map_windows.rs index 01cebc9b27fd8..b677f1cfd55e7 100644 --- a/library/core/tests/iter/adapters/map_windows.rs +++ b/library/core/tests/iter/adapters/map_windows.rs @@ -159,10 +159,11 @@ fn output_n2() { >::new(), ); assert_eq!("ab".chars().map_windows(|a: &[_; 2]| *a).collect::>(), vec![['a', 'b']]); - assert_eq!( - "abcd".chars().map_windows(|a: &[_; 2]| *a).collect::>(), - vec![['a', 'b'], ['b', 'c'], ['c', 'd']], - ); + assert_eq!("abcd".chars().map_windows(|a: &[_; 2]| *a).collect::>(), vec![ + ['a', 'b'], + ['b', 'c'], + ['c', 'd'] + ],); } #[test] diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs index 94b49bac45337..70392dca0fa17 100644 --- a/library/core/tests/iter/adapters/zip.rs +++ b/library/core/tests/iter/adapters/zip.rs @@ -240,7 +240,7 @@ fn test_zip_trusted_random_access_composition() { #[test] #[cfg(panic = "unwind")] fn test_zip_trusted_random_access_next_back_drop() { - use std::panic::{catch_unwind, AssertUnwindSafe}; + use std::panic::{AssertUnwindSafe, catch_unwind}; let mut counter = 0; diff --git a/library/core/tests/iter/sources.rs b/library/core/tests/iter/sources.rs index eb8c80dd08724..506febaa056a8 100644 --- a/library/core/tests/iter/sources.rs +++ b/library/core/tests/iter/sources.rs @@ -156,3 +156,27 @@ fn test_repeat_n_drop() { drop((x0, x1, x2)); assert_eq!(count.get(), 3); } + +#[test] +fn test_repeat_n_soundness() { + let x = std::iter::repeat_n(String::from("use after free"), 0); + println!("{x:?}"); + + pub struct PanicOnClone; + + impl Clone for PanicOnClone { + fn clone(&self) -> Self { + unreachable!() + } + } + + // `repeat_n` should drop the element immediately if `count` is zero. + // `Clone` should then not try to clone the element. + let x = std::iter::repeat_n(PanicOnClone, 0); + let _ = x.clone(); + + let mut y = std::iter::repeat_n(Box::new(0), 1); + let x = y.next().unwrap(); + let _z = y; + assert_eq!(0, *x); +} diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs index a3b89f15b3f81..711511eaf4a5a 100644 --- a/library/core/tests/lazy.rs +++ b/library/core/tests/lazy.rs @@ -113,6 +113,27 @@ fn lazy_type_inference() { let _ = LazyCell::new(|| ()); } +#[test] +#[should_panic = "LazyCell instance has previously been poisoned"] +fn lazy_force_mut_panic() { + let mut lazy = LazyCell::::new(|| panic!()); + std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + let _ = LazyCell::force_mut(&mut lazy); + })) + .unwrap_err(); + let _ = &*lazy; +} + +#[test] +fn lazy_force_mut() { + let s = "abc".to_owned(); + let mut lazy = LazyCell::new(move || s); + LazyCell::force_mut(&mut lazy); + let p = LazyCell::force_mut(&mut lazy); + p.clear(); + LazyCell::force_mut(&mut lazy); +} + #[test] fn aliasing_in_get() { let x = OnceCell::new(); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c205f028dd3a7..604c0d4874362 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(offset_of_nested))] +#![cfg_attr(bootstrap, feature(const_mut_refs))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(alloc_layout_extra)] @@ -21,13 +21,10 @@ #![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] -#![feature(const_intrinsic_copy)] #![feature(const_ip)] #![feature(const_ipv4)] #![feature(const_ipv6)] #![feature(const_likely)] -#![feature(const_maybe_uninit_as_mut_ptr)] -#![feature(const_mut_refs)] #![feature(const_nonnull_new)] #![feature(const_option)] #![feature(const_option_ext)] @@ -77,6 +74,7 @@ #![feature(iterator_try_collect)] #![feature(iterator_try_reduce)] #![feature(layout_for_ptr)] +#![feature(lazy_get)] #![feature(maybe_uninit_fill)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(maybe_uninit_write_slice)] @@ -112,7 +110,6 @@ #![feature(unsize)] #![feature(unsized_tuple_coercion)] #![feature(unwrap_infallible)] -#![feature(waker_getters)] // tidy-alphabetical-end #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index b7eee10ec3f9c..f3b4387f6a898 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -773,15 +773,20 @@ fn offset_of_addr() { #[test] fn const_maybe_uninit_zeroed() { // Sanity check for `MaybeUninit::zeroed` in a realistic const situation (plugin array term) + + // It is crucial that this type has no padding! #[repr(C)] struct Foo { - a: Option<&'static str>, + a: Option<&'static u8>, b: Bar, c: f32, + _pad: u32, d: *const u8, } + #[repr(C)] struct Bar(usize); + struct FooPtr(*const Foo); unsafe impl Sync for FooPtr {} diff --git a/library/core/tests/num/bignum.rs b/library/core/tests/num/bignum.rs index 416e7cea7a67b..f213fd5366cbf 100644 --- a/library/core/tests/num/bignum.rs +++ b/library/core/tests/num/bignum.rs @@ -1,5 +1,5 @@ -use core::num::bignum::tests::Big8x3 as Big; use core::num::bignum::Big32x40; +use core::num::bignum::tests::Big8x3 as Big; #[test] #[should_panic] diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs index 070a53edc2e0f..3d82522481316 100644 --- a/library/core/tests/num/flt2dec/mod.rs +++ b/library/core/tests/num/flt2dec/mod.rs @@ -1,6 +1,6 @@ use core::num::flt2dec::{ - decode, round_up, to_exact_exp_str, to_exact_fixed_str, to_shortest_exp_str, to_shortest_str, - DecodableFloat, Decoded, FullDecoded, Sign, MAX_SIG_DIGITS, + DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, Sign, decode, round_up, to_exact_exp_str, + to_exact_fixed_str, to_shortest_exp_str, to_shortest_str, }; use core::num::fmt::{Formatted, Part}; use std::mem::MaybeUninit; diff --git a/library/core/tests/num/flt2dec/random.rs b/library/core/tests/num/flt2dec/random.rs index 4817a66638391..99fc23af7ea9d 100644 --- a/library/core/tests/num/flt2dec/random.rs +++ b/library/core/tests/num/flt2dec/random.rs @@ -1,7 +1,7 @@ #![cfg(not(target_arch = "wasm32"))] use core::num::flt2dec::strategy::grisu::{format_exact_opt, format_shortest_opt}; -use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS}; +use core::num::flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; use std::mem::MaybeUninit; use std::str; diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 830a96204ca03..6a26bd15a663d 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -244,6 +244,8 @@ macro_rules! int_module { assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>); assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>); + assert_eq!($T::from_str_radix("10_0", 10).ok(), None::<$T>); + assert_eq!(u32::from_str_radix("-9", 10).ok(), None::); } #[test] diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index b14fe0b22c311..6da9b9a13293a 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -1,5 +1,5 @@ use core::fmt::Debug; -use core::num::{can_not_overflow, IntErrorKind, ParseIntError, TryFromIntError}; +use core::num::{IntErrorKind, ParseIntError, TryFromIntError, can_not_overflow}; use core::ops::{Add, Div, Mul, Rem, Sub}; use core::str::FromStr; diff --git a/library/core/tests/pin_macro.rs b/library/core/tests/pin_macro.rs index 36c6972515a96..43542397a6136 100644 --- a/library/core/tests/pin_macro.rs +++ b/library/core/tests/pin_macro.rs @@ -2,7 +2,7 @@ use core::marker::PhantomPinned; use core::mem::{drop as stuff, transmute}; -use core::pin::{pin, Pin}; +use core::pin::{Pin, pin}; #[test] fn basic() { diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index cdefb5d3eb201..7197f3812e542 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1857,8 +1857,8 @@ fn sort_unstable() { fn select_nth_unstable() { use core::cmp::Ordering::{Equal, Greater, Less}; - use rand::seq::SliceRandom; use rand::Rng; + use rand::seq::SliceRandom; let mut rng = crate::test_rng(); diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs index 361e900e69562..4889b8959ece4 100644 --- a/library/core/tests/waker.rs +++ b/library/core/tests/waker.rs @@ -4,14 +4,13 @@ use std::task::{RawWaker, RawWakerVTable, Waker}; #[test] fn test_waker_getters() { let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE); - assert_eq!(raw_waker.data() as usize, 42); - assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE)); - let waker = unsafe { Waker::from_raw(raw_waker) }; + assert_eq!(waker.data() as usize, 42); + assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE)); + let waker2 = waker.clone(); - let raw_waker2 = waker2.as_raw(); - assert_eq!(raw_waker2.data() as usize, 43); - assert!(ptr::eq(raw_waker2.vtable(), &WAKER_VTABLE)); + assert_eq!(waker2.data() as usize, 43); + assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE)); } static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( @@ -23,7 +22,7 @@ static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( // https://github.com/rust-lang/rust/issues/102012#issuecomment-1915282956 mod nop_waker { - use core::future::{ready, Future}; + use core::future::{Future, ready}; use core::pin::Pin; use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index f830808d19648..6d1f9764efbfd 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -20,3 +20,10 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2", default-features = false } + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + # #[cfg(bootstrap)] rtems + 'cfg(target_os, values("rtems"))', +] diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index 86a43184fb529..b986fc1c2a829 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -78,7 +78,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { super::__rust_foreign_exception(); } - let canary = ptr::addr_of!((*adjusted_ptr).canary).read(); + let canary = (&raw const (*adjusted_ptr).canary).read(); if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) { super::__rust_foreign_exception(); } @@ -98,14 +98,11 @@ pub unsafe fn panic(data: Box) -> u32 { if exception.is_null() { return uw::_URC_FATAL_PHASE1_ERROR as u32; } - ptr::write( - exception, - Exception { - canary: &EXCEPTION_TYPE_INFO, - 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); } diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 589d3c1b4d2d0..89b44338d6b46 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -61,7 +61,7 @@ struct Exception { pub unsafe fn panic(data: Box) -> u32 { let exception = Box::new(Exception { _uwe: uw::_Unwind_Exception { - exception_class: rust_exception_class(), + exception_class: RUST_EXCEPTION_CLASS, exception_cleanup: Some(exception_cleanup), private: [core::ptr::null(); uw::unwinder_private_data_size], }, @@ -84,7 +84,7 @@ pub unsafe fn panic(data: Box) -> u32 { pub unsafe fn cleanup(ptr: *mut u8) -> Box { let exception = ptr as *mut uw::_Unwind_Exception; - if (*exception).exception_class != rust_exception_class() { + if (*exception).exception_class != RUST_EXCEPTION_CLASS { uw::_Unwind_DeleteException(exception); super::__rust_foreign_exception(); } @@ -92,7 +92,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { let exception = exception.cast::(); // Just access the canary field, avoid accessing the entire `Exception` as // it can be a foreign Rust exception. - let canary = ptr::addr_of!((*exception).canary).read(); + let canary = (&raw const (*exception).canary).read(); if !ptr::eq(canary, &CANARY) { // A foreign Rust exception, treat it slightly differently from other // foreign exceptions, because call into `_Unwind_DeleteException` will @@ -107,7 +107,4 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { // Rust's exception class identifier. This is used by personality routines to // determine whether the exception was thrown by their own runtime. -fn rust_exception_class() -> uw::_Unwind_Exception_Class { - // M O Z \0 R U S T -- vendor, language - 0x4d4f5a_00_52555354 -} +const RUST_EXCEPTION_CLASS: uw::_Unwind_Exception_Class = u64::from_be_bytes(*b"MOZ\0RUST"); diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 2d174f4b1a4a2..6cd4dffb8aa30 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -48,7 +48,7 @@ cfg_if::cfg_if! { target_os = "psp", target_os = "xous", target_os = "solid_asp3", - all(target_family = "unix", not(target_os = "espidf")), + all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems", target_os = "nuttx"))), all(target_vendor = "fortanix", target_env = "sgx"), target_family = "wasm", ))] { diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 82c248c5a7ba1..565a2b8c573b4 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -50,7 +50,6 @@ use alloc::boxed::Box; use core::any::Any; use core::ffi::{c_int, c_uint, c_void}; use core::mem::{self, ManuallyDrop}; -use core::ptr::{addr_of, addr_of_mut}; // NOTE(nbdd0121): The `canary` field is part of stable ABI. #[repr(C)] @@ -131,8 +130,6 @@ mod imp { #[cfg(not(target_arch = "x86"))] mod imp { - use core::ptr::addr_of; - // On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`. #[repr(transparent)] #[derive(Copy, Clone)] @@ -157,10 +154,7 @@ mod imp { // going to be cross-lang LTOed anyway. However, using expose is shorter and // requires less unsafe. let addr: usize = ptr.expose_provenance(); - #[cfg(bootstrap)] - let image_base = unsafe { addr_of!(__ImageBase) }.addr(); - #[cfg(not(bootstrap))] - let image_base = addr_of!(__ImageBase).addr(); + let image_base = (&raw const __ImageBase).addr(); let offset: usize = addr - image_base; Self(offset as u32) } @@ -253,10 +247,7 @@ extern "C" { // This is fine since the MSVC runtime uses string comparison on the type name // to match TypeDescriptors rather than pointer equality. static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { - #[cfg(bootstrap)] - pVFTable: unsafe { addr_of!(TYPE_INFO_VTABLE) } as *const _, - #[cfg(not(bootstrap))] - pVFTable: addr_of!(TYPE_INFO_VTABLE) as *const _, + pVFTable: (&raw const TYPE_INFO_VTABLE) as *const _, spare: core::ptr::null_mut(), name: TYPE_NAME, }; @@ -297,6 +288,8 @@ cfg_if::cfg_if! { } } +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#[allow(static_mut_refs)] pub unsafe fn panic(data: Box) -> u32 { use core::intrinsics::atomic_store_seqcst; @@ -308,8 +301,8 @@ pub unsafe fn panic(data: Box) -> u32 { // dropped when unwinding. Instead it will be dropped by exception_cleanup // which is invoked by the C++ runtime. let mut exception = - ManuallyDrop::new(Exception { canary: addr_of!(TYPE_DESCRIPTOR), data: Some(data) }); - let throw_ptr = addr_of_mut!(exception) as *mut _; + ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data: Some(data) }); + let throw_ptr = (&raw mut exception) as *mut _; // This... may seems surprising, and justifiably so. On 32-bit MSVC the // pointers between these structure are just that, pointers. On 64-bit MSVC, @@ -332,23 +325,23 @@ pub unsafe fn panic(data: Box) -> u32 { // In any case, we basically need to do something like this until we can // express more operations in statics (and we may never be able to). atomic_store_seqcst( - addr_of_mut!(THROW_INFO.pmfnUnwind).cast(), + (&raw mut THROW_INFO.pmfnUnwind).cast(), ptr_t::new(exception_cleanup as *mut u8).raw(), ); atomic_store_seqcst( - addr_of_mut!(THROW_INFO.pCatchableTypeArray).cast(), - ptr_t::new(addr_of_mut!(CATCHABLE_TYPE_ARRAY).cast()).raw(), + (&raw mut THROW_INFO.pCatchableTypeArray).cast(), + ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), - ptr_t::new(addr_of_mut!(CATCHABLE_TYPE).cast()).raw(), + (&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), + ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE.pType).cast(), - ptr_t::new(addr_of_mut!(TYPE_DESCRIPTOR).cast()).raw(), + (&raw mut CATCHABLE_TYPE.pType).cast(), + ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE.copyFunction).cast(), + (&raw mut CATCHABLE_TYPE.copyFunction).cast(), ptr_t::new(exception_copy as *mut u8).raw(), ); @@ -356,7 +349,7 @@ pub unsafe fn panic(data: Box) -> u32 { fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; } - _CxxThrowException(throw_ptr, addr_of_mut!(THROW_INFO) as *mut _); + _CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _); } pub unsafe fn cleanup(payload: *mut u8) -> Box { @@ -366,8 +359,8 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box { super::__rust_foreign_exception(); } let exception = payload as *mut Exception; - let canary = addr_of!((*exception).canary).read(); - if !core::ptr::eq(canary, addr_of!(TYPE_DESCRIPTOR)) { + let canary = (&raw const (*exception).canary).read(); + if !core::ptr::eq(canary, &raw const TYPE_DESCRIPTOR) { // A foreign Rust exception. super::__rust_foreign_exception(); } diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs index 331b66262490c..cc6246b4a0d41 100644 --- a/library/portable-simd/crates/core_simd/src/lib.rs +++ b/library/portable-simd/crates/core_simd/src/lib.rs @@ -1,8 +1,6 @@ #![no_std] #![feature( - const_intrinsic_copy, const_refs_to_cell, - const_maybe_uninit_as_mut_ptr, const_mut_refs, convert_float_to_int, core_intrinsics, diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs index 2f4f777b20e29..d62642fb9061b 100644 --- a/library/portable-simd/crates/core_simd/src/swizzle.rs +++ b/library/portable-simd/crates/core_simd/src/swizzle.rs @@ -85,7 +85,7 @@ pub trait Swizzle { LaneCount: SupportedLaneCount, LaneCount: SupportedLaneCount, { - // Safety: `vector` is a vector, and the index is a const array of u32. + // Safety: `vector` is a vector, and the index is a const vector of u32. unsafe { core::intrinsics::simd::simd_shuffle( vector, @@ -103,7 +103,11 @@ pub trait Swizzle { output[i] = index as u32; i += 1; } - output + + // The index list needs to be returned as a vector. + #[repr(simd)] + struct SimdShuffleIdx([u32; LEN]); + SimdShuffleIdx(output) }, ) } @@ -121,7 +125,7 @@ pub trait Swizzle { LaneCount: SupportedLaneCount, LaneCount: SupportedLaneCount, { - // Safety: `first` and `second` are vectors, and the index is a const array of u32. + // Safety: `first` and `second` are vectors, and the index is a const vector of u32. unsafe { core::intrinsics::simd::simd_shuffle( first, @@ -139,7 +143,11 @@ pub trait Swizzle { output[i] = index as u32; i += 1; } - output + + // The index list needs to be returned as a vector. + #[repr(simd)] + struct SimdShuffleIdx([u32; LEN]); + SimdShuffleIdx(output) }, ) } diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index 78fcd1999b2f3..3760749d83a54 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -119,9 +119,7 @@ impl Write for Buffer { } impl Drop for Buffer { - // HACK(nbdd0121): Hack to prevent LLVM < 17.0.4 from misoptimising, - // change to `#[inline]` if fixed. - #[inline(never)] + #[inline] fn drop(&mut self) { let b = self.take(); (b.drop)(b); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 72b53c60f7439..5522d556a5975 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -54,7 +54,7 @@ use std::{error, fmt}; #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level, MultiSpan}; -use crate::escape::{escape_bytes, EscapeOptions}; +use crate::escape::{EscapeOptions, escape_bytes}; /// Determines whether proc_macro has been made accessible to the currently /// running program. @@ -371,7 +371,7 @@ impl Extend for TokenStream { /// Public implementation details for the `TokenStream` type, such as iterators. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub mod token_stream { - use crate::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; + use crate::{Group, Ident, Literal, Punct, TokenStream, TokenTree, bridge}; /// An iterator over `TokenStream`'s `TokenTree`s. /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 82cfd603a21e3..ea11586f9a519 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,12 +17,16 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.123" } +compiler_builtins = { version = "0.1.125" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = [ 'rustc-dep-of-std', ] } +# FIXME(#127890): `object` depends on `memchr`, but `memchr` > v2.5 causes +# issues with LTO. This dependency is not used directly, but pin it here so +# it resolves to 2.5. To be removed once rust-lang/rust#127890 is fixed. +memchr = { version = "=2.5.0", default-features = false, features = ["rustc-dep-of-std"] } std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = [ 'rustc-dep-of-std', ] } @@ -146,4 +150,6 @@ check-cfg = [ # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg 'cfg(feature, values(any()))', + # #[cfg(bootstrap)] rtems + 'cfg(target_os, values("rtems"))', ] diff --git a/library/std/build.rs b/library/std/build.rs index fecdf2c3e1f43..359ae4f20eea8 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -53,6 +53,8 @@ fn main() { || target_os == "uefi" || target_os == "teeos" || target_os == "zkvm" + || target_os == "rtems" + || target_os == "nuttx" // See src/bootstrap/src/core/build_steps/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() @@ -142,7 +144,7 @@ fn main() { // Configure platforms that have reliable basics but may have unreliable math. - // LLVM is currenlty adding missing routines, + // LLVM is currently adding missing routines, let has_reliable_f16_math = has_reliable_f16 && match (target_arch.as_str(), target_os.as_str()) { // FIXME: Disabled on Miri as the intrinsics are not implemented yet. diff --git a/library/std/src/ascii.rs b/library/std/src/ascii.rs index 3a2880fd50904..3813f3237fb34 100644 --- a/library/std/src/ascii.rs +++ b/library/std/src/ascii.rs @@ -16,7 +16,7 @@ #[unstable(feature = "ascii_char", issue = "110998")] pub use core::ascii::Char; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::ascii::{escape_default, EscapeDefault}; +pub use core::ascii::{EscapeDefault, escape_default}; /// Extension methods for ASCII-subset only operations. /// diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 7df9a8a14b00c..fc333d7ff3f95 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -91,9 +91,9 @@ mod tests; use crate::backtrace_rs::{self, BytesOrWideString}; use crate::ffi::c_void; use crate::panic::UnwindSafe; +use crate::sync::LazyLock; use crate::sync::atomic::AtomicU8; use crate::sync::atomic::Ordering::Relaxed; -use crate::sync::LazyLock; use crate::sys::backtrace::{lock, output_filename, set_image_base}; use crate::{env, fmt}; diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 822fa5791e300..1a18721b15e92 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1037,6 +1037,7 @@ where /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_contains_key")] pub fn contains_key(&self, k: &Q) -> bool where K: Borrow, @@ -1100,6 +1101,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push", "append", "put")] + #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_insert")] pub fn insert(&mut self, k: K, v: V) -> Option { self.base.insert(k, v) } @@ -1391,6 +1393,7 @@ where /// let iter = map.iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_iter_ty")] pub struct Iter<'a, K: 'a, V: 'a> { base: base::Iter<'a, K, V>, } @@ -1429,6 +1432,7 @@ impl fmt::Debug for Iter<'_, K, V> { /// let iter = map.iter_mut(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_iter_mut_ty")] pub struct IterMut<'a, K: 'a, V: 'a> { base: base::IterMut<'a, K, V>, } @@ -1489,6 +1493,7 @@ impl IntoIter { /// let iter_keys = map.keys(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_keys_ty")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, } @@ -1527,6 +1532,7 @@ impl fmt::Debug for Keys<'_, K, V> { /// let iter_values = map.values(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_values_ty")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, } @@ -1565,6 +1571,7 @@ impl fmt::Debug for Values<'_, K, V> { /// let iter = map.drain(); /// ``` #[stable(feature = "drain", since = "1.6.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_drain_ty")] pub struct Drain<'a, K: 'a, V: 'a> { base: base::Drain<'a, K, V>, } @@ -1622,6 +1629,7 @@ where /// let iter_values = map.values_mut(); /// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_values_mut_ty")] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } @@ -2754,7 +2762,6 @@ impl<'a, K, V> Entry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(entry_insert)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, String> = HashMap::new(); @@ -2763,7 +2770,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// assert_eq!(entry.key(), &"poneyland"); /// ``` #[inline] - #[unstable(feature = "entry_insert", issue = "65225")] + #[stable(feature = "entry_insert", since = "CURRENT_RUSTC_VERSION")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { match self { Occupied(mut entry) => { @@ -3097,7 +3104,6 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(entry_insert)] /// use std::collections::HashMap; /// use std::collections::hash_map::Entry; /// @@ -3109,7 +3115,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// assert_eq!(map["poneyland"], 37); /// ``` #[inline] - #[unstable(feature = "entry_insert", issue = "65225")] + #[stable(feature = "entry_insert", since = "CURRENT_RUSTC_VERSION")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { let base = self.base.insert_entry(value); OccupiedEntry { base } diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 6641197c3724a..c28dd7b6b5059 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -947,7 +947,7 @@ fn test_raw_entry() { mod test_extract_if { use super::*; - use crate::panic::{catch_unwind, AssertUnwindSafe}; + use crate::panic::{AssertUnwindSafe, catch_unwind}; use crate::sync::atomic::{AtomicUsize, Ordering}; trait EqSorted: Iterator { diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index d611353b0d3f2..4a113ddea3a6b 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -187,6 +187,7 @@ impl HashSet { #[inline] #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_iter")] pub fn iter(&self) -> Iter<'_, T> { Iter { base: self.base.iter() } } @@ -1270,6 +1271,7 @@ where /// let mut iter = a.iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashset_iter_ty")] pub struct Iter<'a, K: 'a> { base: base::Iter<'a, K>, } @@ -1312,6 +1314,7 @@ pub struct IntoIter { /// let mut drain = a.drain(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashset_drain_ty")] pub struct Drain<'a, K: 'a> { base: base::Drain<'a, K>, } diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs index 4e6351652721f..7aa2167e21321 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -1,8 +1,8 @@ use super::HashSet; use crate::hash::RandomState; -use crate::panic::{catch_unwind, AssertUnwindSafe}; -use crate::sync::atomic::{AtomicU32, Ordering}; +use crate::panic::{AssertUnwindSafe, catch_unwind}; use crate::sync::Arc; +use crate::sync::atomic::{AtomicU32, Ordering}; #[test] fn test_zero_capacities() { diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index 3b04412e76630..889ed3c538035 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -79,41 +79,49 @@ //! see each type's documentation, and note that the names of actual methods may //! differ from the tables below on certain collections. //! -//! Throughout the documentation, we will follow a few conventions. For all -//! operations, the collection's size is denoted by n. If another collection is -//! involved in the operation, it contains m elements. Operations which have an -//! *amortized* cost are suffixed with a `*`. Operations with an *expected* -//! cost are suffixed with a `~`. +//! Throughout the documentation, we will adhere to the following conventions +//! for operation notation: //! -//! All amortized costs are for the potential need to resize when capacity is -//! exhausted. If a resize occurs it will take *O*(*n*) time. Our collections never -//! automatically shrink, so removal operations aren't amortized. Over a -//! sufficiently large series of operations, the average cost per operation will -//! deterministically equal the given cost. +//! * The collection's size is denoted by `n`. +//! * If a second collection is involved, its size is denoted by `m`. +//! * Item indices are denoted by `i`. +//! * Operations which have an *amortized* cost are suffixed with a `*`. +//! * Operations with an *expected* cost are suffixed with a `~`. //! -//! Only [`HashMap`] has expected costs, due to the probabilistic nature of hashing. -//! It is theoretically possible, though very unlikely, for [`HashMap`] to -//! experience worse performance. +//! Calling operations that add to a collection will occasionally require a +//! collection to be resized - an extra operation that takes *O*(*n*) time. //! -//! ## Sequences +//! *Amortized* costs are calculated to account for the time cost of such resize +//! operations *over a sufficiently large series of operations*. An individual +//! operation may be slower or faster due to the sporadic nature of collection +//! resizing, however the average cost per operation will approach the amortized +//! cost. //! -//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | -//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------| -//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) | -//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) | -//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) | +//! Rust's collections never automatically shrink, so removal operations aren't +//! amortized. //! -//! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and -//! [`VecDeque`] is generally going to be faster than [`LinkedList`]. +//! [`HashMap`] uses *expected* costs. It is theoretically possible, though very +//! unlikely, for [`HashMap`] to experience significantly worse performance than +//! the expected cost. This is due to the probabilistic nature of hashing - i.e. +//! it is possible to generate a duplicate hash given some input key that will +//! requires extra computation to correct. //! -//! ## Maps +//! ## Cost of Collection Operations //! -//! For Sets, all operations have the cost of the equivalent Map operation. //! -//! | | get | insert | remove | range | append | -//! |--------------|---------------|---------------|---------------|---------------|--------------| -//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A | -//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) | +//! | | get(i) | insert(i) | remove(i) | append(Vec(m)) | split_off(i) | range | append | +//! |----------------|------------------------|-------------------------|------------------------|-------------------|------------------------|-----------------|--------------| +//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) | N/A | N/A | +//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) | N/A | N/A | +//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) | N/A | N/A | +//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A | N/A | N/A | +//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | N/A | N/A | *O*(log(*n*)) | *O*(*n*+*m*) | +//! +//! Note that where ties occur, [`Vec`] is generally going to be faster than +//! [`VecDeque`], and [`VecDeque`] is generally going to be faster than +//! [`LinkedList`]. +//! +//! For Sets, all operations have the cost of the equivalent Map operation. //! //! # Correct and Efficient Usage of Collections //! @@ -410,13 +418,13 @@ pub use alloc_crate::collections::TryReserveError; )] pub use alloc_crate::collections::TryReserveErrorKind; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::collections::{binary_heap, btree_map, btree_set}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::collections::{linked_list, vec_deque}; -#[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::collections::{BTreeMap, BTreeSet, BinaryHeap}; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::collections::{LinkedList, VecDeque}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc_crate::collections::{binary_heap, btree_map, btree_set}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc_crate::collections::{linked_list, vec_deque}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(inline)] diff --git a/library/std/src/env.rs b/library/std/src/env.rs index e06a851658c03..97a1b846a91a4 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -354,12 +354,8 @@ impl Error for VarError { /// } /// assert_eq!(env::var(key), Ok("VALUE".to_string())); /// ``` -#[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] -#[cfg_attr( - not(bootstrap), - rustc_deprecated_safe_2024( - audit_that = "the environment access only happens in single-threaded code" - ) +#[rustc_deprecated_safe_2024( + audit_that = "the environment access only happens in single-threaded code" )] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn set_var, V: AsRef>(key: K, value: V) { @@ -424,12 +420,8 @@ pub unsafe fn set_var, V: AsRef>(key: K, value: V) { /// } /// assert!(env::var(key).is_err()); /// ``` -#[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] -#[cfg_attr( - not(bootstrap), - rustc_deprecated_safe_2024( - audit_that = "the environment access only happens in single-threaded code" - ) +#[rustc_deprecated_safe_2024( + audit_that = "the environment access only happens in single-threaded code" )] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn remove_var>(key: K) { @@ -943,106 +935,147 @@ impl fmt::Debug for ArgsOs { pub mod consts { use crate::sys::env::os; - /// A string describing the architecture of the CPU that is currently - /// in use. + /// A string describing the architecture of the CPU that is currently in use. + /// An example value may be: `"x86"`, `"arm"` or `"riscv64"`. /// - /// Some possible values: + ///

Full list of possible values /// - /// - x86 - /// - x86_64 - /// - arm - /// - aarch64 - /// - loongarch64 - /// - m68k - /// - csky - /// - mips - /// - mips64 - /// - powerpc - /// - powerpc64 - /// - riscv64 - /// - s390x - /// - sparc64 + /// * `"x86"` + /// * `"x86_64"` + /// * `"arm"` + /// * `"aarch64"` + /// * `"m68k"` + /// * `"mips"` + /// * `"mips32r6"` + /// * `"mips64"` + /// * `"mips64r6"` + /// * `"csky"` + /// * `"powerpc"` + /// * `"powerpc64"` + /// * `"riscv32"` + /// * `"riscv64"` + /// * `"s390x"` + /// * `"sparc"` + /// * `"sparc64"` + /// * `"hexagon"` + /// * `"loongarch64"` + /// + ///
#[stable(feature = "env", since = "1.0.0")] pub const ARCH: &str = env!("STD_ENV_ARCH"); - /// The family of the operating system. Example value is `unix`. + /// A string describing the family of the operating system. + /// An example value may be: `"unix"`, or `"windows"`. + /// + /// This value may be an empty string if the family is unknown. + /// + ///
Full list of possible values /// - /// Some possible values: + /// * `"unix"` + /// * `"windows"` + /// * `"itron"` + /// * `"wasm"` + /// * `""` /// - /// - unix - /// - windows + ///
#[stable(feature = "env", since = "1.0.0")] pub const FAMILY: &str = os::FAMILY; /// A string describing the specific operating system in use. - /// Example value is `linux`. + /// An example value may be: `"linux"`, or `"freebsd"`. /// - /// Some possible values: + ///
Full list of possible values /// - /// - linux - /// - macos - /// - ios - /// - freebsd - /// - dragonfly - /// - netbsd - /// - openbsd - /// - solaris - /// - android - /// - windows + /// * `"linux"` + /// * `"windows"` + /// * `"macos"` + /// * `"android"` + /// * `"ios"` + /// * `"openbsd"` + /// * `"freebsd"` + /// * `"netbsd"` + /// * `"wasi"` + /// * `"hermit"` + /// * `"aix"` + /// * `"apple"` + /// * `"dragonfly"` + /// * `"emscripten"` + /// * `"espidf"` + /// * `"fortanix"` + /// * `"uefi"` + /// * `"fuchsia"` + /// * `"haiku"` + /// * `"hermit"` + /// * `"watchos"` + /// * `"visionos"` + /// * `"tvos"` + /// * `"horizon"` + /// * `"hurd"` + /// * `"illumos"` + /// * `"l4re"` + /// * `"nto"` + /// * `"redox"` + /// * `"solaris"` + /// * `"solid_asp3` + /// * `"vita"` + /// * `"vxworks"` + /// * `"xous"` + /// + ///
#[stable(feature = "env", since = "1.0.0")] pub const OS: &str = os::OS; - /// Specifies the filename prefix used for shared libraries on this - /// platform. Example value is `lib`. - /// - /// Some possible values: - /// - /// - lib - /// - `""` (an empty string) + /// Specifies the filename prefix, if any, used for shared libraries on this platform. + /// This is either `"lib"` or an empty string. (`""`). #[stable(feature = "env", since = "1.0.0")] pub const DLL_PREFIX: &str = os::DLL_PREFIX; - /// Specifies the filename suffix used for shared libraries on this - /// platform. Example value is `.so`. - /// - /// Some possible values: + /// Specifies the filename suffix, if any, used for shared libraries on this platform. + /// An example value may be: `".so"`, `".elf"`, or `".dll"`. /// - /// - .so - /// - .dylib - /// - .dll + /// The possible values are identical to those of [`DLL_EXTENSION`], but with the leading period included. #[stable(feature = "env", since = "1.0.0")] pub const DLL_SUFFIX: &str = os::DLL_SUFFIX; - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot. Example value is `so`. + /// Specifies the file extension, if any, used for shared libraries on this platform that goes after the dot. + /// An example value may be: `"so"`, `"elf"`, or `"dll"`. + /// + ///
Full list of possible values /// - /// Some possible values: + /// * `"so"` + /// * `"dylib"` + /// * `"dll"` + /// * `"sgxs"` + /// * `"a"` + /// * `"elf"` + /// * `"wasm"` + /// * `""` (an empty string) /// - /// - so - /// - dylib - /// - dll + ///
#[stable(feature = "env", since = "1.0.0")] pub const DLL_EXTENSION: &str = os::DLL_EXTENSION; - /// Specifies the filename suffix used for executable binaries on this - /// platform. Example value is `.exe`. + /// Specifies the filename suffix, if any, used for executable binaries on this platform. + /// An example value may be: `".exe"`, or `".efi"`. /// - /// Some possible values: - /// - /// - .exe - /// - .nexe - /// - .pexe - /// - `""` (an empty string) + /// The possible values are identical to those of [`EXE_EXTENSION`], but with the leading period included. #[stable(feature = "env", since = "1.0.0")] pub const EXE_SUFFIX: &str = os::EXE_SUFFIX; - /// Specifies the file extension, if any, used for executable binaries - /// on this platform. Example value is `exe`. + /// Specifies the file extension, if any, used for executable binaries on this platform. + /// An example value may be: `"exe"`, or an empty string (`""`). + /// + ///
Full list of possible values /// - /// Some possible values: + /// * `"exe"` + /// * `"efi"` + /// * `"js"` + /// * `"sgxs"` + /// * `"elf"` + /// * `"wasm"` + /// * `""` (an empty string) /// - /// - exe - /// - `""` (an empty string) + ///
#[stable(feature = "env", since = "1.0.0")] pub const EXE_EXTENSION: &str = os::EXE_EXTENSION; } diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 3e17431af45b0..b3e63aaf1c567 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -7,7 +7,7 @@ mod tests; #[stable(feature = "rust1", since = "1.0.0")] pub use core::error::Error; #[unstable(feature = "error_generic_member_access", issue = "99301")] -pub use core::error::{request_ref, request_value, Request}; +pub use core::error::{Request, request_ref, request_value}; use crate::backtrace::Backtrace; use crate::fmt::{self, Write}; diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index cafbe9761da19..fa0b3ef6484f7 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -18,8 +18,8 @@ mod tests; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::f32::{ - consts, DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP, - MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX, + DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP, MIN_EXP, + MIN_POSITIVE, NAN, NEG_INFINITY, RADIX, consts, }; #[cfg(not(test))] diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index 3a4c1c120a495..99cfcfb231dad 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -2,31 +2,24 @@ use crate::f32::consts; use crate::num::{FpCategory as Fp, *}; /// Smallest number -#[allow(dead_code)] // unused on x86 const TINY_BITS: u32 = 0x1; /// Next smallest number -#[allow(dead_code)] // unused on x86 const TINY_UP_BITS: u32 = 0x2; /// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -#[allow(dead_code)] // unused on x86 const MAX_DOWN_BITS: u32 = 0x7f7f_fffe; /// Zeroed exponent, full significant -#[allow(dead_code)] // unused on x86 const LARGEST_SUBNORMAL_BITS: u32 = 0x007f_ffff; /// Exponent = 0b1, zeroed significand -#[allow(dead_code)] // unused on x86 const SMALLEST_NORMAL_BITS: u32 = 0x0080_0000; /// First pattern over the mantissa -#[allow(dead_code)] // unused on x86 const NAN_MASK1: u32 = 0x002a_aaaa; /// Second pattern over the mantissa -#[allow(dead_code)] // unused on x86 const NAN_MASK2: u32 = 0x0055_5555; #[allow(unused_macros)] @@ -353,9 +346,6 @@ fn test_is_sign_negative() { assert!((-f32::NAN).is_sign_negative()); } -// Ignore test on x87 floating point, these platforms do not guarantee NaN -// payloads are preserved and flush denormals to zero, failing the tests. -#[cfg(not(target_arch = "x86"))] #[test] fn test_next_up() { let tiny = f32::from_bits(TINY_BITS); @@ -386,9 +376,6 @@ fn test_next_up() { assert_f32_biteq!(nan2.next_up(), nan2); } -// Ignore test on x87 floating point, these platforms do not guarantee NaN -// payloads are preserved and flush denormals to zero, failing the tests. -#[cfg(not(target_arch = "x86"))] #[test] fn test_next_down() { let tiny = f32::from_bits(TINY_BITS); diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index fba283e3a44bc..9fa43a6742ea6 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -18,8 +18,8 @@ mod tests; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::f64::{ - consts, DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP, - MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX, + DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP, MIN_EXP, + MIN_POSITIVE, NAN, NEG_INFINITY, RADIX, consts, }; #[cfg(not(test))] diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index bac8405f97361..3fac2efe0d76c 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -2,31 +2,24 @@ use crate::f64::consts; use crate::num::{FpCategory as Fp, *}; /// Smallest number -#[allow(dead_code)] // unused on x86 const TINY_BITS: u64 = 0x1; /// Next smallest number -#[allow(dead_code)] // unused on x86 const TINY_UP_BITS: u64 = 0x2; /// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -#[allow(dead_code)] // unused on x86 const MAX_DOWN_BITS: u64 = 0x7fef_ffff_ffff_fffe; /// Zeroed exponent, full significant -#[allow(dead_code)] // unused on x86 const LARGEST_SUBNORMAL_BITS: u64 = 0x000f_ffff_ffff_ffff; /// Exponent = 0b1, zeroed significand -#[allow(dead_code)] // unused on x86 const SMALLEST_NORMAL_BITS: u64 = 0x0010_0000_0000_0000; /// First pattern over the mantissa -#[allow(dead_code)] // unused on x86 const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa -#[allow(dead_code)] // unused on x86 const NAN_MASK2: u64 = 0x0005_5555_5555_5555; #[allow(unused_macros)] @@ -343,9 +336,6 @@ fn test_is_sign_negative() { assert!((-f64::NAN).is_sign_negative()); } -// Ignore test on x87 floating point, these platforms do not guarantee NaN -// payloads are preserved and flush denormals to zero, failing the tests. -#[cfg(not(target_arch = "x86"))] #[test] fn test_next_up() { let tiny = f64::from_bits(TINY_BITS); @@ -375,9 +365,6 @@ fn test_next_up() { assert_f64_biteq!(nan2.next_up(), nan2); } -// Ignore test on x87 floating point, these platforms do not guarantee NaN -// payloads are preserved and flush denormals to zero, failing the tests. -#[cfg(not(target_arch = "x86"))] #[test] fn test_next_down() { let tiny = f64::from_bits(TINY_BITS); diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 2b67750c2f0a9..469136be8838a 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -166,11 +166,6 @@ pub mod c_str; #[stable(feature = "core_c_void", since = "1.30.0")] pub use core::ffi::c_void; -#[stable(feature = "core_ffi_c", since = "1.64.0")] -pub use core::ffi::{ - c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, - c_ulong, c_ulonglong, c_ushort, -}; #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ @@ -178,6 +173,11 @@ pub use core::ffi::{ issue = "44930" )] pub use core::ffi::{VaList, VaListImpl}; +#[stable(feature = "core_ffi_c", since = "1.64.0")] +pub use core::ffi::{ + c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, + c_ulong, c_ulonglong, c_ushort, +}; #[doc(no_inline)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 918eec2d0d8ef..2243f100643df 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -9,7 +9,6 @@ use crate::borrow::{Borrow, Cow}; use crate::collections::TryReserveError; use crate::hash::{Hash, Hasher}; use crate::ops::{self, Range}; -use crate::ptr::addr_of_mut; use crate::rc::Rc; use crate::str::FromStr; use crate::sync::Arc; @@ -196,6 +195,7 @@ impl OsString { /// let os_str = OsStr::new("foo"); /// assert_eq!(os_string.as_os_str(), os_str); /// ``` + #[cfg_attr(not(test), rustc_diagnostic_item = "os_string_as_os_str")] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] @@ -852,7 +852,7 @@ impl OsStr { /// Converts an `OsStr` to a [Cow]<[str]>. /// - /// Any non-Unicode sequences are replaced with + /// Any non-UTF-8 sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER @@ -918,6 +918,7 @@ impl OsStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "os_str_to_os_string")] pub fn to_os_string(&self) -> OsString { OsString { inner: self.inner.to_owned() } } @@ -1270,7 +1271,7 @@ unsafe impl CloneToUninit for OsStr { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around a platform-specific Slice - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 6a0d9f47960ec..db7867337dd59 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -375,6 +375,44 @@ impl File { OpenOptions::new().read(true).open(path.as_ref()) } + /// Attempts to open a file in read-only mode with buffering. + /// + /// See the [`OpenOptions::open`] method, the [`BufReader`][io::BufReader] type, + /// and the [`BufRead`][io::BufRead] trait for more details. + /// + /// If you only need to read the entire file contents, + /// consider [`std::fs::read()`][self::read] or + /// [`std::fs::read_to_string()`][self::read_to_string] instead. + /// + /// # Errors + /// + /// This function will return an error if `path` does not already exist. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_buffered)] + /// use std::fs::File; + /// use std::io::BufRead; + /// + /// fn main() -> std::io::Result<()> { + /// let mut f = File::open_buffered("foo.txt")?; + /// assert!(f.capacity() > 0); + /// for (line, i) in f.lines().zip(1..) { + /// println!("{i:6}: {}", line?); + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_buffered", issue = "130804")] + pub fn open_buffered>(path: P) -> io::Result> { + // Allocate the buffer *first* so we don't affect the filesystem otherwise. + let buffer = io::BufReader::::try_new_buffer()?; + let file = File::open(path)?; + Ok(io::BufReader::with_buffer(file, buffer)) + } + /// Opens a file in write-only mode. /// /// This function will create a file if it does not exist, @@ -404,6 +442,45 @@ impl File { OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()) } + /// Opens a file in write-only mode with buffering. + /// + /// This function will create a file if it does not exist, + /// and will truncate it if it does. + /// + /// Depending on the platform, this function may fail if the + /// full directory path does not exist. + /// + /// See the [`OpenOptions::open`] method and the + /// [`BufWriter`][io::BufWriter] type for more details. + /// + /// See also [`std::fs::write()`][self::write] for a simple function to + /// create a file with some given data. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_buffered)] + /// use std::fs::File; + /// use std::io::Write; + /// + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create_buffered("foo.txt")?; + /// assert!(f.capacity() > 0); + /// for i in 0..100 { + /// writeln!(&mut f, "{i}")?; + /// } + /// f.flush()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_buffered", issue = "130804")] + pub fn create_buffered>(path: P) -> io::Result> { + // Allocate the buffer *first* so we don't affect the filesystem otherwise. + let buffer = io::BufWriter::::try_new_buffer()?; + let file = File::create(path)?; + Ok(io::BufWriter::with_buffer(file, buffer)) + } + /// Creates a new file in read-write mode; error if the file exists. /// /// This function will create a file if it does not exist, or return an error if it does. This @@ -466,6 +543,7 @@ impl File { /// ``` #[must_use] #[stable(feature = "with_options", since = "1.58.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "file_options")] pub fn options() -> OpenOptions { OpenOptions::new() } @@ -835,7 +913,7 @@ impl Read for &File { } #[stable(feature = "rust1", since = "1.0.0")] impl Write for &File { - /// Writes some bytes from the file. + /// Writes some bytes to the file. /// /// See [`Write::write`] docs for more info. /// @@ -1009,6 +1087,7 @@ impl OpenOptions { /// let mut options = OpenOptions::new(); /// let file = options.read(true).open("foo.txt"); /// ``` + #[cfg_attr(not(test), rustc_diagnostic_item = "open_options_new")] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub fn new() -> Self { @@ -1989,6 +2068,11 @@ impl AsInner for DirEntry { /// * The file doesn't exist. /// * The user lacks permissions to remove the file. /// +/// This function will only ever return an error of kind `NotFound` if the given +/// path does not exist. Note that the inverse is not true, +/// ie. if a path does not exist, its removal may fail for a number of reasons, +/// such as insufficient permissions. +/// /// # Examples /// /// ```no_run @@ -2446,6 +2530,11 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// * The user lacks permissions to remove the directory at the provided `path`. /// * The directory isn't empty. /// +/// This function will only ever return an error of kind `NotFound` if the given +/// path does not exist. Note that the inverse is not true, +/// ie. if a path does not exist, its removal may fail for a number of reasons, +/// such as insufficient permissions. +/// /// # Examples /// /// ```no_run @@ -2471,16 +2560,15 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// # Platform-specific behavior /// /// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions -/// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`, -/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile` functions on -/// Windows. Note that, this [may change in the future][changes]. +/// on Unix (except for REDOX) and the `CreateFileW`, `GetFileInformationByHandleEx`, +/// `SetFileInformationByHandle`, and `NtCreateFile` functions on Windows. Note that, this +/// [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior /// -/// On macOS before version 10.10 and REDOX, as well as when running in Miri for any target, this -/// function is not protected against time-of-check to time-of-use (TOCTOU) race conditions, and -/// should not be used in security-sensitive code on those platforms. All other platforms are -/// protected. +/// On REDOX, as well as when running in Miri for any target, this function is not protected against +/// time-of-check to time-of-use (TOCTOU) race conditions, and should not be used in +/// security-sensitive code on those platforms. All other platforms are protected. /// /// # Errors /// diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 13028c4c3b57e..0672fe6f7718a 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,7 +1,5 @@ use rand::RngCore; -#[cfg(target_os = "macos")] -use crate::ffi::{c_char, c_int}; use crate::fs::{self, File, FileTimes, OpenOptions}; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; @@ -13,12 +11,10 @@ use crate::os::unix::fs::symlink as symlink_file; #[cfg(unix)] use crate::os::unix::fs::symlink as junction_point; #[cfg(windows)] -use crate::os::windows::fs::{junction_point, symlink_dir, symlink_file, OpenOptionsExt}; +use crate::os::windows::fs::{OpenOptionsExt, junction_point, symlink_dir, symlink_file}; use crate::path::Path; use crate::sync::Arc; -#[cfg(target_os = "macos")] -use crate::sys::weak::weak; -use crate::sys_common::io::test::{tmpdir, TempDir}; +use crate::sys_common::io::test::{TempDir, tmpdir}; use crate::time::{Duration, Instant, SystemTime}; use crate::{env, str, thread}; @@ -80,17 +76,6 @@ pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { } } -#[cfg(target_os = "macos")] -fn able_to_not_follow_symlinks_while_hard_linking() -> bool { - weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int); - linkat.get().is_some() -} - -#[cfg(not(target_os = "macos"))] -fn able_to_not_follow_symlinks_while_hard_linking() -> bool { - return true; -} - #[test] fn file_test_io_smoke_test() { let message = "it's alright. have a good time"; @@ -1456,9 +1441,6 @@ fn symlink_hard_link() { if !got_symlink_permission(&tmpdir) { return; }; - if !able_to_not_follow_symlinks_while_hard_linking() { - return; - } // Create "file", a file. check!(fs::File::create(tmpdir.join("file"))); @@ -1750,7 +1732,7 @@ fn windows_unix_socket_exists() { let bytes = core::slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()); addr.sun_path[..bytes.len()].copy_from_slice(bytes); let len = mem::size_of_val(&addr) as i32; - let result = c::bind(socket, ptr::addr_of!(addr).cast::(), len); + let result = c::bind(socket, (&raw const addr).cast::(), len); c::closesocket(socket); assert_eq!(result, 0); } diff --git a/library/std/src/hash/random.rs b/library/std/src/hash/random.rs index 8ef45172eac40..40f3a90f60c8a 100644 --- a/library/std/src/hash/random.rs +++ b/library/std/src/hash/random.rs @@ -10,7 +10,8 @@ #[allow(deprecated)] use super::{BuildHasher, Hasher, SipHasher13}; use crate::cell::Cell; -use crate::{fmt, sys}; +use crate::fmt; +use crate::sys::random::hashmap_random_keys; /// `RandomState` is the default state for [`HashMap`] types. /// @@ -65,7 +66,7 @@ impl RandomState { // increment one of the seeds on every RandomState creation, giving // every corresponding HashMap a different iteration order. thread_local!(static KEYS: Cell<(u64, u64)> = { - Cell::new(sys::hashmap_random_keys()) + Cell::new(hashmap_random_keys()) }); KEYS.with(|keys| { diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index cf226bd28d005..fcb3e36027bab 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -4,8 +4,8 @@ use buffer::Buffer; use crate::fmt; use crate::io::{ - self, uninlined_slow_read_byte, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, - SizeHint, SpecReadByte, DEFAULT_BUF_SIZE, + self, BorrowedCursor, BufRead, DEFAULT_BUF_SIZE, IoSliceMut, Read, Seek, SeekFrom, SizeHint, + SpecReadByte, uninlined_slow_read_byte, }; /// The `BufReader` struct adds buffering to any reader. @@ -74,6 +74,14 @@ impl BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } + pub(crate) fn try_new_buffer() -> io::Result { + Buffer::try_with_capacity(DEFAULT_BUF_SIZE) + } + + pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self { + Self { inner, buf } + } + /// Creates a new `BufReader` with the specified buffer capacity. /// /// # Examples @@ -99,7 +107,10 @@ impl BufReader { impl BufReader { /// Attempt to look ahead `n` bytes. /// - /// `n` must be less than `capacity`. + /// `n` must be less than or equal to `capacity`. + /// + /// the returned slice may be less than `n` bytes long if + /// end of file is reached. /// /// ## Examples /// @@ -117,6 +128,7 @@ impl BufReader { /// let mut s = String::new(); /// rdr.read_to_string(&mut s).unwrap(); /// assert_eq!(&s, "hello"); + /// assert_eq!(rdr.peek(1).unwrap().len(), 0); /// ``` #[unstable(feature = "bufreader_peek", issue = "128405")] pub fn peek(&mut self, n: usize) -> io::Result<&[u8]> { @@ -125,7 +137,11 @@ impl BufReader { if self.buf.pos() > 0 { self.buf.backshift(); } - self.buf.read_more(&mut self.inner)?; + let new = self.buf.read_more(&mut self.inner)?; + if new == 0 { + // end of file, no more bytes to read + return Ok(&self.buf.buffer()[..]); + } debug_assert_eq!(self.buf.pos(), 0); } Ok(&self.buf.buffer()[..n]) @@ -267,6 +283,7 @@ impl BufReader { // This is only used by a test which asserts that the initialization-tracking is correct. #[cfg(test)] impl BufReader { + #[allow(missing_docs)] pub fn initialized(&self) -> usize { self.buf.initialized() } diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index ccd67fafb45b4..3df7e3971dac4 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -10,7 +10,7 @@ //! without encountering any runtime bounds checks. use crate::cmp; -use crate::io::{self, BorrowedBuf, Read}; +use crate::io::{self, BorrowedBuf, ErrorKind, Read}; use crate::mem::MaybeUninit; pub struct Buffer { @@ -36,6 +36,16 @@ impl Buffer { Self { buf, pos: 0, filled: 0, initialized: 0 } } + #[inline] + pub fn try_with_capacity(capacity: usize) -> io::Result { + match Box::try_new_uninit_slice(capacity) { + Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }), + Err(_) => { + Err(io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) + } + } + } + #[inline] pub fn buffer(&self) -> &[u8] { // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and @@ -98,7 +108,7 @@ impl Buffer { } /// Read more bytes into the buffer without discarding any of its contents - pub fn read_more(&mut self, mut reader: impl Read) -> io::Result<()> { + pub fn read_more(&mut self, mut reader: impl Read) -> io::Result { let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]); let old_init = self.initialized - self.pos; unsafe { @@ -107,7 +117,7 @@ impl Buffer { reader.read_buf(buf.unfilled())?; self.filled += buf.len(); self.initialized += buf.init_len() - old_init; - Ok(()) + Ok(buf.len()) } /// Remove bytes that have already been read from the buffer. diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 21650d467446e..c41bae2aa4e81 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -1,5 +1,5 @@ use crate::io::{ - self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE, + self, DEFAULT_BUF_SIZE, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, }; use crate::mem::{self, ManuallyDrop}; use crate::{error, fmt, ptr}; @@ -94,6 +94,16 @@ impl BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } + pub(crate) fn try_new_buffer() -> io::Result> { + Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| { + io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer") + }) + } + + pub(crate) fn with_buffer(inner: W, buf: Vec) -> Self { + Self { inner, buf, panicked: false } + } + /// Creates a new `BufWriter` with at least the specified buffer capacity. /// /// # Examples diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index d49866345cbf6..8d733325b3be7 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,4 +1,4 @@ -use super::{BorrowedBuf, BufReader, BufWriter, Read, Result, Write, DEFAULT_BUF_SIZE}; +use super::{BorrowedBuf, BufReader, BufWriter, DEFAULT_BUF_SIZE, Read, Result, Write}; use crate::alloc::Allocator; use crate::cmp; use crate::collections::VecDeque; diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs index 7e08826a7e1d8..2e0eb6cdce666 100644 --- a/library/std/src/io/copy/tests.rs +++ b/library/std/src/io/copy/tests.rs @@ -122,8 +122,8 @@ mod io_benches { use test::Bencher; use crate::fs::{File, OpenOptions}; - use crate::io::prelude::*; use crate::io::BufReader; + use crate::io::prelude::*; #[bench] fn bench_copy_buf_reader(b: &mut Bencher) { diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index e8ae1d99fbf37..f20814dd95cc1 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -223,10 +223,10 @@ pub enum ErrorKind { #[stable(feature = "rust1", since = "1.0.0")] ConnectionReset, /// The remote host is not reachable. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] HostUnreachable, /// The network containing the remote host is not reachable. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] NetworkUnreachable, /// The connection was aborted (terminated) by the remote server. #[stable(feature = "rust1", since = "1.0.0")] @@ -243,7 +243,7 @@ pub enum ErrorKind { #[stable(feature = "rust1", since = "1.0.0")] AddrNotAvailable, /// The system's networking is down. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] NetworkDown, /// The operation failed because a pipe was closed. #[stable(feature = "rust1", since = "1.0.0")] @@ -259,18 +259,18 @@ pub enum ErrorKind { /// /// For example, a filesystem path was specified where one of the intermediate directory /// components was, in fact, a plain file. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] NotADirectory, /// The filesystem object is, unexpectedly, a directory. /// /// A directory was specified when a non-directory was expected. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] IsADirectory, /// A non-empty directory was specified where an empty directory was expected. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] DirectoryNotEmpty, /// The filesystem or storage medium is read-only, but a write operation was attempted. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] ReadOnlyFilesystem, /// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links. /// @@ -285,7 +285,7 @@ pub enum ErrorKind { /// /// With some network filesystems, notably NFS, an open file (or directory) can be invalidated /// by problems with the network or server. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] StaleNetworkFileHandle, /// A parameter was incorrect. #[stable(feature = "rust1", since = "1.0.0")] @@ -319,13 +319,13 @@ pub enum ErrorKind { /// The underlying storage (typically, a filesystem) is full. /// /// This does not include out of quota errors. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] StorageFull, /// Seek on unseekable file. /// /// Seeking was attempted on an open file handle which is not suitable for seeking - for /// example, on Unix, a named pipe opened with `File::open`. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] NotSeekable, /// Filesystem quota was exceeded. #[unstable(feature = "io_error_more", issue = "86442")] @@ -335,22 +335,22 @@ pub enum ErrorKind { /// This might arise from a hard limit of the underlying filesystem or file access API, or from /// an administratively imposed resource limitation. Simple disk full, and out of quota, have /// their own errors. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] FileTooLarge, /// Resource is busy. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] ResourceBusy, /// Executable file is busy. /// /// An attempt was made to write to a file which is also in use as a running program. (Not all /// operating systems detect this situation.) - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] ExecutableFileBusy, /// Deadlock (avoided). /// /// A file locking operation would result in deadlock. This situation is typically detected, if /// at all, on a best-effort basis. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] Deadlock, /// Cross-device or cross-filesystem (hard) link or rename. #[unstable(feature = "io_error_more", issue = "86442")] @@ -358,7 +358,7 @@ pub enum ErrorKind { /// Too many (hard) links to the same filesystem object. /// /// The filesystem does not support making so many hardlinks to the same file. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] TooManyLinks, /// A filename was invalid. /// @@ -369,7 +369,7 @@ pub enum ErrorKind { /// /// When trying to run an external program, a system or process limit on the size of the /// arguments would have been exceeded. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_a_bit_more", since = "CURRENT_RUSTC_VERSION")] ArgumentListTooLong, /// This operation was interrupted. /// @@ -400,6 +400,11 @@ pub enum ErrorKind { #[stable(feature = "out_of_memory_error", since = "1.54.0")] OutOfMemory, + /// The operation was partially successful and needs to be checked + /// later on due to not blocking. + #[unstable(feature = "io_error_inprogress", issue = "130840")] + InProgress, + // "Unusual" error kinds which do not correspond simply to (sets // of) OS error codes, should be added just above this comment. // `Other` and `Uncategorized` should remain at the end: @@ -449,6 +454,7 @@ impl ErrorKind { FilesystemQuotaExceeded => "filesystem quota exceeded", HostUnreachable => "host unreachable", Interrupted => "operation interrupted", + InProgress => "in progress", InvalidData => "invalid data", InvalidFilename => "invalid filename", InvalidInput => "invalid input parameter", diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 9d3ade46bd929..80ba8455df347 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -348,6 +348,7 @@ fn kind_from_prim(ek: u32) -> Option { UnexpectedEof, Unsupported, OutOfMemory, + InProgress, Uncategorized, }) } diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index 064e2e36b7a1d..00d04984a3854 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -1,4 +1,4 @@ -use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage}; +use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_io_error}; use crate::assert_matches::assert_matches; use crate::mem::size_of; use crate::sys::decode_error_kind; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 644b294db8da1..0b57d01f27346 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -307,9 +307,9 @@ pub(crate) use error::const_io_error; pub use self::buffered::WriterPanicked; #[unstable(feature = "raw_os_error_ty", issue = "107792")] pub use self::error::RawOsError; -pub(crate) use self::stdio::attempt_print_to_stderr; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; +pub(crate) use self::stdio::attempt_print_to_stderr; #[unstable(feature = "print_internals", issue = "none")] #[doc(hidden)] pub use self::stdio::{_eprint, _print}; @@ -322,8 +322,8 @@ pub use self::{ copy::copy, cursor::Cursor, error::{Error, ErrorKind, Result}, - stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock}, - util::{empty, repeat, sink, Empty, Repeat, Sink}, + stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout}, + util::{Empty, Repeat, Sink, empty, repeat, sink}, }; use crate::mem::take; use crate::ops::{Deref, DerefMut}; @@ -398,8 +398,7 @@ where // - avoid passing large buffers to readers that always initialize the free capacity if they perform short reads (#23815, #23820) // - pass large buffers to readers that do not initialize the spare capacity. this can amortize per-call overheads // - and finally pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems -// at the same time, i.e. small reads suffer from syscall overhead, all reads incur initialization cost -// proportional to buffer size (#110650) +// at the same time, i.e. small reads suffer from syscall overhead, all reads incur costs proportional to buffer size (#110650) // pub(crate) fn default_read_to_end( r: &mut R, @@ -444,6 +443,8 @@ pub(crate) fn default_read_to_end( } } + let mut consecutive_short_reads = 0; + loop { if buf.len() == buf.capacity() && buf.capacity() == start_cap { // The buffer might be an exact fit. Let's read into a probe buffer @@ -489,6 +490,12 @@ pub(crate) fn default_read_to_end( return Ok(buf.len() - start_len); } + if bytes_read < buf_len { + consecutive_short_reads += 1; + } else { + consecutive_short_reads = 0; + } + // store how much was initialized but not filled initialized = unfilled_but_initialized; @@ -503,7 +510,10 @@ pub(crate) fn default_read_to_end( // The reader is returning short reads but it doesn't call ensure_init(). // In that case we no longer need to restrict read sizes to avoid // initialization costs. - if !was_fully_initialized { + // When reading from disk we usually don't get any short reads except at EOF. + // So we wait for at least 2 short reads before uncapping the read buffer; + // this helps with the Windows issue. + if !was_fully_initialized && consecutive_short_reads > 1 { max_read_size = usize::MAX; } @@ -2058,6 +2068,7 @@ pub trait Seek { /// It is used by the [`Seek`] trait. #[derive(Copy, PartialEq, Eq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")] pub enum SeekFrom { /// Sets the offset to the provided number of bytes. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs index f89fd27ce6c23..ea76a271d12bf 100644 --- a/library/std/src/io/stdio/tests.rs +++ b/library/std/src/io/stdio/tests.rs @@ -159,8 +159,7 @@ where assert_eq!(rx2.recv().unwrap(), Release2); // release th2 th2.join().unwrap(); th1.join().unwrap(); - assert_eq!( - *log.lock().unwrap(), - [Start1, Acquire1, Start2, Release1, Acquire2, Release2, Acquire1, Release1] - ); + assert_eq!(*log.lock().unwrap(), [ + Start1, Acquire1, Start2, Release1, Acquire2, Release2, Acquire1, Release1 + ]); } diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index bb6a53bb290f9..f551dcd401efc 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -1,7 +1,7 @@ -use super::{repeat, BorrowedBuf, Cursor, SeekFrom}; +use super::{BorrowedBuf, Cursor, SeekFrom, repeat}; use crate::cmp::{self, min}; use crate::io::{ - self, BufRead, BufReader, IoSlice, IoSliceMut, Read, Seek, Write, DEFAULT_BUF_SIZE, + self, BufRead, BufReader, DEFAULT_BUF_SIZE, IoSlice, IoSliceMut, Read, Seek, Write, }; use crate::mem::MaybeUninit; use crate::ops::Deref; @@ -738,7 +738,7 @@ fn read_buf_full_read() { #[test] // Miri does not support signalling OOM #[cfg_attr(miri, ignore)] -// 64-bit only to be sure the allocator will fail fast on an impossible to satsify size +// 64-bit only to be sure the allocator will fail fast on an impossible to satisfy size #[cfg(target_pointer_width = "64")] fn try_oom_error() { let mut v = Vec::::new(); diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs index 1dff3f3832bd7..0599a881af179 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/std/src/io/util/tests.rs @@ -1,5 +1,5 @@ use crate::io::prelude::*; -use crate::io::{empty, repeat, sink, BorrowedBuf, Empty, Repeat, SeekFrom, Sink}; +use crate::io::{BorrowedBuf, Empty, Repeat, SeekFrom, Sink, empty, repeat, sink}; use crate::mem::MaybeUninit; #[test] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 606d75668c4d5..b81e7c18abbb0 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -32,13 +32,17 @@ //! //! Once you are familiar with the contents of the standard library you may //! begin to find the verbosity of the prose distracting. At this stage in your -//! development you may want to press the `[-]` button near the top of the -//! page to collapse it into a more skimmable view. -//! -//! While you are looking at that `[-]` button also notice the `source` -//! link. Rust's API documentation comes with the source code and you are -//! encouraged to read it. The standard library source is generally high -//! quality and a peek behind the curtains is often enlightening. +//! development you may want to press the +//! +//! Summary button near the +//! top of the page to collapse it into a more skimmable view. +//! +//! While you are looking at the top of the page, also notice the +//! source link. Rust's API documentation comes with the source +//! code and you are encouraged to read it. The standard library source is +//! generally high quality and a peek behind the curtains is +//! often enlightening. //! //! # What is in the standard library documentation? //! @@ -272,7 +276,7 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))] +#![cfg_attr(bootstrap, feature(const_mut_refs))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] @@ -282,7 +286,6 @@ #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(concat_idents)] -#![feature(const_mut_refs)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] @@ -319,6 +322,7 @@ // // Library features (core): // tidy-alphabetical-start +#![feature(array_chunks)] #![feature(c_str_module)] #![feature(char_internals)] #![feature(clone_to_uninit)] @@ -338,6 +342,7 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(ip)] +#![feature(lazy_get)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_write_slice)] #![feature(panic_can_unwind)] @@ -348,6 +353,7 @@ #![feature(prelude_2024)] #![feature(ptr_as_uninit)] #![feature(ptr_mask)] +#![feature(random)] #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(slice_range)] @@ -368,6 +374,7 @@ #![feature(slice_concat_trait)] #![feature(thin_box)] #![feature(try_reserve_kind)] +#![feature(try_with_capacity)] #![feature(vec_into_raw_parts)] // tidy-alphabetical-end // @@ -493,9 +500,9 @@ pub use core::default; pub use core::future; #[stable(feature = "core_hint", since = "1.27.0")] pub use core::hint; -#[stable(feature = "i128", since = "1.26.0")] +#[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] -pub use core::i128; +pub use core::i8; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::i16; @@ -505,9 +512,9 @@ pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::i64; -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "i128", since = "1.26.0")] #[allow(deprecated, deprecated_in_future)] -pub use core::i8; +pub use core::i128; #[stable(feature = "rust1", since = "1.0.0")] pub use core::intrinsics; #[stable(feature = "rust1", since = "1.0.0")] @@ -529,9 +536,9 @@ pub use core::pin; pub use core::ptr; #[stable(feature = "rust1", since = "1.0.0")] pub use core::result; -#[stable(feature = "i128", since = "1.26.0")] +#[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] -pub use core::u128; +pub use core::u8; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::u16; @@ -541,9 +548,9 @@ pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::u64; -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "i128", since = "1.26.0")] #[allow(deprecated, deprecated_in_future)] -pub use core::u8; +pub use core::u128; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::usize; @@ -595,6 +602,8 @@ pub mod path; #[unstable(feature = "anonymous_pipe", issue = "127154")] pub mod pipe; pub mod process; +#[unstable(feature = "random", issue = "130703")] +pub mod random; pub mod sync; pub mod time; @@ -649,9 +658,9 @@ pub mod arch { #[stable(feature = "simd_x86", since = "1.27.0")] pub use std_detect::is_x86_feature_detected; #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] - pub use std_detect::{is_mips64_feature_detected, is_mips_feature_detected}; + pub use std_detect::{is_mips_feature_detected, is_mips64_feature_detected}; #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] - pub use std_detect::{is_powerpc64_feature_detected, is_powerpc_feature_detected}; + pub use std_detect::{is_powerpc_feature_detected, is_powerpc64_feature_detected}; } // This was stabilized in the crate root so we have to keep it there. diff --git a/library/std/src/net/ip_addr/tests.rs b/library/std/src/net/ip_addr/tests.rs index ab99c0c2fcc16..7bed6f8a0f523 100644 --- a/library/std/src/net/ip_addr/tests.rs +++ b/library/std/src/net/ip_addr/tests.rs @@ -1,5 +1,5 @@ -use crate::net::test::{sa4, tsa}; use crate::net::Ipv4Addr; +use crate::net::test::{sa4, tsa}; #[test] fn to_socket_addr_socketaddr() { diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 22d2dfe65a249..06ed4f6a03d43 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -8,7 +8,7 @@ use crate::io::prelude::*; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::iter::FusedIterator; use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; -use crate::sys_common::{net as net_imp, AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner, net as net_imp}; use crate::time::Duration; /// A TCP stream between a local and a remote socket. diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 32e9086003d6b..d4252cb87ac22 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -4,7 +4,7 @@ mod tests; use crate::fmt; use crate::io::{self, ErrorKind}; use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; -use crate::sys_common::{net as net_imp, AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner, net as net_imp}; use crate::time::Duration; /// A UDP socket. diff --git a/library/std/src/num.rs b/library/std/src/num.rs index c1e6e7e628c83..d2f679e7dde54 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -26,9 +26,9 @@ pub use core::num::ZeroablePrimitive; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError}; #[stable(feature = "signed_nonzero", since = "1.34.0")] -pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; +pub use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize}; #[stable(feature = "nonzero", since = "1.28.0")] -pub use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; +pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; #[cfg(test)] use crate::fmt; diff --git a/library/std/src/os/fortanix_sgx/mod.rs b/library/std/src/os/fortanix_sgx/mod.rs index 64f4d97ca95e2..2b5ccbe98f1b3 100644 --- a/library/std/src/os/fortanix_sgx/mod.rs +++ b/library/std/src/os/fortanix_sgx/mod.rs @@ -22,12 +22,12 @@ pub mod usercalls { /// Lowest-level interfaces to usercalls and usercall ABI type definitions. pub mod raw { pub use crate::sys::abi::usercalls::raw::{ - accept_stream, alloc, async_queues, bind_stream, close, connect_stream, do_usercall, - exit, flush, free, insecure_time, launch_thread, read, read_alloc, send, wait, write, - ByteBuffer, Cancel, Error, Fd, FifoDescriptor, Register, RegisterArgument, Result, - Return, ReturnValue, Tcs, Usercall, Usercalls as UsercallNrs, EV_RETURNQ_NOT_EMPTY, - EV_UNPARK, EV_USERCALLQ_NOT_FULL, FD_STDERR, FD_STDIN, FD_STDOUT, RESULT_SUCCESS, - USERCALL_USER_DEFINED, WAIT_INDEFINITE, WAIT_NO, + ByteBuffer, Cancel, EV_RETURNQ_NOT_EMPTY, EV_UNPARK, EV_USERCALLQ_NOT_FULL, Error, + FD_STDERR, FD_STDIN, FD_STDOUT, Fd, FifoDescriptor, RESULT_SUCCESS, Register, + RegisterArgument, Result, Return, ReturnValue, Tcs, USERCALL_USER_DEFINED, Usercall, + Usercalls as UsercallNrs, WAIT_INDEFINITE, WAIT_NO, accept_stream, alloc, async_queues, + bind_stream, close, connect_stream, do_usercall, exit, flush, free, insecure_time, + launch_thread, read, read_alloc, send, wait, write, }; } } diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 020a8b324f410..6701173d1e005 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -139,10 +139,14 @@ pub mod macos; pub mod netbsd; #[cfg(target_os = "nto")] pub mod nto; +#[cfg(target_os = "nuttx")] +pub mod nuttx; #[cfg(target_os = "openbsd")] pub mod openbsd; #[cfg(target_os = "redox")] pub mod redox; +#[cfg(target_os = "rtems")] +pub mod rtems; #[cfg(target_os = "solaris")] pub mod solaris; #[cfg(target_os = "solid_asp3")] diff --git a/library/std/src/os/nuttx/fs.rs b/library/std/src/os/nuttx/fs.rs new file mode 100644 index 0000000000000..7d6d8d16eca79 --- /dev/null +++ b/library/std/src/os/nuttx/fs.rs @@ -0,0 +1,92 @@ +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_sec as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_sec as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_sec as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/library/std/src/os/nuttx/mod.rs b/library/std/src/os/nuttx/mod.rs new file mode 100644 index 0000000000000..7275bfd1765d5 --- /dev/null +++ b/library/std/src/os/nuttx/mod.rs @@ -0,0 +1,4 @@ +#![stable(feature = "raw_ext", since = "1.1.0")] +#![forbid(unsafe_op_in_unsafe_fn)] +pub mod fs; +pub(crate) mod raw; diff --git a/library/std/src/os/nuttx/raw.rs b/library/std/src/os/nuttx/raw.rs new file mode 100644 index 0000000000000..113079cf4abdc --- /dev/null +++ b/library/std/src/os/nuttx/raw.rs @@ -0,0 +1,33 @@ +//! rtems raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = libc::pthread_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blkcnt_t = libc::blkcnt_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blksize_t = libc::blksize_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = libc::dev_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = libc::ino_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = libc::mode_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = libc::nlink_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = libc::off_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = libc::time_t; diff --git a/library/std/src/os/rtems/fs.rs b/library/std/src/os/rtems/fs.rs new file mode 100644 index 0000000000000..bec0d41e42d81 --- /dev/null +++ b/library/std/src/os/rtems/fs.rs @@ -0,0 +1,374 @@ +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: crate::fs::Metadata +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Returns the device ID on which this file resides. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_dev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + + /// Returns the inode number. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ino()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + + /// Returns the file type and mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mode()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + + /// Returns the number of hard links to file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_nlink()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + + /// Returns the user ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_uid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + + /// Returns the group ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_gid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + + /// Returns the device ID that this file represents. Only relevant for special file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_rdev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_size()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + + /// Returns the last access time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + + /// Returns the last access time of the file, in nanoseconds since [`st_atime`]. + /// + /// [`st_atime`]: Self::st_atime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + + /// Returns the last modification time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + + /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. + /// + /// [`st_mtime`]: Self::st_mtime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + + /// Returns the last status change time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + + /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`]. + /// + /// [`st_ctime`]: Self::st_ctime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + + /// Returns the "preferred" block size for efficient filesystem I/O. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blksize()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + + /// Returns the number of blocks allocated to the file, 512-byte units. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::rtems::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blocks()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + + fn st_atime_nsec(&self) -> i64 { + 0 + } + + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + + fn st_mtime_nsec(&self) -> i64 { + 0 + } + + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + + fn st_ctime_nsec(&self) -> i64 { + 0 + } + + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/library/std/src/os/rtems/mod.rs b/library/std/src/os/rtems/mod.rs new file mode 100644 index 0000000000000..7275bfd1765d5 --- /dev/null +++ b/library/std/src/os/rtems/mod.rs @@ -0,0 +1,4 @@ +#![stable(feature = "raw_ext", since = "1.1.0")] +#![forbid(unsafe_op_in_unsafe_fn)] +pub mod fs; +pub(crate) mod raw; diff --git a/library/std/src/os/rtems/raw.rs b/library/std/src/os/rtems/raw.rs new file mode 100644 index 0000000000000..113079cf4abdc --- /dev/null +++ b/library/std/src/os/rtems/raw.rs @@ -0,0 +1,33 @@ +//! rtems raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = libc::pthread_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blkcnt_t = libc::blkcnt_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blksize_t = libc::blksize_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = libc::dev_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = libc::ino_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = libc::mode_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = libc::nlink_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = libc::off_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = libc::time_t; diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index caf6980afd91b..a964db2e0ac38 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -334,6 +334,7 @@ pub trait PermissionsExt { /// assert_eq!(permissions.mode(), 0o644); /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "permissions_from_mode")] fn from_mode(mode: u32) -> Self; } diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index c6581b9c4c8c8..5c2ec8ef994d4 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -69,10 +69,14 @@ mod platform { pub use crate::os::netbsd::*; #[cfg(target_os = "nto")] pub use crate::os::nto::*; + #[cfg(target_os = "nuttx")] + pub use crate::os::nuttx::*; #[cfg(target_os = "openbsd")] pub use crate::os::openbsd::*; #[cfg(target_os = "redox")] pub use crate::os::redox::*; + #[cfg(target_os = "rtems")] + pub use crate::os::rtems::*; #[cfg(target_os = "solaris")] pub use crate::os::solaris::*; #[cfg(target_os = "vita")] diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 79f2c365025b7..d7b87d480b73c 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -98,7 +98,7 @@ impl SocketAddr { unsafe { let mut addr: libc::sockaddr_un = mem::zeroed(); let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(core::ptr::addr_of_mut!(addr) as *mut _, &mut len))?; + cvt(f((&raw mut addr) as *mut _, &mut len))?; SocketAddr::from_parts(addr, len) } } diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 9b487a6298247..36967fc3f98b0 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -1,6 +1,6 @@ // FIXME: This is currently disabled on *BSD. -use super::{sockaddr_un, SocketAddr}; +use super::{SocketAddr, sockaddr_un}; use crate::io::{self, IoSlice, IoSliceMut}; use crate::marker::PhantomData; use crate::mem::zeroed; @@ -37,7 +37,7 @@ pub(super) fn recv_vectored_with_ancillary_from( unsafe { let mut msg_name: libc::sockaddr_un = zeroed(); let mut msg: libc::msghdr = zeroed(); - msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _; + msg.msg_name = (&raw mut msg_name) as *mut _; msg.msg_namelen = size_of::() as libc::socklen_t; msg.msg_iov = bufs.as_mut_ptr().cast(); msg.msg_iovlen = bufs.len() as _; @@ -70,7 +70,7 @@ pub(super) fn send_vectored_with_ancillary_to( if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; let mut msg: libc::msghdr = zeroed(); - msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _; + msg.msg_name = (&raw mut msg_name) as *mut _; msg.msg_namelen = msg_namelen; msg.msg_iov = bufs.as_ptr() as *mut _; msg.msg_iovlen = bufs.len() as _; diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index a605c3d4a2602..82446ea107fe5 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -12,9 +12,9 @@ ))] use libc::MSG_NOSIGNAL; +use super::{SocketAddr, sockaddr_un}; #[cfg(any(doc, target_os = "android", target_os = "linux"))] -use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; -use super::{sockaddr_un, SocketAddr}; +use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to}; #[cfg(any(doc, target_os = "android", target_os = "linux"))] use crate::io::{IoSlice, IoSliceMut}; use crate::net::Shutdown; @@ -100,7 +100,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(socket.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len as _))?; + cvt(libc::bind(socket.as_raw_fd(), (&raw const addr) as *const _, len as _))?; Ok(socket) } @@ -133,7 +133,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; cvt(libc::bind( socket.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len as _, ))?; Ok(socket) @@ -215,7 +215,7 @@ impl UnixDatagram { unsafe { let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(self.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?; + cvt(libc::connect(self.as_raw_fd(), (&raw const addr) as *const _, len))?; } Ok(()) } @@ -247,7 +247,7 @@ impl UnixDatagram { unsafe { cvt(libc::connect( self.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; } @@ -514,7 +514,7 @@ impl UnixDatagram { buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - core::ptr::addr_of!(addr) as *const _, + (&raw const addr) as *const _, len, ))?; Ok(count as usize) @@ -549,7 +549,7 @@ impl UnixDatagram { buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; Ok(count as usize) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index a55199c82fc10..be236317d047d 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -1,4 +1,4 @@ -use super::{sockaddr_un, SocketAddr, UnixStream}; +use super::{SocketAddr, UnixStream, sockaddr_un}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::path::Path; use crate::sys::cvt; @@ -103,11 +103,7 @@ impl UnixListener { )))] const backlog: libc::c_int = libc::SOMAXCONN; - cvt(libc::bind( - inner.as_inner().as_raw_fd(), - core::ptr::addr_of!(addr) as *const _, - len as _, - ))?; + cvt(libc::bind(inner.as_inner().as_raw_fd(), (&raw const addr) as *const _, len as _))?; cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; Ok(UnixListener(inner)) @@ -147,7 +143,7 @@ impl UnixListener { const backlog: core::ffi::c_int = 128; cvt(libc::bind( inner.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len as _, ))?; cvt(libc::listen(inner.as_raw_fd(), backlog))?; @@ -182,7 +178,7 @@ impl UnixListener { pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?; + let sock = self.0.accept((&raw mut storage) as *mut _, &mut len)?; let addr = SocketAddr::from_parts(storage, len)?; Ok((UnixStream(sock), addr)) } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 19fc7b3d8532f..cb210b41eae19 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -1,3 +1,6 @@ +use super::{SocketAddr, sockaddr_un}; +#[cfg(any(doc, target_os = "android", target_os = "linux"))] +use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to}; #[cfg(any( target_os = "android", target_os = "linux", @@ -8,10 +11,7 @@ target_os = "nto", target_vendor = "apple", ))] -use super::{peer_cred, UCred}; -#[cfg(any(doc, target_os = "android", target_os = "linux"))] -use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; -use super::{sockaddr_un, SocketAddr}; +use super::{UCred, peer_cred}; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::Shutdown; @@ -84,7 +84,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(inner.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?; + cvt(libc::connect(inner.as_raw_fd(), (&raw const addr) as *const _, len))?; Ok(UnixStream(inner)) } } @@ -118,7 +118,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::connect( inner.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; Ok(UnixStream(inner)) diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs index b96e373ad0ae3..e1014a4f296dd 100644 --- a/library/std/src/os/unix/net/ucred.rs +++ b/library/std/src/os/unix/net/ucred.rs @@ -38,7 +38,7 @@ pub(super) use self::impl_linux::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] mod impl_linux { - use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED}; + use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred}; use super::UCred; use crate::os::unix::io::AsRawFd; @@ -60,7 +60,7 @@ mod impl_linux { socket.as_raw_fd(), SOL_SOCKET, SO_PEERCRED, - core::ptr::addr_of_mut!(ucred) as *mut c_void, + (&raw mut ucred) as *mut c_void, &mut ucred_size, ); @@ -98,7 +98,7 @@ mod impl_bsd { #[cfg(target_vendor = "apple")] mod impl_apple { - use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL}; + use libc::{LOCAL_PEERPID, SOL_LOCAL, c_void, getpeereid, getsockopt, pid_t, socklen_t}; use super::UCred; use crate::os::unix::io::AsRawFd; @@ -121,7 +121,7 @@ mod impl_apple { socket.as_raw_fd(), SOL_LOCAL, LOCAL_PEERPID, - core::ptr::addr_of_mut!(pid) as *mut c_void, + (&raw mut pid) as *mut c_void, &mut pid_size, ); diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 46202441d4e38..9aadd9491169f 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -118,11 +118,7 @@ pub trait CommandExt: Sealed { /// [`pre_exec`]: CommandExt::pre_exec #[stable(feature = "process_exec", since = "1.15.0")] #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")] - #[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] - #[cfg_attr( - not(bootstrap), - rustc_deprecated_safe_2024(audit_that = "the closure is async-signal-safe") - )] + #[rustc_deprecated_safe_2024(audit_that = "the closure is async-signal-safe")] unsafe fn before_exec(&mut self, f: F) -> &mut process::Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static, diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 3dcde43cfec78..ddb8dbd8feea2 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -298,7 +298,7 @@ impl OpenOptionsExt for OpenOptions { /// of the [`BY_HANDLE_FILE_INFORMATION`] structure. /// /// [`BY_HANDLE_FILE_INFORMATION`]: -/// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information +/// https://docs.microsoft.com/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Returns the value of the `dwFileAttributes` field of this metadata. @@ -322,7 +322,7 @@ pub trait MetadataExt { /// ``` /// /// [File Attribute Constants]: - /// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants + /// https://docs.microsoft.com/windows/win32/fileio/file-attribute-constants #[stable(feature = "metadata_ext", since = "1.1.0")] fn file_attributes(&self) -> u32; @@ -351,7 +351,7 @@ pub trait MetadataExt { /// } /// ``` /// - /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime + /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime #[stable(feature = "metadata_ext", since = "1.1.0")] fn creation_time(&self) -> u64; @@ -386,7 +386,7 @@ pub trait MetadataExt { /// } /// ``` /// - /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime + /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime #[stable(feature = "metadata_ext", since = "1.1.0")] fn last_access_time(&self) -> u64; @@ -419,11 +419,11 @@ pub trait MetadataExt { /// } /// ``` /// - /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime + /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime #[stable(feature = "metadata_ext", since = "1.1.0")] fn last_write_time(&self) -> u64; - /// Returns the value of the `nFileSize{High,Low}` fields of this + /// Returns the value of the `nFileSize` fields of this /// metadata. /// /// The returned value does not have meaning for directories. @@ -462,7 +462,7 @@ pub trait MetadataExt { #[unstable(feature = "windows_by_handle", issue = "63010")] fn number_of_links(&self) -> Option; - /// Returns the value of the `nFileIndex{Low,High}` fields of this + /// Returns the value of the `nFileIndex` fields of this /// metadata. /// /// This will return `None` if the `Metadata` instance was created from a @@ -471,10 +471,14 @@ pub trait MetadataExt { #[unstable(feature = "windows_by_handle", issue = "63010")] fn file_index(&self) -> Option; - /// Returns the change time, which is the last time file metadata was changed, such as - /// renames, attributes, etc + /// Returns the value of the `ChangeTime` fields of this metadata. /// - /// This will return `None` if the `Metadata` instance was not created using the `FILE_BASIC_INFO` type. + /// `ChangeTime` is the last time file metadata was changed, such as + /// renames, attributes, etc. + /// + /// This will return `None` if `Metadata` instance was created from a call to + /// `DirEntry::metadata` or if the `target_vendor` is outside the current platform + /// support for this api. #[unstable(feature = "windows_change_time", issue = "121478")] fn change_time(&self) -> Option; } diff --git a/library/std/src/os/xous/ffi/definitions.rs b/library/std/src/os/xous/ffi/definitions.rs index 345005bcc78d7..1b16849af03b0 100644 --- a/library/std/src/os/xous/ffi/definitions.rs +++ b/library/std/src/os/xous/ffi/definitions.rs @@ -126,42 +126,36 @@ impl From for Error { #[stable(feature = "rust1", since = "1.0.0")] impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!( - f, - "{}", - match self { - Error::NoError => "no error occurred", - Error::BadAlignment => "memory was not properly aligned", - Error::BadAddress => "an invalid address was supplied", - Error::OutOfMemory => "the process or service has run out of memory", - Error::MemoryInUse => "the requested address is in use", - Error::InterruptNotFound => - "the requested interrupt does not exist on this platform", - Error::InterruptInUse => "the requested interrupt is currently in use", - Error::InvalidString => "the specified string was not formatted correctly", - Error::ServerExists => "a server with that address already exists", - Error::ServerNotFound => "the requetsed server could not be found", - Error::ProcessNotFound => "the target process does not exist", - Error::ProcessNotChild => - "the requested operation can only be done on child processes", - Error::ProcessTerminated => "the target process has crashed", - Error::Timeout => "the requested operation timed out", - Error::InternalError => "an internal error occurred", - Error::ServerQueueFull => "the server has too many pending messages", - Error::ThreadNotAvailable => "the specified thread does not exist", - Error::UnhandledSyscall => "the kernel did not recognize that syscall", - Error::InvalidSyscall => "the syscall had incorrect parameters", - Error::ShareViolation => "an attempt was made to share memory twice", - Error::InvalidThread => "tried to resume a thread that was not ready", - Error::InvalidPid => "kernel attempted to use a pid that was not valid", - Error::AccessDenied => "no permission to perform the requested operation", - Error::UseBeforeInit => "attempt to use a service before initialization finished", - Error::DoubleFree => "the requested resource was freed twice", - Error::DebugInProgress => "kernel attempted to activate a thread being debugged", - Error::InvalidLimit => "process attempted to adjust an invalid limit", - Error::UnknownError => "an unknown error occurred", - } - ) + write!(f, "{}", match self { + Error::NoError => "no error occurred", + Error::BadAlignment => "memory was not properly aligned", + Error::BadAddress => "an invalid address was supplied", + Error::OutOfMemory => "the process or service has run out of memory", + Error::MemoryInUse => "the requested address is in use", + Error::InterruptNotFound => "the requested interrupt does not exist on this platform", + Error::InterruptInUse => "the requested interrupt is currently in use", + Error::InvalidString => "the specified string was not formatted correctly", + Error::ServerExists => "a server with that address already exists", + Error::ServerNotFound => "the requetsed server could not be found", + Error::ProcessNotFound => "the target process does not exist", + Error::ProcessNotChild => "the requested operation can only be done on child processes", + Error::ProcessTerminated => "the target process has crashed", + Error::Timeout => "the requested operation timed out", + Error::InternalError => "an internal error occurred", + Error::ServerQueueFull => "the server has too many pending messages", + Error::ThreadNotAvailable => "the specified thread does not exist", + Error::UnhandledSyscall => "the kernel did not recognize that syscall", + Error::InvalidSyscall => "the syscall had incorrect parameters", + Error::ShareViolation => "an attempt was made to share memory twice", + Error::InvalidThread => "tried to resume a thread that was not ready", + Error::InvalidPid => "kernel attempted to use a pid that was not valid", + Error::AccessDenied => "no permission to perform the requested operation", + Error::UseBeforeInit => "attempt to use a service before initialization finished", + Error::DoubleFree => "the requested resource was freed twice", + Error::DebugInProgress => "kernel attempted to activate a thread being debugged", + Error::InvalidLimit => "process attempted to adjust an invalid limit", + Error::UnknownError => "an unknown error occurred", + }) } } diff --git a/library/std/src/os/xous/services.rs b/library/std/src/os/xous/services.rs index ddf0236f5ad74..93916750c0547 100644 --- a/library/std/src/os/xous/services.rs +++ b/library/std/src/os/xous/services.rs @@ -19,7 +19,7 @@ pub(crate) use ticktimer::*; mod ns { const NAME_MAX_LENGTH: usize = 64; - use crate::os::xous::ffi::{lend_mut, Connection}; + use crate::os::xous::ffi::{Connection, lend_mut}; // By making this repr(C), the layout of this struct becomes well-defined // and no longer shifts around. // By marking it as `align(4096)` we define that it will be page-aligned, diff --git a/library/std/src/os/xous/services/systime.rs b/library/std/src/os/xous/services/systime.rs index 079ede7aa86c7..de87694b4cdca 100644 --- a/library/std/src/os/xous/services/systime.rs +++ b/library/std/src/os/xous/services/systime.rs @@ -1,6 +1,6 @@ use core::sync::atomic::{AtomicU32, Ordering}; -use crate::os::xous::ffi::{connect, Connection}; +use crate::os::xous::ffi::{Connection, connect}; pub(crate) enum SystimeScalar { GetUtcTimeMs, diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 6f0952c41ede5..015cab8948547 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -231,11 +231,11 @@ pub macro panic_2015 { }), } +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use core::panic::Location; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] pub use core::panic::panic_2021; -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub use core::panic::Location; #[stable(feature = "catch_unwind", since = "1.9.0")] pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; @@ -283,6 +283,9 @@ where { } +#[unstable(feature = "abort_unwind", issue = "130338")] +pub use core::panic::abort_unwind; + /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// /// This function will return `Ok` with the closure's result if the closure diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 1c972d3810036..9fe05db8126df 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -23,8 +23,8 @@ use crate::mem::{self, ManuallyDrop}; use crate::panic::{BacktraceStyle, PanicHookInfo}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{PoisonError, RwLock}; -use crate::sys::backtrace; use crate::sys::stdio::panic_output; +use crate::sys::{backtrace, dbg}; use crate::{fmt, intrinsics, process, thread}; // Binary interface to the panic runtime that the standard library depends on. @@ -506,7 +506,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // method of calling a catch panic whilst juggling ownership. let mut data = Data { f: ManuallyDrop::new(f) }; - let data_ptr = core::ptr::addr_of_mut!(data) as *mut u8; + let data_ptr = (&raw mut data) as *mut u8; // SAFETY: // // Access to the union's fields: this is `std` and we know that the `r#try` @@ -859,6 +859,14 @@ pub fn rust_panic_without_hook(payload: Box) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(not(feature = "panic_immediate_abort"))] fn rust_panic(msg: &mut dyn PanicPayload) -> ! { + // Break into the debugger if it is attached. + // The return value is not currently used. + // + // This function isn't used anywhere else, and + // using inside `#[panic_handler]` doesn't seem + // to count, so a warning is issued. + let _ = dbg::breakpoint_if_debugging(); + let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } @@ -866,6 +874,14 @@ fn rust_panic(msg: &mut dyn PanicPayload) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(feature = "panic_immediate_abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { + // Break into the debugger if it is attached. + // The return value is not currently used. + // + // This function isn't used anywhere else, and + // using inside `#[panic_handler]` doesn't seem + // to count, so a warning is issued. + let _ = dbg::breakpoint_if_debugging(); + unsafe { crate::intrinsics::abort(); } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9eaa0e01c2c00..63edfdb82f361 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -75,14 +75,14 @@ use core::clone::CloneToUninit; use crate::borrow::{Borrow, Cow}; use crate::collections::TryReserveError; use crate::error::Error; -use crate::ffi::{os_str, OsStr, OsString}; +use crate::ffi::{OsStr, OsString, os_str}; use crate::hash::{Hash, Hasher}; use crate::iter::FusedIterator; use crate::ops::{self, Deref}; use crate::rc::Rc; use crate::str::FromStr; use crate::sync::Arc; -use crate::sys::path::{is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR}; +use crate::sys::path::{MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix}; use crate::{cmp, fmt, fs, io, sys}; //////////////////////////////////////////////////////////////////////////////// @@ -263,6 +263,7 @@ pub fn is_separator(c: char) -> bool { /// /// For example, `/` on Unix and `\` on Windows. #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "path_main_separator")] pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP; /// The primary separator of path components for the current platform. @@ -1153,6 +1154,21 @@ impl FusedIterator for Ancestors<'_> {} /// ``` /// /// Which method works best depends on what kind of situation you're in. +/// +/// Note that `PathBuf` does not always sanitize arguments, for example +/// [`push`] allows paths built from strings which include separators: +/// +/// use std::path::PathBuf; +/// +/// let mut path = PathBuf::new(); +/// +/// path.push(r"C:\"); +/// path.push("windows"); +/// path.push(r"..\otherdir"); +/// path.push("system32"); +/// +/// The behaviour of `PathBuf` may be changed to a panic on such inputs +/// in the future. [`Extend::extend`] should be used to add multi-part paths. #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] pub struct PathBuf { @@ -1211,6 +1227,7 @@ impl PathBuf { /// let p = PathBuf::from("/test"); /// assert_eq!(Path::new("/test"), p.as_path()); /// ``` + #[cfg_attr(not(test), rustc_diagnostic_item = "pathbuf_as_path")] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] @@ -1391,6 +1408,9 @@ impl PathBuf { /// `file_name`. The new path will be a sibling of the original path. /// (That is, it will have the same parent.) /// + /// The argument is not sanitized, so can include separators. This + /// behaviour may be changed to a panic in the future. + /// /// [`self.file_name`]: Path::file_name /// [`pop`]: PathBuf::pop /// @@ -1411,6 +1431,12 @@ impl PathBuf { /// /// buf.set_file_name("baz"); /// assert!(buf == PathBuf::from("/baz")); + /// + /// buf.set_file_name("../b/c.txt"); + /// assert!(buf == PathBuf::from("/../b/c.txt")); + /// + /// buf.set_file_name("baz"); + /// assert!(buf == PathBuf::from("/../b/baz")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_file_name>(&mut self, file_name: S) { @@ -2200,7 +2226,7 @@ impl Path { /// Converts a `Path` to a [`Cow`]. /// - /// Any non-Unicode sequences are replaced with + /// Any non-UTF-8 sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [U+FFFD]: super::char::REPLACEMENT_CHARACTER @@ -2240,6 +2266,7 @@ impl Path { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "path_to_pathbuf")] pub fn to_path_buf(&self) -> PathBuf { PathBuf::from(self.inner.to_os_string()) } @@ -3117,7 +3144,7 @@ unsafe impl CloneToUninit for Path { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: Path is just a wrapper around OsStr - unsafe { self.inner.clone_to_uninit(core::ptr::addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/pipe.rs b/library/std/src/pipe.rs index aa4c7014fe918..891032e94a669 100644 --- a/library/std/src/pipe.rs +++ b/library/std/src/pipe.rs @@ -12,7 +12,7 @@ //! ``` use crate::io; -use crate::sys::anonymous_pipe::{pipe as pipe_inner, AnonPipe}; +use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// Create anonymous pipe that is close-on-exec and blocking. #[unstable(feature = "anonymous_pipe", issue = "127154")] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index bbea27ebc1056..c84a5c652639f 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -157,7 +157,7 @@ use crate::io::prelude::*; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::num::NonZero; use crate::path::Path; -use crate::sys::pipe::{read2, AnonPipe}; +use crate::sys::pipe::{AnonPipe, read2}; use crate::sys::process as imp; #[stable(feature = "command_access", since = "1.57.0")] pub use crate::sys_common::process::CommandEnvs; @@ -617,8 +617,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -699,8 +697,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -748,8 +744,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -786,8 +780,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -822,8 +814,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::{Command, Stdio}; /// use std::env; @@ -870,8 +860,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -900,8 +888,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -928,8 +914,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -959,8 +943,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::{Command, Stdio}; /// @@ -988,8 +970,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::{Command, Stdio}; /// @@ -1017,8 +997,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::{Command, Stdio}; /// @@ -1039,8 +1017,6 @@ impl Command { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -1934,10 +1910,14 @@ impl crate::error::Error for ExitStatusError {} /// to its parent under normal termination. /// /// `ExitCode` is intended to be consumed only by the standard library (via -/// [`Termination::report()`]), and intentionally does not provide accessors like -/// `PartialEq`, `Eq`, or `Hash`. Instead the standard library provides the -/// canonical `SUCCESS` and `FAILURE` exit codes as well as `From for -/// ExitCode` for constructing other arbitrary exit codes. +/// [`Termination::report()`]). For forwards compatibility with potentially +/// unusual targets, this type currently does not provide `Eq`, `Hash`, or +/// access to the raw value. This type does provide `PartialEq` for +/// comparison, but note that there may potentially be multiple failure +/// codes, some of which will _not_ compare equal to `ExitCode::FAILURE`. +/// The standard library provides the canonical `SUCCESS` and `FAILURE` +/// exit codes as well as `From for ExitCode` for constructing other +/// arbitrary exit codes. /// /// # Portability /// @@ -1976,7 +1956,7 @@ impl crate::error::Error for ExitStatusError {} /// ExitCode::SUCCESS /// } /// ``` -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] #[stable(feature = "process_exitcode", since = "1.61.0")] pub struct ExitCode(imp::ExitCode); @@ -2105,8 +2085,6 @@ impl Child { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -2129,8 +2107,6 @@ impl Child { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -2158,8 +2134,6 @@ impl Child { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -2194,8 +2168,6 @@ impl Child { /// /// # Examples /// - /// Basic usage: - /// /// ```no_run /// use std::process::Command; /// @@ -2398,15 +2370,11 @@ pub fn abort() -> ! { /// /// # Examples /// -/// Basic usage: -/// /// ```no_run /// use std::process; /// /// println!("My pid is {}", process::id()); /// ``` -/// -/// #[must_use] #[stable(feature = "getpid", since = "1.26.0")] pub fn id() -> u32 { diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index f8e8e0dea553b..88cc95caf4073 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -437,7 +437,7 @@ fn test_proc_thread_attributes() { use crate::mem; use crate::os::windows::io::AsRawHandle; use crate::os::windows::process::CommandExt; - use crate::sys::c::{CloseHandle, BOOL, HANDLE}; + use crate::sys::c::{BOOL, CloseHandle, HANDLE}; use crate::sys::cvt; #[repr(C)] diff --git a/library/std/src/random.rs b/library/std/src/random.rs new file mode 100644 index 0000000000000..604fa4df11066 --- /dev/null +++ b/library/std/src/random.rs @@ -0,0 +1,105 @@ +//! Random value generation. +//! +//! The [`Random`] trait allows generating a random value for a type using a +//! given [`RandomSource`]. + +#[unstable(feature = "random", issue = "130703")] +pub use core::random::*; + +use crate::sys::random as sys; + +/// The default random source. +/// +/// This asks the system for random data suitable for cryptographic purposes +/// such as key generation. If security is a concern, consult the platform +/// documentation below for the specific guarantees your target provides. +/// +/// The high quality of randomness provided by this source means it can be quite +/// slow on some targets. If you need a large quantity of random numbers and +/// security is not a concern, consider using an alternative random number +/// generator (potentially seeded from this one). +/// +/// # Underlying sources +/// +/// Platform | Source +/// -----------------------|--------------------------------------------------------------- +/// Linux | [`getrandom`] or [`/dev/urandom`] after polling `/dev/random` +/// Windows | [`ProcessPrng`](https://learn.microsoft.com/en-us/windows/win32/seccng/processprng) +/// Apple | `CCRandomGenerateBytes` +/// DragonFly | [`arc4random_buf`](https://man.dragonflybsd.org/?command=arc4random) +/// ESP-IDF | [`esp_fill_random`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t) +/// FreeBSD | [`arc4random_buf`](https://man.freebsd.org/cgi/man.cgi?query=arc4random) +/// Fuchsia | [`cprng_draw`](https://fuchsia.dev/reference/syscalls/cprng_draw) +/// Haiku | `arc4random_buf` +/// Illumos | [`arc4random_buf`](https://www.illumos.org/man/3C/arc4random) +/// NetBSD | [`arc4random_buf`](https://man.netbsd.org/arc4random.3) +/// OpenBSD | [`arc4random_buf`](https://man.openbsd.org/arc4random.3) +/// Solaris | [`arc4random_buf`](https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html) +/// Vita | `arc4random_buf` +/// Hermit | `read_entropy` +/// Horizon | `getrandom` shim +/// Hurd, L4Re, QNX | `/dev/urandom` +/// Redox | `/scheme/rand` +/// SGX | [`rdrand`](https://en.wikipedia.org/wiki/RDRAND) +/// SOLID | `SOLID_RNG_SampleRandomBytes` +/// TEEOS | `TEE_GenerateRandom` +/// UEFI | [`EFI_RNG_PROTOCOL`](https://uefi.org/specs/UEFI/2.10/37_Secure_Technologies.html#random-number-generator-protocol) +/// VxWorks | `randABytes` after waiting for `randSecure` to become ready +/// WASI | [`random_get`](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-random_getbuf-pointeru8-buf_len-size---result-errno) +/// ZKVM | `sys_rand` +/// +/// Note that the sources used might change over time. +/// +/// Consult the documentation for the underlying operations on your supported +/// targets to determine whether they provide any particular desired properties, +/// such as support for reseeding on VM fork operations. +/// +/// [`getrandom`]: https://www.man7.org/linux/man-pages/man2/getrandom.2.html +/// [`/dev/urandom`]: https://www.man7.org/linux/man-pages/man4/random.4.html +#[derive(Default, Debug, Clone, Copy)] +#[unstable(feature = "random", issue = "130703")] +pub struct DefaultRandomSource; + +#[unstable(feature = "random", issue = "130703")] +impl RandomSource for DefaultRandomSource { + fn fill_bytes(&mut self, bytes: &mut [u8]) { + sys::fill_bytes(bytes) + } +} + +/// Generates a random value with the default random source. +/// +/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and +/// will sample according to the same distribution as the underlying [`Random`] +/// trait implementation. See [`DefaultRandomSource`] for more information about +/// how randomness is sourced. +/// +/// **Warning:** Be careful when manipulating random values! The +/// [`random`](Random::random) method on integers samples them with a uniform +/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using +/// modulo operations, some of the resulting values can become more likely than +/// others. Use audited crates when in doubt. +/// +/// # Examples +/// +/// Generating a [version 4/variant 1 UUID] represented as text: +/// ``` +/// #![feature(random)] +/// +/// use std::random::random; +/// +/// let bits: u128 = random(); +/// let g1 = (bits >> 96) as u32; +/// let g2 = (bits >> 80) as u16; +/// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16; +/// let g4 = (0x8000 | (bits >> 48) & 0x3fff) as u16; +/// let g5 = (bits & 0xffffffffffff) as u64; +/// let uuid = format!("{g1:08x}-{g2:04x}-{g3:04x}-{g4:04x}-{g5:012x}"); +/// println!("{uuid}"); +/// ``` +/// +/// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) +#[unstable(feature = "random", issue = "130703")] +pub fn random() -> T { + T::random(&mut DefaultRandomSource) +} diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 307a543c9d215..b6f36931ec28a 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -146,7 +146,7 @@ fn lang_start_internal( rtabort!("drop of the panic payload panicked"); }); panic::catch_unwind(cleanup).map_err(rt_abort)?; - // Guard against multple threads calling `libc::exit` concurrently. + // Guard against multiple threads calling `libc::exit` concurrently. // See the documentation for `unique_thread_exit` for more information. panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?; ret_code diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs index 834a3e75158a7..c5620cd91d851 100644 --- a/library/std/src/sync/barrier/tests.rs +++ b/library/std/src/sync/barrier/tests.rs @@ -1,4 +1,4 @@ -use crate::sync::mpsc::{channel, TryRecvError}; +use crate::sync::mpsc::{TryRecvError, channel}; use crate::sync::{Arc, Barrier}; use crate::thread; diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 08d46f356d9f2..44ffcb528d937 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -2,7 +2,7 @@ mod tests; use crate::fmt; -use crate::sync::{mutex, poison, LockResult, MutexGuard, PoisonError}; +use crate::sync::{LockResult, MutexGuard, PoisonError, mutex, poison}; use crate::sys::sync as sys; use crate::time::{Duration, Instant}; @@ -195,8 +195,11 @@ impl Condvar { if poisoned { Err(PoisonError::new(guard)) } else { Ok(guard) } } - /// Blocks the current thread until this condition variable receives a - /// notification and the provided condition is false. + /// Blocks the current thread until the provided condition becomes false. + /// + /// `condition` is checked immediately; if not met (returns `true`), this + /// will [`wait`] for the next notification then check again. This repeats + /// until `condition` returns `false`, in which case this function returns. /// /// This function will atomically unlock the mutex specified (represented by /// `guard`) and block the current thread. This means that any calls @@ -210,6 +213,7 @@ impl Condvar { /// poisoned when this thread re-acquires the lock. For more information, /// see information about [poisoning] on the [`Mutex`] type. /// + /// [`wait`]: Self::wait /// [`notify_one`]: Self::notify_one /// [`notify_all`]: Self::notify_all /// [poisoning]: super::Mutex#poisoning diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 953aef40e7b76..b05615035d7b1 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -44,8 +44,6 @@ union Data { /// /// // The `String` is built, stored in the `LazyLock`, and returned as `&String`. /// let _ = &*DEEP_THOUGHT; -/// // The `String` is retrieved from the `LazyLock` and returned as `&String`. -/// let _ = &*DEEP_THOUGHT; /// ``` /// /// Initialize fields with `LazyLock`. @@ -121,7 +119,7 @@ impl T> LazyLock { pub fn into_inner(mut this: Self) -> Result { let state = this.once.state(); match state { - ExclusiveState::Poisoned => panic!("LazyLock instance has previously been poisoned"), + ExclusiveState::Poisoned => panic_poisoned(), state => { let this = ManuallyDrop::new(this); let data = unsafe { ptr::read(&this.data) }.into_inner(); @@ -134,6 +132,60 @@ impl T> LazyLock { } } + /// Forces the evaluation of this lazy value and returns a mutable reference to + /// the result. + /// + /// # Examples + /// + /// ``` + /// #![feature(lazy_get)] + /// use std::sync::LazyLock; + /// + /// let mut lazy = LazyLock::new(|| 92); + /// + /// let p = LazyLock::force_mut(&mut lazy); + /// assert_eq!(*p, 92); + /// *p = 44; + /// assert_eq!(*lazy, 44); + /// ``` + #[inline] + #[unstable(feature = "lazy_get", issue = "129333")] + pub fn force_mut(this: &mut LazyLock) -> &mut T { + #[cold] + /// # Safety + /// May only be called when the state is `Incomplete`. + unsafe fn really_init_mut T>(this: &mut LazyLock) -> &mut T { + struct PoisonOnPanic<'a, T, F>(&'a mut LazyLock); + impl Drop for PoisonOnPanic<'_, T, F> { + #[inline] + fn drop(&mut self) { + self.0.once.set_state(ExclusiveState::Poisoned); + } + } + + // SAFETY: We always poison if the initializer panics (then we never check the data), + // or set the data on success. + let f = unsafe { ManuallyDrop::take(&mut this.data.get_mut().f) }; + // INVARIANT: Initiated from mutable reference, don't drop because we read it. + let guard = PoisonOnPanic(this); + let data = f(); + guard.0.data.get_mut().value = ManuallyDrop::new(data); + guard.0.once.set_state(ExclusiveState::Complete); + core::mem::forget(guard); + // SAFETY: We put the value there above. + unsafe { &mut this.data.get_mut().value } + } + + let state = this.once.state(); + match state { + ExclusiveState::Poisoned => panic_poisoned(), + // SAFETY: The `Once` states we completed the initialization. + ExclusiveState::Complete => unsafe { &mut this.data.get_mut().value }, + // SAFETY: The state is `Incomplete`. + ExclusiveState::Incomplete => unsafe { really_init_mut(this) }, + } + } + /// Forces the evaluation of this lazy value and returns a reference to /// result. This is equivalent to the `Deref` impl, but is explicit. /// @@ -174,13 +226,58 @@ impl T> LazyLock { } impl LazyLock { - /// Gets the inner value if it has already been initialized. - fn get(&self) -> Option<&T> { - if self.once.is_completed() { + /// Returns a reference to the value if initialized, or `None` if not. + /// + /// # Examples + /// + /// ``` + /// #![feature(lazy_get)] + /// + /// use std::sync::LazyLock; + /// + /// let mut lazy = LazyLock::new(|| 92); + /// + /// assert_eq!(LazyLock::get_mut(&mut lazy), None); + /// let _ = LazyLock::force(&lazy); + /// *LazyLock::get_mut(&mut lazy).unwrap() = 44; + /// assert_eq!(*lazy, 44); + /// ``` + #[inline] + #[unstable(feature = "lazy_get", issue = "129333")] + pub fn get_mut(this: &mut LazyLock) -> Option<&mut T> { + // `state()` does not perform an atomic load, so prefer it over `is_complete()`. + let state = this.once.state(); + match state { + // SAFETY: + // The closure has been run successfully, so `value` has been initialized. + ExclusiveState::Complete => Some(unsafe { &mut this.data.get_mut().value }), + _ => None, + } + } + + /// Returns a mutable reference to the value if initialized, or `None` if not. + /// + /// # Examples + /// + /// ``` + /// #![feature(lazy_get)] + /// + /// use std::sync::LazyLock; + /// + /// let lazy = LazyLock::new(|| 92); + /// + /// assert_eq!(LazyLock::get(&lazy), None); + /// let _ = LazyLock::force(&lazy); + /// assert_eq!(LazyLock::get(&lazy), Some(&92)); + /// ``` + #[inline] + #[unstable(feature = "lazy_get", issue = "129333")] + pub fn get(this: &LazyLock) -> Option<&T> { + if this.once.is_completed() { // SAFETY: // The closure has been run successfully, so `value` has been initialized // and will not be modified again. - Some(unsafe { &*(*self.data.get()).value }) + Some(unsafe { &(*this.data.get()).value }) } else { None } @@ -228,7 +325,7 @@ impl Default for LazyLock { impl fmt::Debug for LazyLock { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut d = f.debug_tuple("LazyLock"); - match self.get() { + match LazyLock::get(self) { Some(v) => d.field(v), None => d.field(&format_args!("")), }; @@ -236,6 +333,12 @@ impl fmt::Debug for LazyLock { } } +#[cold] +#[inline(never)] +fn panic_poisoned() -> ! { + panic!("LazyLock instance has previously been poisoned") +} + // We never create a `&F` from a `&LazyLock` so it is fine // to not impl `Sync` for `F`. #[stable(feature = "lazy_cell", since = "1.80.0")] diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs index 8a6ab4ac4fd99..94044368305be 100644 --- a/library/std/src/sync/lazy_lock/tests.rs +++ b/library/std/src/sync/lazy_lock/tests.rs @@ -142,3 +142,24 @@ fn is_sync_send() { fn assert_traits() {} assert_traits::>(); } + +#[test] +#[should_panic = "has previously been poisoned"] +fn lazy_force_mut_panic() { + let mut lazy = LazyLock::::new(|| panic!()); + crate::panic::catch_unwind(crate::panic::AssertUnwindSafe(|| { + let _ = LazyLock::force_mut(&mut lazy); + })) + .unwrap_err(); + let _ = &*lazy; +} + +#[test] +fn lazy_force_mut() { + let s = "abc".to_owned(); + let mut lazy = LazyLock::new(move || s); + LazyLock::force_mut(&mut lazy); + let p = LazyLock::force_mut(&mut lazy); + p.clear(); + LazyLock::force_mut(&mut lazy); +} diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index d0ba8cc3b47df..0fb8e669bf86e 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -9,6 +9,9 @@ //! Consider the following code, operating on some global static variables: //! //! ```rust +//! // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +//! #![allow(static_mut_refs)] +//! //! static mut A: u32 = 0; //! static mut B: u32 = 0; //! static mut C: u32 = 0; @@ -158,10 +161,10 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::sync::atomic; #[unstable(feature = "exclusive_wrapper", issue = "98407")] pub use core::sync::Exclusive; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::sync::atomic; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::sync::{Arc, Weak}; @@ -178,7 +181,7 @@ pub use self::mutex::MappedMutexGuard; pub use self::mutex::{Mutex, MutexGuard}; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] -pub use self::once::{Once, OnceState, ONCE_INIT}; +pub use self::once::{ONCE_INIT, Once, OnceState}; #[stable(feature = "once_cell", since = "1.70.0")] pub use self::once_lock::OnceLock; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/sync/mpmc/context.rs b/library/std/src/sync/mpmc/context.rs index 8db3c9896eb77..2371d32d4ea0d 100644 --- a/library/std/src/sync/mpmc/context.rs +++ b/library/std/src/sync/mpmc/context.rs @@ -4,8 +4,8 @@ use super::select::Selected; use super::waker::current_thread_id; use crate::cell::Cell; use crate::ptr; -use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; use crate::sync::Arc; +use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; use crate::thread::{self, Thread}; use crate::time::Instant; diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index bbe205cad04e6..88a8c75f7c8b9 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -551,7 +551,7 @@ impl Channel { let mut head = self.head.index.load(Ordering::Acquire); // The channel may be uninitialized, so we have to swap to avoid overwriting any sender's attempts - // to initalize the first block before noticing that the receivers disconnected. Late allocations + // to initialize the first block before noticing that the receivers disconnected. Late allocations // will be deallocated by the sender in Drop. let mut block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel); diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs index fb877887f9c9d..1895466f95d45 100644 --- a/library/std/src/sync/mpmc/waker.rs +++ b/library/std/src/sync/mpmc/waker.rs @@ -3,8 +3,8 @@ use super::context::Context; use super::select::{Operation, Selected}; use crate::ptr; -use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::Mutex; +use crate::sync::atomic::{AtomicBool, Ordering}; /// Represents a thread blocked on a specific channel operation. pub(crate) struct Entry { diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index 2b82eeda3d5fb..446881291e68e 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -9,8 +9,8 @@ use super::utils::Backoff; use super::waker::Waker; use crate::cell::UnsafeCell; use crate::marker::PhantomData; -use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::Mutex; +use crate::sync::atomic::{AtomicBool, Ordering}; use crate::time::Instant; use crate::{fmt, ptr}; @@ -185,11 +185,7 @@ impl Channel { // Prepare for blocking until a receiver wakes us up. let oper = Operation::hook(token); let mut packet = Packet::::message_on_stack(msg); - inner.senders.register_with_packet( - oper, - core::ptr::addr_of_mut!(packet) as *mut (), - cx, - ); + inner.senders.register_with_packet(oper, (&raw mut packet) as *mut (), cx); inner.receivers.notify(); drop(inner); @@ -256,11 +252,7 @@ impl Channel { // Prepare for blocking until a sender wakes us up. let oper = Operation::hook(token); let mut packet = Packet::::empty_on_stack(); - inner.receivers.register_with_packet( - oper, - core::ptr::addr_of_mut!(packet) as *mut (), - cx, - ); + inner.receivers.register_with_packet(oper, (&raw mut packet) as *mut (), cx); inner.senders.notify(); drop(inner); diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index d417034f5af85..f3de1f7bf495e 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -7,7 +7,7 @@ use crate::marker::PhantomData; use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; use crate::ptr::NonNull; -use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; +use crate::sync::{LockResult, TryLockError, TryLockResult, poison}; use crate::sys::sync as sys; /// A mutual exclusion primitive useful for protecting shared data diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index bf595fdea2d25..5a1cd7d0b8b12 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -314,6 +314,16 @@ impl Once { pub(crate) fn state(&mut self) -> ExclusiveState { self.inner.state() } + + /// Sets current state of the `Once` instance. + /// + /// Since this takes a mutable reference, no initialization can currently + /// be running, so the state must be either "incomplete", "poisoned" or + /// "complete". + #[inline] + pub(crate) fn set_state(&mut self, new_state: ExclusiveState) { + self.inner.set_state(new_state); + } } #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index a51e5c1b76b23..be615a5a8ef37 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -517,7 +517,7 @@ impl OnceLock { res = Err(e); // Treat the underlying `Once` as poisoned since we - // failed to initialize our value. Calls + // failed to initialize our value. p.poison(); } } diff --git a/library/std/src/sync/once_lock/tests.rs b/library/std/src/sync/once_lock/tests.rs index 176830c6748b2..1fff3273d2021 100644 --- a/library/std/src/sync/once_lock/tests.rs +++ b/library/std/src/sync/once_lock/tests.rs @@ -1,7 +1,7 @@ +use crate::sync::OnceLock; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::SeqCst; use crate::sync::mpsc::channel; -use crate::sync::OnceLock; use crate::{panic, thread}; fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 84a0b36db1798..39f23a14441c2 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -8,7 +8,7 @@ use crate::fmt; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sys::sync as sys; -use crate::thread::{current_id, ThreadId}; +use crate::thread::{ThreadId, current_id}; /// A re-entrant mutual exclusion lock /// @@ -136,7 +136,7 @@ cfg_if!( // match do we read out the actual TID. // Note also that we can use relaxed atomic operations here, because // we only ever read from the tid if `tls_addr` matches the current - // TLS address. In that case, either the the tid has been set by + // TLS address. In that case, either the tid has been set by // the current thread, or by a thread that has terminated before // the current thread was created. In either case, no further // synchronization is needed (as per ) diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index d995a16e056d6..143bdef736d25 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -7,7 +7,7 @@ use crate::marker::PhantomData; use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; use crate::ptr::NonNull; -use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; +use crate::sync::{LockResult, TryLockError, TryLockResult, poison}; use crate::sys::sync as sys; /// A reader-writer lock diff --git a/library/std/src/sys/alloc/solid.rs b/library/std/src/sys/alloc/solid.rs index abb534a1c5cf4..47cfa2eb1162b 100644 --- a/library/std/src/sys/alloc/solid.rs +++ b/library/std/src/sys/alloc/solid.rs @@ -1,4 +1,4 @@ -use super::{realloc_fallback, MIN_ALIGN}; +use super::{MIN_ALIGN, realloc_fallback}; use crate::alloc::{GlobalAlloc, Layout, System}; #[stable(feature = "alloc_system_type", since = "1.28.0")] diff --git a/library/std/src/sys/alloc/unix.rs b/library/std/src/sys/alloc/unix.rs index 46ed7de7162f8..1af9d76629014 100644 --- a/library/std/src/sys/alloc/unix.rs +++ b/library/std/src/sys/alloc/unix.rs @@ -1,4 +1,4 @@ -use super::{realloc_fallback, MIN_ALIGN}; +use super::{MIN_ALIGN, realloc_fallback}; use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ptr; @@ -71,6 +71,7 @@ cfg_if::cfg_if! { } } else { #[inline] + #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { let mut out = ptr::null_mut(); // We prefer posix_memalign over aligned_alloc since it is more widely available, and diff --git a/library/std/src/sys/alloc/wasm.rs b/library/std/src/sys/alloc/wasm.rs index ef9d753d7f86c..a308fafc68b15 100644 --- a/library/std/src/sys/alloc/wasm.rs +++ b/library/std/src/sys/alloc/wasm.rs @@ -16,6 +16,9 @@ //! The crate itself provides a global allocator which on wasm has no //! synchronization as there are no threads! +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use crate::alloc::{GlobalAlloc, Layout, System}; static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new(); diff --git a/library/std/src/sys/alloc/windows.rs b/library/std/src/sys/alloc/windows.rs index e91956966aa73..a77dda6e817ba 100644 --- a/library/std/src/sys/alloc/windows.rs +++ b/library/std/src/sys/alloc/windows.rs @@ -1,4 +1,4 @@ -use super::{realloc_fallback, MIN_ALIGN}; +use super::{MIN_ALIGN, realloc_fallback}; use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ffi::c_void; use crate::mem::MaybeUninit; diff --git a/library/std/src/sys/dbg.rs b/library/std/src/sys/dbg.rs new file mode 100644 index 0000000000000..7266a739e785d --- /dev/null +++ b/library/std/src/sys/dbg.rs @@ -0,0 +1,152 @@ +//! Debugging aids. + +/// Presence of a debugger. The debugger being concerned +/// is expected to use the OS API to debug this process. +#[derive(Copy, Clone, Debug)] +#[allow(unused)] +pub(crate) enum DebuggerPresence { + /// The debugger is attached to this process. + Detected, + /// The debugger is not attached to this process. + NotDetected, +} + +#[cfg(target_os = "windows")] +mod os { + use super::DebuggerPresence; + + #[link(name = "kernel32")] + extern "system" { + fn IsDebuggerPresent() -> i32; + } + + pub(super) fn is_debugger_present() -> Option { + // SAFETY: No state is shared between threads. The call reads + // a field from the Thread Environment Block using the OS API + // as required by the documentation. + if unsafe { IsDebuggerPresent() } != 0 { + Some(DebuggerPresence::Detected) + } else { + Some(DebuggerPresence::NotDetected) + } + } +} + +#[cfg(any(target_vendor = "apple", target_os = "freebsd"))] +mod os { + use libc::{CTL_KERN, KERN_PROC, KERN_PROC_PID, c_int, sysctl}; + + use super::DebuggerPresence; + use crate::io::{Cursor, Read, Seek, SeekFrom}; + use crate::process; + + const P_TRACED: i32 = 0x00000800; + + // The assumption is that the kernel structures available to the + // user space may not shrink or repurpose the existing fields over + // time. The kernels normally adhere to that for the backward + // compatibility of the user space. + + // The macOS 14.5 SDK comes with a header `MacOSX14.5.sdk/usr/include/sys/sysctl.h` + // that defines `struct kinfo_proc` be of `648` bytes on the 64-bit system. That has + // not changed since macOS 10.13 (released in 2017) at least, validated by building + // a C program in XCode while changing the build target. Apple provides this example + // for reference: https://developer.apple.com/library/archive/qa/qa1361/_index.html. + #[cfg(target_vendor = "apple")] + const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 648 } else { 492 }; + #[cfg(target_vendor = "apple")] + const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 32 } else { 16 }; + + // Works for FreeBSD stable (13.3, 13.4) and current (14.0, 14.1). + // The size of the structure has stayed the same for a long time, + // at least since 2005: + // https://lists.freebsd.org/pipermail/freebsd-stable/2005-November/019899.html + #[cfg(target_os = "freebsd")] + const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 1088 } else { 768 }; + #[cfg(target_os = "freebsd")] + const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 368 } else { 296 }; + + pub(super) fn is_debugger_present() -> Option { + debug_assert_ne!(KINFO_PROC_SIZE, 0); + + let mut flags = [0u8; 4]; // `ki_flag` under FreeBSD and `p_flag` under macOS. + let mut mib = [CTL_KERN, KERN_PROC, KERN_PROC_PID, process::id() as c_int]; + let mut info_size = KINFO_PROC_SIZE; + let mut kinfo_proc = [0u8; KINFO_PROC_SIZE]; + + // SAFETY: No state is shared with other threads. The sysctl call + // is safe according to the documentation. + if unsafe { + sysctl( + mib.as_mut_ptr(), + mib.len() as u32, + kinfo_proc.as_mut_ptr().cast(), + &mut info_size, + core::ptr::null_mut(), + 0, + ) + } != 0 + { + return None; + } + debug_assert_eq!(info_size, KINFO_PROC_SIZE); + + let mut reader = Cursor::new(kinfo_proc); + reader.seek(SeekFrom::Start(KINFO_PROC_FLAGS_OFFSET)).ok()?; + reader.read_exact(&mut flags).ok()?; + // Just in case, not limiting this to the little-endian systems. + let flags = i32::from_ne_bytes(flags); + + if flags & P_TRACED != 0 { + Some(DebuggerPresence::Detected) + } else { + Some(DebuggerPresence::NotDetected) + } + } +} + +#[cfg(not(any(target_os = "windows", target_vendor = "apple", target_os = "freebsd")))] +mod os { + pub(super) fn is_debugger_present() -> Option { + None + } +} + +/// Detect the debugger presence. +/// +/// The code does not try to detect the debugger at all costs (e.g., when anti-debugger +/// tricks are at play), it relies on the interfaces provided by the OS. +/// +/// Return value: +/// * `None`: it's not possible to conclude whether the debugger is attached to this +/// process or not. When checking for the presence of the debugger, the detection logic +/// encountered an issue, such as the OS API throwing an error or the feature not being +/// implemented. +/// * `Some(DebuggerPresence::Detected)`: yes, the debugger is attached +/// to this process. +/// * `Some(DebuggerPresence::NotDetected)`: no, the debugger is not +/// attached to this process. +pub(crate) fn is_debugger_present() -> Option { + if cfg!(miri) { None } else { os::is_debugger_present() } +} + +/// Execute the breakpoint instruction if the debugger presence is detected. +/// Useful for breaking into the debugger without the need to set a breakpoint +/// in the debugger. +/// +/// Note that there is a race between attaching or detaching the debugger, and running the +/// breakpoint instruction. This is nonetheless memory-safe, like [`crate::process::abort`] +/// is. In case the debugger is attached and the function is about +/// to run the breakpoint instruction yet right before that the debugger detaches, the +/// process will crash due to running the breakpoint instruction and the debugger not +/// handling the trap exception. +pub(crate) fn breakpoint_if_debugging() -> Option { + let debugger_present = is_debugger_present(); + if let Some(DebuggerPresence::Detected) = debugger_present { + // SAFETY: Executing the breakpoint instruction. No state is shared + // or modified by this code. + unsafe { core::intrinsics::breakpoint() }; + } + + debugger_present +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 1ef17dd530fd2..df25b84fbbe5a 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -11,9 +11,11 @@ mod personality; pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; +pub mod dbg; pub mod exit_guard; pub mod os_str; pub mod path; +pub mod random; pub mod sync; pub mod thread_local; diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 992767211d083..8e0609fe48c53 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -2,7 +2,6 @@ //! systems: just a `Vec`/`[u8]`. use core::clone::CloneToUninit; -use core::ptr::addr_of_mut; use crate::borrow::Cow; use crate::collections::TryReserveError; @@ -355,6 +354,6 @@ unsafe impl CloneToUninit for Slice { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around [u8] - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 433237aa6e7bf..b3834388df68a 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -1,13 +1,12 @@ //! The underlying OsString/OsStr implementation on Windows is a //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more. use core::clone::CloneToUninit; -use core::ptr::addr_of_mut; use crate::borrow::Cow; use crate::collections::TryReserveError; use crate::rc::Rc; use crate::sync::Arc; -use crate::sys_common::wtf8::{check_utf8_boundary, Wtf8, Wtf8Buf}; +use crate::sys_common::wtf8::{Wtf8, Wtf8Buf, check_utf8_boundary}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, mem}; @@ -278,6 +277,6 @@ unsafe impl CloneToUninit for Slice { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around Wtf8 - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/sys/pal/hermit/args.rs b/library/std/src/sys/pal/hermit/args.rs index 51afe3434aedc..4402426027730 100644 --- a/library/std/src/sys/pal/hermit/args.rs +++ b/library/std/src/sys/pal/hermit/args.rs @@ -1,4 +1,4 @@ -use crate::ffi::{c_char, CStr, OsString}; +use crate::ffi::{CStr, OsString, c_char}; use crate::os::hermit::ffi::OsStringExt; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicIsize, AtomicPtr}; diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index aaf1a044d0613..70f6981f7175b 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -1,7 +1,7 @@ use super::fd::FileDesc; use super::hermit_abi::{ - self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, - O_DIRECTORY, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, + self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, + O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct, }; use crate::ffi::{CStr, OsStr, OsString}; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 1f2e5d9469f5c..f49ef94717499 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -52,20 +52,6 @@ pub fn abort_internal() -> ! { unsafe { hermit_abi::abort() } } -pub fn hashmap_random_keys() -> (u64, u64) { - let mut buf = [0; 16]; - let mut slice = &mut buf[..]; - while !slice.is_empty() { - let res = cvt(unsafe { hermit_abi::read_entropy(slice.as_mut_ptr(), slice.len(), 0) }) - .expect("failed to generate random hashmap keys"); - slice = &mut slice[res as usize..]; - } - - let key1 = buf[..8].try_into().unwrap(); - let key2 = buf[8..].try_into().unwrap(); - (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2)) -} - // This function is needed by the panic runtime. The symbol is named in // pre-link args for the target specification, so keep that in sync. #[cfg(not(test))] diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs index 416469c003738..d9baa091a2321 100644 --- a/library/std/src/sys/pal/hermit/net.rs +++ b/library/std/src/sys/pal/hermit/net.rs @@ -192,7 +192,7 @@ impl Socket { buf.as_mut_ptr(), buf.len(), flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) })?; @@ -298,7 +298,7 @@ impl Socket { netc::ioctl( self.as_raw_fd(), netc::FIONBIO, - core::ptr::addr_of_mut!(nonblocking) as *mut core::ffi::c_void, + (&raw mut nonblocking) as *mut core::ffi::c_void, ) }) .map(drop) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 2c87c4860a27a..e0b6eb76b03af 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -2,7 +2,7 @@ use core::hash::{Hash, Hasher}; -use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME}; +use super::hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME, timespec}; use crate::cmp::Ordering; use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::time::Duration; @@ -107,8 +107,7 @@ pub struct Instant(Timespec); impl Instant { pub fn now() -> Instant { let mut time: Timespec = Timespec::zero(); - let _ = - unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) }; + let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) }; Instant(time) } @@ -209,8 +208,7 @@ impl SystemTime { pub fn now() -> SystemTime { let mut time: Timespec = Timespec::zero(); - let _ = - unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) }; + let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) }; SystemTime(time) } diff --git a/library/std/src/sys/pal/itron/task.rs b/library/std/src/sys/pal/itron/task.rs index 5da0c5917885f..49c420baca2f3 100644 --- a/library/std/src/sys/pal/itron/task.rs +++ b/library/std/src/sys/pal/itron/task.rs @@ -1,5 +1,5 @@ use super::abi; -use super::error::{fail, fail_aborting, ItronError}; +use super::error::{ItronError, fail, fail_aborting}; use crate::mem::MaybeUninit; /// Gets the ID of the task in Running state. Panics on failure. diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index 01e69afa99e13..04095e1a7cf99 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -1,7 +1,7 @@ //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and //! `exd_tsk` are available. -use super::error::{expect_success, expect_success_aborting, ItronError}; +use super::error::{ItronError, expect_success, expect_success_aborting}; use super::time::dur2reltims; use super::{abi, task}; use crate::cell::UnsafeCell; diff --git a/library/std/src/sys/pal/itron/time/tests.rs b/library/std/src/sys/pal/itron/time/tests.rs index d14035d9da49f..28db4f8b6799f 100644 --- a/library/std/src/sys/pal/itron/time/tests.rs +++ b/library/std/src/sys/pal/itron/time/tests.rs @@ -8,26 +8,24 @@ fn reltim2dur(t: u64) -> Duration { fn test_dur2reltims() { assert_eq!(dur2reltims(reltim2dur(0)).collect::>(), vec![]); assert_eq!(dur2reltims(reltim2dur(42)).collect::>(), vec![42]); - assert_eq!( - dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), - vec![abi::TMAX_RELTIM] - ); - assert_eq!( - dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), - vec![abi::TMAX_RELTIM, 10000] - ); + assert_eq!(dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), vec![ + abi::TMAX_RELTIM + ]); + assert_eq!(dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), vec![ + abi::TMAX_RELTIM, + 10000 + ]); } #[test] fn test_dur2tmos() { assert_eq!(dur2tmos(reltim2dur(0)).collect::>(), vec![0]); assert_eq!(dur2tmos(reltim2dur(42)).collect::>(), vec![42]); - assert_eq!( - dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), - vec![abi::TMAX_RELTIM] - ); - assert_eq!( - dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), - vec![abi::TMAX_RELTIM, 10000] - ); + assert_eq!(dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), vec![ + abi::TMAX_RELTIM + ]); + assert_eq!(dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), vec![ + abi::TMAX_RELTIM, + 10000 + ]); } diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index def1ccdf81ac0..90b9b59471a52 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -1,6 +1,6 @@ use crate::cmp; use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult}; -use crate::sys::rand::rdrand64; +use crate::random::{DefaultRandomSource, Random}; use crate::time::{Duration, Instant}; pub(crate) mod alloc; @@ -164,7 +164,7 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult { // trusted to ensure accurate timeouts. if let Ok(timeout_signed) = i64::try_from(timeout) { let tenth = timeout_signed / 10; - let deviation = (rdrand64() as i64).checked_rem(tenth).unwrap_or(0); + let deviation = i64::random(&mut DefaultRandomSource).checked_rem(tenth).unwrap_or(0); timeout = timeout_signed.saturating_add(deviation) as _; } } diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/tests.rs b/library/std/src/sys/pal/sgx/abi/usercalls/tests.rs index ef824d35f4a16..5978ae5a0fac9 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/tests.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/tests.rs @@ -1,4 +1,4 @@ -use super::alloc::{copy_from_userspace, copy_to_userspace, User}; +use super::alloc::{User, copy_from_userspace, copy_to_userspace}; #[test] fn test_copy_to_userspace_function() { diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 8d29b2ec6193e..586ccd18c2f57 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -132,24 +132,6 @@ pub extern "C" fn __rust_abort() { abort_internal(); } -pub mod rand { - pub fn rdrand64() -> u64 { - unsafe { - let mut ret: u64 = 0; - for _ in 0..10 { - if crate::arch::x86_64::_rdrand64_step(&mut ret) == 1 { - return ret; - } - } - rtabort!("Failed to obtain random data"); - } - } -} - -pub fn hashmap_random_keys() -> (u64, u64) { - (self::rand::rdrand64(), self::rand::rdrand64()) -} - pub use crate::sys_common::{AsInner, FromInner, IntoInner}; pub trait TryIntoInner: Sized { diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/pal/sgx/net.rs index f2e751c51194d..44913ffe3a9ff 100644 --- a/library/std/src/sys/pal/sgx/net.rs +++ b/library/std/src/sys/pal/sgx/net.rs @@ -3,7 +3,7 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sync::Arc; use crate::sys::fd::FileDesc; -use crate::sys::{sgx_ineffective, unsupported, AsInner, FromInner, IntoInner, TryIntoInner}; +use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported}; use crate::time::Duration; use crate::{error, fmt}; diff --git a/library/std/src/sys/pal/sgx/waitqueue/mod.rs b/library/std/src/sys/pal/sgx/waitqueue/mod.rs index bd114523fe80b..41d1413fcdee9 100644 --- a/library/std/src/sys/pal/sgx/waitqueue/mod.rs +++ b/library/std/src/sys/pal/sgx/waitqueue/mod.rs @@ -16,9 +16,9 @@ mod tests; mod spin_mutex; mod unsafe_list; -use fortanix_sgx_abi::{Tcs, EV_UNPARK, WAIT_INDEFINITE}; +use fortanix_sgx_abi::{EV_UNPARK, Tcs, WAIT_INDEFINITE}; -pub use self::spin_mutex::{try_lock_or_false, SpinMutex, SpinMutexGuard}; +pub use self::spin_mutex::{SpinMutex, SpinMutexGuard, try_lock_or_false}; use self::unsafe_list::{UnsafeList, UnsafeListEntry}; use super::abi::{thread, usercalls}; use crate::num::NonZero; diff --git a/library/std/src/sys/pal/solid/abi/fs.rs b/library/std/src/sys/pal/solid/abi/fs.rs index 394be15b0064b..6864a3e7745b9 100644 --- a/library/std/src/sys/pal/solid/abi/fs.rs +++ b/library/std/src/sys/pal/solid/abi/fs.rs @@ -1,8 +1,8 @@ //! `solid_fs.h` pub use libc::{ - ino_t, off_t, stat, time_t, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, - SEEK_CUR, SEEK_END, SEEK_SET, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFMT, S_IFREG, S_IWRITE, + O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFBLK, S_IFCHR, S_IFDIR, + S_IFIFO, S_IFMT, S_IFREG, S_IWRITE, SEEK_CUR, SEEK_END, SEEK_SET, ino_t, off_t, stat, time_t, }; use crate::os::raw::{c_char, c_int, c_uchar}; diff --git a/library/std/src/sys/pal/solid/abi/mod.rs b/library/std/src/sys/pal/solid/abi/mod.rs index 62cd86236bbd3..4d09705721748 100644 --- a/library/std/src/sys/pal/solid/abi/mod.rs +++ b/library/std/src/sys/pal/solid/abi/mod.rs @@ -4,7 +4,7 @@ mod fs; pub mod sockets; pub use self::fs::*; // `solid_types.h` -pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID}; +pub use super::itron::abi::{E_TMOUT, ER, ER_ID, ID}; pub const SOLID_ERR_NOTFOUND: ER = -1000; pub const SOLID_ERR_NOTSUPPORTED: ER = -1001; diff --git a/library/std/src/sys/pal/solid/error.rs b/library/std/src/sys/pal/solid/error.rs index 66c4d8a0ea27a..e092497856d43 100644 --- a/library/std/src/sys/pal/solid/error.rs +++ b/library/std/src/sys/pal/solid/error.rs @@ -1,4 +1,4 @@ -pub use self::itron::error::{expect_success, ItronError as SolidError}; +pub use self::itron::error::{ItronError as SolidError, expect_success}; use super::{abi, itron, net}; use crate::io::ErrorKind; diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs index 591be66fcb463..bce9aa6d99cd1 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/pal/solid/fs.rs @@ -538,7 +538,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { } }; // ignore internal NotFound errors - if let Err(err) = result + if let Err(err) = &result && err.kind() != io::ErrorKind::NotFound { return result; diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 6ebcf5b7c48c8..d41042be51844 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -62,13 +62,3 @@ pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { pub fn abort_internal() -> ! { unsafe { libc::abort() } } - -pub fn hashmap_random_keys() -> (u64, u64) { - unsafe { - let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit(); - let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16); - assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {result}"); - let [x1, x2] = out.assume_init(); - (x1, x2) - } -} diff --git a/library/std/src/sys/pal/solid/net.rs b/library/std/src/sys/pal/solid/net.rs index b6a31395095d9..c0818ecd856d2 100644 --- a/library/std/src/sys/pal/solid/net.rs +++ b/library/std/src/sys/pal/solid/net.rs @@ -1,6 +1,6 @@ use libc::{c_int, c_void, size_t}; -use self::netc::{sockaddr, socklen_t, MSG_PEEK}; +use self::netc::{MSG_PEEK, sockaddr, socklen_t}; use super::abi; use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 00e3860424006..60a227afb84e3 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -6,8 +6,6 @@ #![allow(unused_variables)] #![allow(dead_code)] -pub use self::rand::hashmap_random_keys; - #[path = "../unsupported/args.rs"] pub mod args; #[path = "../unsupported/env.rs"] @@ -23,7 +21,6 @@ pub mod os; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -mod rand; pub mod stdio; pub mod thread; #[allow(non_upper_case_globals)] diff --git a/library/std/src/sys/pal/teeos/rand.rs b/library/std/src/sys/pal/teeos/rand.rs deleted file mode 100644 index b45c3bb40e782..0000000000000 --- a/library/std/src/sys/pal/teeos/rand.rs +++ /dev/null @@ -1,21 +0,0 @@ -pub fn hashmap_random_keys() -> (u64, u64) { - const KEY_LEN: usize = core::mem::size_of::(); - - let mut v = [0u8; KEY_LEN * 2]; - imp::fill_bytes(&mut v); - - let key1 = v[0..KEY_LEN].try_into().unwrap(); - let key2 = v[KEY_LEN..].try_into().unwrap(); - - (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2)) -} - -mod imp { - extern "C" { - fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t); - } - - pub fn fill_bytes(v: &mut [u8]) { - unsafe { TEE_GenerateRandom(v.as_mut_ptr() as _, v.len() * crate::mem::size_of::()) } - } -} diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 4031d33ba8066..bd8a6684b64f9 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -14,7 +14,7 @@ use r_efi::protocols::{device_path, device_path_to_text}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_io_error}; -use crate::mem::{size_of, MaybeUninit}; +use crate::mem::{MaybeUninit, size_of}; use crate::os::uefi::env::boot_services; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::os::uefi::{self}; diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index ac22f4ded8855..c0ab52f650aa5 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -179,39 +179,6 @@ pub extern "C" fn __rust_abort() { abort_internal(); } -#[inline] -pub fn hashmap_random_keys() -> (u64, u64) { - get_random().unwrap() -} - -fn get_random() -> Option<(u64, u64)> { - use r_efi::protocols::rng; - - let mut buf = [0u8; 16]; - let handles = helpers::locate_handles(rng::PROTOCOL_GUID).ok()?; - for handle in handles { - if let Ok(protocol) = helpers::open_protocol::(handle, rng::PROTOCOL_GUID) { - let r = unsafe { - ((*protocol.as_ptr()).get_rng)( - protocol.as_ptr(), - crate::ptr::null_mut(), - buf.len(), - buf.as_mut_ptr(), - ) - }; - if r.is_error() { - continue; - } else { - return Some(( - u64::from_le_bytes(buf[..8].try_into().ok()?), - u64::from_le_bytes(buf[8..].try_into().ok()?), - )); - } - } - } - None -} - /// Disable access to BootServices if `EVT_SIGNAL_EXIT_BOOT_SERVICES` is signaled extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) { uefi::env::disable_boot_services(); diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index 4d2d7264704b2..9aee67d622fad 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -1,7 +1,7 @@ -use r_efi::efi::protocols::{device_path, loaded_image_device_path}; use r_efi::efi::Status; +use r_efi::efi::protocols::{device_path, loaded_image_device_path}; -use super::{helpers, unsupported, RawOsError}; +use super::{RawOsError, helpers, unsupported}; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index fdc5f5d7e4fea..0cc9cecb89db0 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -470,7 +470,7 @@ mod uefi_command_internal { let st_size = unsafe { (*self.st.as_ptr()).hdr.header_size as usize }; let mut crc32: u32 = 0; - // Set crc to 0 before calcuation + // Set crc to 0 before calculation unsafe { (*self.st.as_mut_ptr()).hdr.crc32 = 0; } diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs index 9a37e1a0346d7..8438a61e90feb 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/pal/unix/args.rs @@ -112,6 +112,8 @@ impl DoubleEndedIterator for Args { target_os = "aix", target_os = "nto", target_os = "hurd", + target_os = "rtems", + target_os = "nuttx", ))] mod imp { use crate::ffi::c_char; diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/pal/unix/env.rs index fb1f868644d48..2aee0b5d46056 100644 --- a/library/std/src/sys/pal/unix/env.rs +++ b/library/std/src/sys/pal/unix/env.rs @@ -240,6 +240,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "rtems")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "rtems"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "vxworks")] pub mod os { pub const FAMILY: &str = "unix"; @@ -272,3 +283,14 @@ pub mod os { pub const EXE_SUFFIX: &str = ""; pub const EXE_EXTENSION: &str = ""; } + +#[cfg(target_os = "nuttx")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "nuttx"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index d8e239ee23ed5..6a28799ca55eb 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -3,14 +3,6 @@ #[cfg(test)] mod tests; -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "emscripten", - target_os = "l4re", - target_os = "hurd", -))] -use libc::off64_t; #[cfg(not(any( target_os = "linux", target_os = "emscripten", @@ -19,6 +11,14 @@ use libc::off64_t; target_os = "hurd", )))] use libc::off_t as off64_t; +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "emscripten", + target_os = "l4re", + target_os = "hurd", +))] +use libc::off64_t; use crate::cmp; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; @@ -98,7 +98,12 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))] + #[cfg(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + )))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let ret = cvt(unsafe { libc::readv( @@ -110,14 +115,24 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] + #[cfg(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + ))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { io::default_read_vectored(|b| self.read(b), bufs) } #[inline] pub fn is_read_vectored(&self) -> bool { - cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))) + cfg!(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + ))) } pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { @@ -297,7 +312,12 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))] + #[cfg(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + )))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { let ret = cvt(unsafe { libc::writev( @@ -309,14 +329,24 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] + #[cfg(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + ))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { io::default_write_vectored(|b| self.write(b), bufs) } #[inline] pub fn is_write_vectored(&self) -> bool { - cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))) + cfg!(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + ))) } #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 7fa147c9754b9..39aabf0b2d679 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -31,10 +31,6 @@ use libc::fstatat64; all(target_os = "linux", target_env = "musl"), ))] use libc::readdir as readdir64; -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] -use libc::readdir64; -#[cfg(any(target_os = "emscripten", target_os = "l4re"))] -use libc::readdir64_r; #[cfg(not(any( target_os = "android", target_os = "linux", @@ -50,6 +46,10 @@ use libc::readdir64_r; target_os = "hurd", )))] use libc::readdir_r as readdir64_r; +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] +use libc::readdir64; +#[cfg(any(target_os = "emscripten", target_os = "l4re"))] +use libc::readdir64_r; use libc::{c_int, mode_t}; #[cfg(target_os = "android")] use libc::{ @@ -478,6 +478,8 @@ impl FileAttr { target_os = "horizon", target_os = "vita", target_os = "hurd", + target_os = "rtems", + target_os = "nuttx", )))] pub fn modified(&self) -> io::Result { #[cfg(target_pointer_width = "32")] @@ -490,12 +492,17 @@ impl FileAttr { SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64) } - #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))] + #[cfg(any( + target_os = "vxworks", + target_os = "espidf", + target_os = "vita", + target_os = "rtems", + ))] pub fn modified(&self) -> io::Result { SystemTime::new(self.stat.st_mtime as i64, 0) } - #[cfg(any(target_os = "horizon", target_os = "hurd"))] + #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))] pub fn modified(&self) -> io::Result { SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64) } @@ -506,6 +513,8 @@ impl FileAttr { target_os = "horizon", target_os = "vita", target_os = "hurd", + target_os = "rtems", + target_os = "nuttx", )))] pub fn accessed(&self) -> io::Result { #[cfg(target_pointer_width = "32")] @@ -518,12 +527,17 @@ impl FileAttr { SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64) } - #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))] + #[cfg(any( + target_os = "vxworks", + target_os = "espidf", + target_os = "vita", + target_os = "rtems" + ))] pub fn accessed(&self) -> io::Result { SystemTime::new(self.stat.st_atime as i64, 0) } - #[cfg(any(target_os = "horizon", target_os = "hurd"))] + #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))] pub fn accessed(&self) -> io::Result { SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64) } @@ -726,7 +740,7 @@ impl Iterator for ReadDir { // // Like for uninitialized contents, converting entry_ptr to `&dirent64` // would not be legal. However, unique to dirent64 is that we don't even - // get to use `addr_of!((*entry_ptr).d_name)` because that operation + // get to use `&raw const (*entry_ptr).d_name` because that operation // requires the full extent of *entry_ptr to be in bounds of the same // allocation, which is not necessarily the case here. // @@ -740,7 +754,7 @@ impl Iterator for ReadDir { } else { #[allow(deref_nullptr)] { - ptr::addr_of!((*ptr::null::()).$field) + &raw const (*ptr::null::()).$field } } }}; @@ -853,6 +867,8 @@ impl Drop for Dir { target_os = "fuchsia", target_os = "horizon", target_os = "vxworks", + target_os = "rtems", + target_os = "nuttx", )))] { let fd = unsafe { libc::dirfd(self.0) }; @@ -970,6 +986,7 @@ impl DirEntry { target_os = "aix", target_os = "nto", target_os = "hurd", + target_os = "rtems", target_vendor = "apple", ))] pub fn ino(&self) -> u64 { @@ -986,6 +1003,13 @@ impl DirEntry { self.entry.d_fileno as u64 } + #[cfg(target_os = "nuttx")] + pub fn ino(&self) -> u64 { + // Leave this 0 for now, as NuttX does not provide an inode number + // in its directory entries. + 0 + } + #[cfg(any( target_os = "netbsd", target_os = "openbsd", @@ -1313,7 +1337,8 @@ impl File { target_os = "redox", target_os = "espidf", target_os = "horizon", - target_os = "vxworks" + target_os = "vxworks", + target_os = "nuttx", )))] let to_timespec = |time: Option| match time { Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts), @@ -1328,7 +1353,7 @@ impl File { None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }), }; cfg_if::cfg_if! { - if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks"))] { + if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks", target_os = "nuttx"))] { // Redox doesn't appear to support `UTIME_OMIT`. // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore // the same as for Redox. @@ -1360,7 +1385,7 @@ impl File { } cvt(unsafe { libc::fsetattrlist( self.as_raw_fd(), - core::ptr::addr_of!(attrlist).cast::().cast_mut(), + (&raw const attrlist).cast::().cast_mut(), buf.as_ptr().cast::().cast_mut(), num_times * mem::size_of::(), 0 @@ -1717,7 +1742,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { run_path_with_cstr(original, &|original| { run_path_with_cstr(link, &|link| { cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nto"))] { + if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] { // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves // it implementation-defined whether `link` follows symlinks, so rely on the // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. @@ -1852,7 +1877,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let max_len = u64::MAX; let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; - use super::kernel_copy::{copy_regular_files, CopyResult}; + use super::kernel_copy::{CopyResult, copy_regular_files}; match copy_regular_files(reader.as_raw_fd(), writer.as_raw_fd(), max_len) { CopyResult::Ended(bytes) => Ok(bytes), @@ -1919,7 +1944,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { libc::copyfile_state_get( state.0, libc::COPYFILE_STATE_COPIED as u32, - core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void, + (&raw mut bytes_copied) as *mut libc::c_void, ) })?; Ok(bytes_copied as u64) @@ -1994,7 +2019,7 @@ mod remove_dir_impl { #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::{fdopendir, openat64 as openat, unlinkat}; - use super::{lstat, Dir, DirEntry, InnerReadDir, ReadDir}; + use super::{Dir, DirEntry, InnerReadDir, ReadDir, lstat}; use crate::ffi::CStr; use crate::io; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; diff --git a/library/std/src/sys/pal/unix/l4re.rs b/library/std/src/sys/pal/unix/l4re.rs index fe9559f2a569f..52d39dcfb16fb 100644 --- a/library/std/src/sys/pal/unix/l4re.rs +++ b/library/std/src/sys/pal/unix/l4re.rs @@ -54,6 +54,10 @@ pub mod net { unimpl!(); } + pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> { + unimpl!(); + } + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { unimpl!(); } diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs index 7474f80e94f9d..78744430f3b51 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd.rs @@ -13,7 +13,7 @@ pub(crate) struct PidFd(FileDesc); impl PidFd { pub fn kill(&self) -> io::Result<()> { - return cvt(unsafe { + cvt(unsafe { libc::syscall( libc::SYS_pidfd_send_signal, self.0.as_raw_fd(), @@ -22,7 +22,7 @@ impl PidFd { 0, ) }) - .map(drop); + .map(drop) } pub fn wait(&self) -> io::Result { @@ -30,7 +30,7 @@ impl PidFd { cvt(unsafe { libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, libc::WEXITED) })?; - return Ok(ExitStatus::from_waitid_siginfo(siginfo)); + Ok(ExitStatus::from_waitid_siginfo(siginfo)) } pub fn try_wait(&self) -> io::Result> { @@ -45,9 +45,10 @@ impl PidFd { ) })?; if unsafe { siginfo.si_pid() } == 0 { - return Ok(None); + Ok(None) + } else { + Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))) } - return Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))); } } diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index ba2f58f9c10bd..4fe18daa2040f 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -1,6 +1,5 @@ #![allow(missing_docs, nonstandard_style)] -pub use self::rand::hashmap_random_keys; use crate::io::ErrorKind; #[cfg(not(target_os = "espidf"))] @@ -26,7 +25,6 @@ pub use self::l4re::net; pub mod os; pub mod pipe; pub mod process; -pub mod rand; pub mod stack_overflow; pub mod stdio; pub mod thread; @@ -79,6 +77,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "l4re", target_os = "horizon", target_os = "vita", + target_os = "rtems", // The poll on Darwin doesn't set POLLNVAL for closed fds. target_vendor = "apple", )))] @@ -223,6 +222,7 @@ static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool = target_os = "horizon", target_os = "vxworks", target_os = "vita", + target_os = "nuttx", )))] pub(crate) fn on_broken_pipe_flag_used() -> bool { ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed) @@ -280,6 +280,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ETIMEDOUT => TimedOut, libc::ETXTBSY => ExecutableFileBusy, libc::EXDEV => CrossesDevices, + libc::EINPROGRESS => InProgress, libc::EACCES | libc::EPERM => PermissionDenied, @@ -425,7 +426,7 @@ cfg_if::cfg_if! { } } -#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] +#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] mod unsupported { use crate::io; diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index bc0e3f4eeeac8..6a67bb0a101e9 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK}; +use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t}; use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; @@ -38,19 +38,19 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { // We may need to trigger a glibc workaround. See on_resolver_failure() for details. on_resolver_failure(); - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] if err == libc::EAI_SYSTEM { return Err(io::Error::last_os_error()); } - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] let detail = unsafe { // We can't always expect a UTF-8 environment. When we don't get that luxury, // it's better to give a low-quality error message than none at all. CStr::from_ptr(libc::gai_strerror(err)).to_string_lossy() }; - #[cfg(target_os = "espidf")] + #[cfg(any(target_os = "espidf", target_os = "nuttx"))] let detail = ""; Err(io::Error::new( @@ -215,7 +215,7 @@ impl Socket { _ => { if cfg!(target_os = "vxworks") { // VxWorks poll does not return POLLHUP or POLLERR in revents. Check if the - // connnection actually succeeded and return ok only when the socket is + // connection actually succeeded and return ok only when the socket is // ready and no errors were found. if let Some(e) = self.take_error()? { return Err(e); @@ -329,7 +329,7 @@ impl Socket { buf.as_mut_ptr() as *mut c_void, buf.len(), flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) })?; diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index a785b97ac8dc5..f983d174ed61c 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -31,7 +31,7 @@ cfg_if::cfg_if! { } extern "C" { - #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] + #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] #[cfg_attr( any( target_os = "linux", @@ -48,6 +48,7 @@ extern "C" { target_os = "openbsd", target_os = "android", target_os = "redox", + target_os = "nuttx", target_env = "newlib" ), link_name = "__errno" @@ -61,13 +62,14 @@ extern "C" { } /// Returns the platform-specific value of errno -#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] +#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] pub fn errno() -> i32 { unsafe { (*errno_location()) as i32 } } /// Sets the platform-specific value of errno -#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! +// needed for readdir and syscall! +#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))] #[allow(dead_code)] // but not all target cfgs actually end up using it pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } @@ -78,6 +80,16 @@ pub fn errno() -> i32 { unsafe { libc::errnoGet() } } +#[cfg(target_os = "rtems")] +pub fn errno() -> i32 { + extern "C" { + #[thread_local] + static _tls_errno: c_int; + } + + unsafe { _tls_errno as i32 } +} + #[cfg(target_os = "dragonfly")] pub fn errno() -> i32 { extern "C" { @@ -388,6 +400,7 @@ pub fn current_exe() -> io::Result { target_os = "linux", target_os = "hurd", target_os = "android", + target_os = "nuttx", target_os = "emscripten" ))] pub fn current_exe() -> io::Result { @@ -472,7 +485,7 @@ pub fn current_exe() -> io::Result { } } -#[cfg(target_os = "redox")] +#[cfg(any(target_os = "redox", target_os = "rtems"))] pub fn current_exe() -> io::Result { crate::fs::read_to_string("sys:exe").map(PathBuf::from) } @@ -599,7 +612,7 @@ pub unsafe fn environ() -> *mut *const *const c_char { extern "C" { static mut environ: *const *const c_char; } - ptr::addr_of_mut!(environ) + &raw mut environ } static ENV_LOCK: RwLock<()> = RwLock::new(()); @@ -706,6 +719,7 @@ pub fn home_dir() -> Option { target_os = "espidf", target_os = "horizon", target_os = "vita", + target_os = "nuttx", all(target_vendor = "apple", not(target_os = "macos")), ))] unsafe fn fallback() -> Option { @@ -719,6 +733,7 @@ pub fn home_dir() -> Option { target_os = "espidf", target_os = "horizon", target_os = "vita", + target_os = "nuttx", all(target_vendor = "apple", not(target_os = "macos")), )))] unsafe fn fallback() -> Option { diff --git a/library/std/src/sys/pal/unix/process/mod.rs b/library/std/src/sys/pal/unix/process/mod.rs index 074f0a105e329..2751d51c44d2a 100644 --- a/library/std/src/sys/pal/unix/process/mod.rs +++ b/library/std/src/sys/pal/unix/process/mod.rs @@ -2,10 +2,10 @@ pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes pub use self::process_inner::{ExitStatus, ExitStatusError, Process}; pub use crate::ffi::OsString as EnvKey; -#[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))] +#[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))] mod process_common; -#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] +#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] mod process_unsupported; cfg_if::cfg_if! { @@ -16,7 +16,7 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "vxworks")] { #[path = "process_vxworks.rs"] mod process_inner; - } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] { + } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] { mod process_inner { pub use super::process_unsupported::*; } diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs index fec825054195a..d9c41d4348756 100644 --- a/library/std/src/sys/pal/unix/process/process_common.rs +++ b/library/std/src/sys/pal/unix/process/process_common.rs @@ -1,7 +1,7 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; -use libc::{c_char, c_int, gid_t, pid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS}; +use libc::{EXIT_FAILURE, EXIT_SUCCESS, c_char, c_int, gid_t, pid_t, uid_t}; use crate::collections::BTreeMap; use crate::ffi::{CStr, CString, OsStr, OsString}; diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs index f3d5fdec4c291..5d0110cf55dcb 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -2,7 +2,7 @@ use libc::{c_int, size_t}; use crate::num::NonZero; use crate::sys::process::process_common::*; -use crate::sys::process::zircon::{zx_handle_t, Handle}; +use crate::sys::process::zircon::{Handle, zx_handle_t}; use crate::{fmt, io, mem, ptr}; //////////////////////////////////////////////////////////////////////////////// @@ -178,7 +178,7 @@ impl Process { zx_cvt(zx_object_get_info( self.handle.raw(), ZX_INFO_PROCESS, - core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void, + (&raw mut proc_info) as *mut libc::c_void, mem::size_of::(), &mut actual, &mut avail, @@ -215,7 +215,7 @@ impl Process { zx_cvt(zx_object_get_info( self.handle.raw(), ZX_INFO_PROCESS, - core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void, + (&raw mut proc_info) as *mut libc::c_void, mem::size_of::(), &mut actual, &mut avail, diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 9d091f033e07f..5d30f388da18e 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -788,15 +788,15 @@ impl Command { let mut iov = [IoSlice::new(b"")]; let mut msg: libc::msghdr = mem::zeroed(); - msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _; + msg.msg_iov = (&raw mut iov) as *mut _; msg.msg_iovlen = 1; // only attach cmsg if we successfully acquired the pidfd if pidfd >= 0 { msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _; - msg.msg_control = core::ptr::addr_of_mut!(cmsg.buf) as *mut _; + msg.msg_control = (&raw mut cmsg.buf) as *mut _; - let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _); + let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _); (*hdr).cmsg_level = SOL_SOCKET; (*hdr).cmsg_type = SCM_RIGHTS; (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _; @@ -838,17 +838,17 @@ impl Command { let mut msg: libc::msghdr = mem::zeroed(); - msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _; + msg.msg_iov = (&raw mut iov) as *mut _; msg.msg_iovlen = 1; msg.msg_controllen = mem::size_of::() as _; - msg.msg_control = core::ptr::addr_of_mut!(cmsg) as *mut _; + msg.msg_control = (&raw mut cmsg) as *mut _; match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) { Err(_) => return -1, Ok(_) => {} } - let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _); + let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _); if hdr.is_null() || (*hdr).cmsg_level != SOL_SOCKET || (*hdr).cmsg_type != SCM_RIGHTS @@ -1089,13 +1089,13 @@ fn signal_string(signal: i32) -> &'static str { libc::SIGURG => " (SIGURG)", #[cfg(not(target_os = "l4re"))] libc::SIGXCPU => " (SIGXCPU)", - #[cfg(not(target_os = "l4re"))] + #[cfg(not(any(target_os = "l4re", target_os = "rtems")))] libc::SIGXFSZ => " (SIGXFSZ)", - #[cfg(not(target_os = "l4re"))] + #[cfg(not(any(target_os = "l4re", target_os = "rtems")))] libc::SIGVTALRM => " (SIGVTALRM)", #[cfg(not(target_os = "l4re"))] libc::SIGPROF => " (SIGPROF)", - #[cfg(not(target_os = "l4re"))] + #[cfg(not(any(target_os = "l4re", target_os = "rtems")))] libc::SIGWINCH => " (SIGWINCH)", #[cfg(not(any(target_os = "haiku", target_os = "l4re")))] libc::SIGIO => " (SIGIO)", @@ -1190,8 +1190,8 @@ impl ExitStatusError { mod linux_child_ext { use crate::os::linux::process as os; - use crate::sys::pal::unix::linux::pidfd as imp; use crate::sys::pal::unix::ErrorKind; + use crate::sys::pal::unix::linux::pidfd as imp; use crate::sys_common::FromInner; use crate::{io, mem}; diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs index 0477b3d9a70da..2d9a304c49512 100644 --- a/library/std/src/sys/pal/unix/process/process_vxworks.rs +++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs @@ -1,5 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use libc::{self, c_char, c_int, RTP_ID}; +use libc::{self, RTP_ID, c_char, c_int}; use crate::io::{self, ErrorKind}; use crate::num::NonZero; diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs deleted file mode 100644 index cc0852aab4396..0000000000000 --- a/library/std/src/sys/pal/unix/rand.rs +++ /dev/null @@ -1,302 +0,0 @@ -pub fn hashmap_random_keys() -> (u64, u64) { - const KEY_LEN: usize = core::mem::size_of::(); - - let mut v = [0u8; KEY_LEN * 2]; - if let Err(err) = read(&mut v) { - panic!("failed to retrieve random hash map seed: {err}"); - } - - let key1 = v[0..KEY_LEN].try_into().unwrap(); - let key2 = v[KEY_LEN..].try_into().unwrap(); - - (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2)) -} - -cfg_if::cfg_if! { - if #[cfg(any( - target_vendor = "apple", - target_os = "openbsd", - target_os = "emscripten", - target_os = "vita", - all(target_os = "netbsd", not(netbsd10)), - target_os = "fuchsia", - target_os = "vxworks", - ))] { - // Some systems have a syscall that directly retrieves random data. - // If that is guaranteed to be available, use it. - use imp::syscall as read; - } else { - // Otherwise, try the syscall to see if it exists only on some systems - // and fall back to reading from the random device otherwise. - fn read(bytes: &mut [u8]) -> crate::io::Result<()> { - use crate::fs::File; - use crate::io::Read; - use crate::sync::OnceLock; - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "espidf", - target_os = "horizon", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "solaris", - target_os = "illumos", - netbsd10, - ))] - if let Some(res) = imp::syscall(bytes) { - return res; - } - - const PATH: &'static str = if cfg!(target_os = "redox") { - "/scheme/rand" - } else { - "/dev/urandom" - }; - - static FILE: OnceLock = OnceLock::new(); - - FILE.get_or_try_init(|| File::open(PATH))?.read_exact(bytes) - } - } -} - -// All these systems a `getrandom` syscall. -// -// It is not guaranteed to be available, so return None to fallback to the file -// implementation. -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "espidf", - target_os = "horizon", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "solaris", - target_os = "illumos", - netbsd10, -))] -mod imp { - use crate::io::{Error, Result}; - use crate::sync::atomic::{AtomicBool, Ordering}; - use crate::sys::os::errno; - - #[cfg(any(target_os = "linux", target_os = "android"))] - fn getrandom(buf: &mut [u8]) -> libc::ssize_t { - use crate::sys::weak::syscall; - - // A weak symbol allows interposition, e.g. for perf measurements that want to - // disable randomness for consistency. Otherwise, we'll try a raw syscall. - // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28) - syscall! { - fn getrandom( - buffer: *mut libc::c_void, - length: libc::size_t, - flags: libc::c_uint - ) -> libc::ssize_t - } - - // This provides the best quality random numbers available at the given moment - // without ever blocking, and is preferable to falling back to /dev/urandom. - static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true); - if GRND_INSECURE_AVAILABLE.load(Ordering::Relaxed) { - let ret = unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_INSECURE) }; - if ret == -1 && errno() as libc::c_int == libc::EINVAL { - GRND_INSECURE_AVAILABLE.store(false, Ordering::Relaxed); - } else { - return ret; - } - } - - unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) } - } - - #[cfg(any( - target_os = "dragonfly", - target_os = "espidf", - target_os = "horizon", - target_os = "freebsd", - netbsd10, - target_os = "illumos", - target_os = "solaris" - ))] - fn getrandom(buf: &mut [u8]) -> libc::ssize_t { - unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } - } - - pub fn syscall(v: &mut [u8]) -> Option> { - static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false); - - if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) { - return None; - } - - let mut read = 0; - while read < v.len() { - let result = getrandom(&mut v[read..]); - if result == -1 { - let err = errno() as libc::c_int; - if err == libc::EINTR { - continue; - } else if err == libc::ENOSYS || err == libc::EPERM { - // `getrandom` is not supported on the current system. - // - // Also fall back in case it is disabled by something like - // seccomp or inside of docker. - // - // If the `getrandom` syscall is not implemented in the current kernel version it should return an - // `ENOSYS` error. Docker also blocks the whole syscall inside unprivileged containers, and - // returns `EPERM` (instead of `ENOSYS`) when a program tries to invoke the syscall. Because of - // that we need to check for *both* `ENOSYS` and `EPERM`. - // - // Note that Docker's behavior is breaking other projects (notably glibc), so they're planning - // to update their filtering to return `ENOSYS` in a future release: - // - // https://github.com/moby/moby/issues/42680 - // - GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed); - return None; - } else if err == libc::EAGAIN { - // getrandom has failed because it would have blocked as the - // non-blocking pool (urandom) has not been initialized in - // the kernel yet due to a lack of entropy. Fallback to - // reading from `/dev/urandom` which will return potentially - // insecure random data to avoid blocking applications which - // could depend on this call without ever knowing they do and - // don't have a work around. - return None; - } else { - return Some(Err(Error::from_raw_os_error(err))); - } - } else { - read += result as usize; - } - } - - Some(Ok(())) - } -} - -#[cfg(any( - target_os = "macos", // Supported since macOS 10.12+. - target_os = "openbsd", - target_os = "emscripten", - target_os = "vita", -))] -mod imp { - use crate::io::{Error, Result}; - - pub fn syscall(v: &mut [u8]) -> Result<()> { - // getentropy(2) permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let ret = unsafe { libc::getentropy(s.as_mut_ptr().cast(), s.len()) }; - if ret == -1 { - return Err(Error::last_os_error()); - } - } - - Ok(()) - } -} - -// On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply -// call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes` -// manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on -// its own thread accessed via GCD. This seems needlessly heavyweight for our purposes -// so we only use it when `getentropy` is blocked, which appears to be the case -// on all platforms except macOS (see #102643). -// -// `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible -// via `libSystem` (libc) while the other needs to link to `Security.framework`. -#[cfg(all(target_vendor = "apple", not(target_os = "macos")))] -mod imp { - use libc::size_t; - - use crate::ffi::{c_int, c_void}; - use crate::io::{Error, Result}; - - pub fn syscall(v: &mut [u8]) -> Result<()> { - extern "C" { - fn CCRandomGenerateBytes(bytes: *mut c_void, count: size_t) -> c_int; - } - - let ret = unsafe { CCRandomGenerateBytes(v.as_mut_ptr().cast(), v.len()) }; - if ret != -1 { Ok(()) } else { Err(Error::last_os_error()) } - } -} - -// FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification. -#[cfg(all(target_os = "netbsd", not(netbsd10)))] -mod imp { - use crate::io::{Error, Result}; - use crate::ptr; - - pub fn syscall(v: &mut [u8]) -> Result<()> { - let mib = [libc::CTL_KERN, libc::KERN_ARND]; - // kern.arandom permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let mut s_len = s.len(); - let ret = unsafe { - libc::sysctl( - mib.as_ptr(), - mib.len() as libc::c_uint, - s.as_mut_ptr() as *mut _, - &mut s_len, - ptr::null(), - 0, - ) - }; - if ret == -1 { - return Err(Error::last_os_error()); - } else if s_len != s.len() { - // FIXME(joboet): this can't actually happen, can it? - panic!("read less bytes than requested from kern.arandom"); - } - } - - Ok(()) - } -} - -#[cfg(target_os = "fuchsia")] -mod imp { - use crate::io::Result; - - #[link(name = "zircon")] - extern "C" { - fn zx_cprng_draw(buffer: *mut u8, len: usize); - } - - pub fn syscall(v: &mut [u8]) -> Result<()> { - unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }; - Ok(()) - } -} - -#[cfg(target_os = "vxworks")] -mod imp { - use core::sync::atomic::AtomicBool; - use core::sync::atomic::Ordering::Relaxed; - - use crate::io::{Error, Result}; - - pub fn syscall(v: &mut [u8]) -> Result<()> { - static RNG_INIT: AtomicBool = AtomicBool::new(false); - while !RNG_INIT.load(Relaxed) { - let ret = unsafe { libc::randSecure() }; - if ret < 0 { - return Err(Error::last_os_error()); - } else if ret > 0 { - RNG_INIT.store(true, Relaxed); - break; - } - - unsafe { libc::usleep(10) }; - } - - let ret = unsafe { - libc::randABytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int) - }; - if ret >= 0 { Ok(()) } else { Err(Error::last_os_error()) } - } -} diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 9ff44b54c41a1..ac0858e1de876 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -32,24 +32,24 @@ impl Drop for Handler { target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris" + target_os = "solaris", + target_os = "illumos", ))] mod imp { + use libc::{ + MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SA_ONSTACK, + SA_SIGINFO, SIG_DFL, SIGBUS, SIGSEGV, SS_DISABLE, sigaction, sigaltstack, sighandler_t, + }; #[cfg(not(all(target_os = "linux", target_env = "gnu")))] use libc::{mmap as mmap64, mprotect, munmap}; #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::{mmap64, mprotect, munmap}; - use libc::{ - sigaction, sigaltstack, sighandler_t, MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, - PROT_NONE, PROT_READ, PROT_WRITE, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIGSEGV, SIG_DFL, - SS_DISABLE, - }; use super::Handler; use crate::cell::Cell; use crate::ops::Range; - use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}; use crate::sync::OnceLock; + use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}; use crate::sys::pal::unix::os; use crate::{io, mem, ptr, thread}; @@ -280,7 +280,7 @@ mod imp { libc::SIGSTKSZ } - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris", target_os = "illumos"))] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut current_stack: libc::stack_t = crate::mem::zeroed(); assert_eq!(libc::stack_getbounds(&mut current_stack), 0); @@ -426,8 +426,8 @@ mod imp { match sysctlbyname.get() { Some(fcn) if unsafe { fcn(oid.as_ptr(), - ptr::addr_of_mut!(guard).cast(), - ptr::addr_of_mut!(size), + (&raw mut guard).cast(), + &raw mut size, ptr::null_mut(), 0) == 0 } => guard, @@ -486,7 +486,12 @@ mod imp { Some(guardaddr..guardaddr + page_size) } - #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "macos", + target_os = "openbsd", + target_os = "solaris", + target_os = "illumos", + ))] // FIXME: I am probably not unsafe. unsafe fn current_guard() -> Option> { let stackptr = get_stack_start()?; @@ -569,7 +574,8 @@ mod imp { target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris" + target_os = "solaris", + target_os = "illumos", )))] mod imp { pub unsafe fn init() {} diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index c9dcc5ad97a50..2f2d6e6add396 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -140,7 +140,12 @@ impl Thread { } } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "nuttx" + ))] pub fn set_name(name: &CStr) { unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); @@ -253,7 +258,7 @@ impl Thread { tv_nsec: nsecs, }; secs -= ts.tv_sec as u64; - let ts_ptr = core::ptr::addr_of_mut!(ts); + let ts_ptr = &raw mut ts; if libc::nanosleep(ts_ptr, ts_ptr) == -1 { assert_eq!(os::errno(), libc::EINTR); secs += ts.tv_sec as u64; @@ -442,8 +447,8 @@ pub fn available_parallelism() -> io::Result> { libc::sysctl( mib.as_mut_ptr(), 2, - core::ptr::addr_of_mut!(cpus) as *mut _, - core::ptr::addr_of_mut!(cpus_size) as *mut _, + (&raw mut cpus) as *mut _, + (&raw mut cpus_size) as *mut _, ptr::null_mut(), 0, ) @@ -516,8 +521,8 @@ mod cgroups { use crate::borrow::Cow; use crate::ffi::OsString; - use crate::fs::{exists, File}; - use crate::io::{BufRead, BufReader, Read}; + use crate::fs::{File, exists}; + use crate::io::{BufRead, Read}; use crate::os::unix::ffi::OsStringExt; use crate::path::{Path, PathBuf}; use crate::str::from_utf8; @@ -690,7 +695,7 @@ mod cgroups { /// If the cgroupfs is a bind mount then `group_path` is adjusted to skip /// over the already-included prefix fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> { - let mut reader = BufReader::new(File::open("/proc/self/mountinfo").ok()?); + let mut reader = File::open_buffered("/proc/self/mountinfo").ok()?; let mut line = String::with_capacity(256); loop { line.clear(); @@ -747,12 +752,15 @@ unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { } // No point in looking up __pthread_get_minstack() on non-glibc platforms. -#[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))] +#[cfg(all( + not(all(target_os = "linux", target_env = "gnu")), + not(any(target_os = "netbsd", target_os = "nuttx")) +))] unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { libc::PTHREAD_STACK_MIN } -#[cfg(target_os = "netbsd")] +#[cfg(any(target_os = "netbsd", target_os = "nuttx"))] unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { static STACK: crate::sync::OnceLock = crate::sync::OnceLock::new(); diff --git a/library/std/src/sys/pal/unix/thread_parking.rs b/library/std/src/sys/pal/unix/thread_parking.rs index 1da5fce3cd30f..72dd2031479ee 100644 --- a/library/std/src/sys/pal/unix/thread_parking.rs +++ b/library/std/src/sys/pal/unix/thread_parking.rs @@ -2,7 +2,7 @@ // separate modules for each platform. #![cfg(target_os = "netbsd")] -use libc::{_lwp_self, c_long, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC}; +use libc::{_lwp_self, CLOCK_MONOTONIC, c_long, clockid_t, lwpid_t, time_t, timespec}; use crate::ffi::{c_int, c_void}; use crate::ptr; diff --git a/library/std/src/sys/pal/unsupported/common.rs b/library/std/src/sys/pal/unsupported/common.rs index 76f80291f0ea8..34a766683830d 100644 --- a/library/std/src/sys/pal/unsupported/common.rs +++ b/library/std/src/sys/pal/unsupported/common.rs @@ -27,7 +27,3 @@ pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { pub fn abort_internal() -> ! { core::intrinsics::abort(); } - -pub fn hashmap_random_keys() -> (u64, u64) { - (1, 2) -} diff --git a/library/std/src/sys/pal/unsupported/process.rs b/library/std/src/sys/pal/unsupported/process.rs index 40231bfc90b1e..fee81744f09ec 100644 --- a/library/std/src/sys/pal/unsupported/process.rs +++ b/library/std/src/sys/pal/unsupported/process.rs @@ -255,11 +255,11 @@ impl ExitStatusError { } #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); +pub struct ExitCode(u8); impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); + pub const SUCCESS: ExitCode = ExitCode(0); + pub const FAILURE: ExitCode = ExitCode(1); pub fn as_i32(&self) -> i32 { self.0 as i32 @@ -268,10 +268,7 @@ impl ExitCode { impl From for ExitCode { fn from(code: u8) -> Self { - match code { - 0 => Self::SUCCESS, - 1..=255 => Self::FAILURE, - } + Self(code) } } diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 88b1e543ec7c2..59ecc45b06a1f 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -13,7 +13,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::time::SystemTime; use crate::sys::unsupported; pub use crate::sys_common::fs::exists; -use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound}; use crate::{fmt, iter, ptr}; pub struct File { @@ -265,7 +265,7 @@ impl OpenOptions { pub fn new() -> OpenOptions { let mut base = OpenOptions::default(); base.dirflags = wasi::LOOKUPFLAGS_SYMLINK_FOLLOW; - return base; + base } pub fn read(&mut self, read: bool) { @@ -382,7 +382,7 @@ impl OpenOptions { base |= wasi::RIGHTS_PATH_UNLINK_FILE; base |= wasi::RIGHTS_POLL_FD_READWRITE; - return base; + base } fn rights_inheriting(&self) -> wasi::Rights { diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs index d047bf2fce857..404747f0dc756 100644 --- a/library/std/src/sys/pal/wasi/helpers.rs +++ b/library/std/src/sys/pal/wasi/helpers.rs @@ -1,6 +1,6 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use crate::{io as std_io, mem}; +use crate::io as std_io; #[inline] pub fn is_interrupted(errno: i32) -> bool { @@ -108,16 +108,6 @@ pub fn abort_internal() -> ! { unsafe { libc::abort() } } -pub fn hashmap_random_keys() -> (u64, u64) { - let mut ret = (0u64, 0u64); - unsafe { - let base = &mut ret as *mut (u64, u64) as *mut u8; - let len = mem::size_of_val(&ret); - wasi::random_get(base, len).expect("random_get failure"); - } - return ret; -} - #[inline] pub(crate) fn err2io(err: wasi::Errno) -> std_io::Error { std_io::Error::from_raw_os_error(err.raw().into()) diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 8051021a58897..5d54c7903065c 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -47,4 +47,4 @@ mod helpers; // then the compiler complains about conflicts. use helpers::err2io; -pub use helpers::{abort_internal, decode_error_kind, hashmap_random_keys, is_interrupted}; +pub use helpers::{abort_internal, decode_error_kind, is_interrupted}; diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 546fadbe5011c..17b26543bd75f 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -50,6 +50,6 @@ mod helpers; // then the compiler complains about conflicts. use helpers::err2io; -pub use helpers::{abort_internal, decode_error_kind, hashmap_random_keys, is_interrupted}; +pub use helpers::{abort_internal, decode_error_kind, is_interrupted}; mod cabi_realloc; diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 00c816a6c09b8..ebe207fde935c 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -30,7 +30,6 @@ //! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example. use core::ffi::c_void; -use core::ptr::addr_of; use super::c; @@ -186,7 +185,7 @@ unsafe trait SizedSetFileInformation: Sized { unsafe impl SetFileInformation for T { const CLASS: i32 = T::CLASS; fn as_ptr(&self) -> *const c_void { - addr_of!(*self).cast::() + (&raw const *self).cast::() } fn size(&self) -> u32 { win32_size_of::() @@ -254,7 +253,7 @@ pub struct WinError { pub code: u32, } impl WinError { - const fn new(code: u32) -> Self { + pub const fn new(code: u32) -> Self { Self { code } } } @@ -272,8 +271,11 @@ impl WinError { // tidy-alphabetical-start pub const ACCESS_DENIED: Self = Self::new(c::ERROR_ACCESS_DENIED); pub const ALREADY_EXISTS: Self = Self::new(c::ERROR_ALREADY_EXISTS); + pub const BAD_NET_NAME: Self = Self::new(c::ERROR_BAD_NET_NAME); + pub const BAD_NETPATH: Self = Self::new(c::ERROR_BAD_NETPATH); pub const CANT_ACCESS_FILE: Self = Self::new(c::ERROR_CANT_ACCESS_FILE); pub const DELETE_PENDING: Self = Self::new(c::ERROR_DELETE_PENDING); + pub const DIR_NOT_EMPTY: Self = Self::new(c::ERROR_DIR_NOT_EMPTY); pub const DIRECTORY: Self = Self::new(c::ERROR_DIRECTORY); pub const FILE_NOT_FOUND: Self = Self::new(c::ERROR_FILE_NOT_FOUND); pub const INSUFFICIENT_BUFFER: Self = Self::new(c::ERROR_INSUFFICIENT_BUFFER); diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs index 66e75a8357149..848632ec2a7e3 100644 --- a/library/std/src/sys/pal/windows/args.rs +++ b/library/std/src/sys/pal/windows/args.rs @@ -14,13 +14,13 @@ use crate::path::{Path, PathBuf}; use crate::sys::path::get_long_path; use crate::sys::process::ensure_no_nuls; use crate::sys::{c, to_u16s}; -use crate::sys_common::wstr::WStrUnits; use crate::sys_common::AsInner; +use crate::sys_common::wstr::WStrUnits; use crate::{fmt, io, iter, vec}; /// This is the const equivalent to `NonZero::new(n).unwrap()` /// -/// FIXME: This can be removed once `Option::unwrap` is stably const. +/// FIXME(const-hack): This can be removed once `Option::unwrap` is stably const. /// See the `const_option` feature (#67441). const fn non_zero_u16(n: u16) -> NonZero { match NonZero::new(n) { diff --git a/library/std/src/sys/pal/windows/args/tests.rs b/library/std/src/sys/pal/windows/args/tests.rs index 484a90ab056df..6d5c953cbd5c6 100644 --- a/library/std/src/sys/pal/windows/args/tests.rs +++ b/library/std/src/sys/pal/windows/args/tests.rs @@ -47,10 +47,10 @@ fn whitespace_behavior() { fn genius_quotes() { chk(r#"EXE "" """#, &["EXE", "", ""]); chk(r#"EXE "" """"#, &["EXE", "", r#"""#]); - chk( - r#"EXE "this is """all""" in the same argument""#, - &["EXE", r#"this is "all" in the same argument"#], - ); + chk(r#"EXE "this is """all""" in the same argument""#, &[ + "EXE", + r#"this is "all" in the same argument"#, + ]); chk(r#"EXE "a"""#, &["EXE", r#"a""#]); chk(r#"EXE "a"" a"#, &["EXE", r#"a" a"#]); // quotes cannot be escaped in command names diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index b888eb7d95ca3..b65ad7dbe8c5a 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -5,7 +5,7 @@ #![unstable(issue = "none", feature = "windows_c")] #![allow(clippy::style)] -use core::ffi::{c_uint, c_ulong, c_ushort, c_void, CStr}; +use core::ffi::{CStr, c_uint, c_ulong, c_ushort, c_void}; use core::{mem, ptr}; mod windows_sys; diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index afacc370c3420..9c2e4500da068 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -34,6 +34,7 @@ Windows.Wdk.Storage.FileSystem.FILE_WRITE_THROUGH Windows.Wdk.Storage.FileSystem.NtCreateFile Windows.Wdk.Storage.FileSystem.NTCREATEFILE_CREATE_DISPOSITION Windows.Wdk.Storage.FileSystem.NTCREATEFILE_CREATE_OPTIONS +Windows.Wdk.Storage.FileSystem.NtOpenFile Windows.Wdk.Storage.FileSystem.NtReadFile Windows.Wdk.Storage.FileSystem.NtWriteFile Windows.Wdk.Storage.FileSystem.SYMLINK_FLAG_RELATIVE @@ -1931,10 +1932,14 @@ Windows.Win32.Foundation.RtlNtStatusToDosError Windows.Win32.Foundation.SetHandleInformation Windows.Win32.Foundation.SetLastError Windows.Win32.Foundation.STATUS_DELETE_PENDING +Windows.Win32.Foundation.STATUS_DIRECTORY_NOT_EMPTY Windows.Win32.Foundation.STATUS_END_OF_FILE +Windows.Win32.Foundation.STATUS_FILE_DELETED +Windows.Win32.Foundation.STATUS_INVALID_HANDLE Windows.Win32.Foundation.STATUS_INVALID_PARAMETER Windows.Win32.Foundation.STATUS_NOT_IMPLEMENTED Windows.Win32.Foundation.STATUS_PENDING +Windows.Win32.Foundation.STATUS_SHARING_VIOLATION Windows.Win32.Foundation.STATUS_SUCCESS Windows.Win32.Foundation.TRUE Windows.Win32.Foundation.UNICODE_STRING diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 529c96a0e1e6b..ab5f8919d7af6 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -105,6 +105,7 @@ windows_targets::link!("kernel32.dll" "system" fn WideCharToMultiByte(codepage : windows_targets::link!("kernel32.dll" "system" fn WriteConsoleW(hconsoleoutput : HANDLE, lpbuffer : PCWSTR, nnumberofcharstowrite : u32, lpnumberofcharswritten : *mut u32, lpreserved : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn WriteFileEx(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL); windows_targets::link!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); @@ -2982,10 +2983,14 @@ pub struct STARTUPINFOW { } pub type STARTUPINFOW_FLAGS = u32; pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056_u32 as _; +pub const STATUS_DIRECTORY_NOT_EMPTY: NTSTATUS = 0xC0000101_u32 as _; pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _; +pub const STATUS_FILE_DELETED: NTSTATUS = 0xC0000123_u32 as _; +pub const STATUS_INVALID_HANDLE: NTSTATUS = 0xC0000008_u32 as _; pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xC000000D_u32 as _; pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _; pub const STATUS_PENDING: NTSTATUS = 0x103_u32 as _; +pub const STATUS_SHARING_VIOLATION: NTSTATUS = 0xC0000043_u32 as _; pub const STATUS_SUCCESS: NTSTATUS = 0x0_u32 as _; pub const STD_ERROR_HANDLE: STD_HANDLE = 4294967284u32; pub type STD_HANDLE = u32; diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index 75232dfc0b0f1..c8e25dd0c94ba 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -19,7 +19,7 @@ //! function is called. In the worst case, multiple threads may all end up //! importing the same function unnecessarily. -use crate::ffi::{c_void, CStr}; +use crate::ffi::{CStr, c_void}; use crate::ptr::NonNull; use crate::sys::c; diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 2134152ea93f1..aab471e28eaeb 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,9 +1,7 @@ -use core::ptr::addr_of; - use super::api::{self, WinError}; -use super::{to_u16s, IoResult}; +use super::{IoResult, to_u16s}; use crate::borrow::Cow; -use crate::ffi::{c_void, OsStr, OsString}; +use crate::ffi::{OsStr, OsString, c_void}; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, MaybeUninit}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; @@ -13,9 +11,12 @@ use crate::sync::Arc; use crate::sys::handle::Handle; use crate::sys::path::maybe_verbatim; use crate::sys::time::SystemTime; -use crate::sys::{c, cvt, Align8}; -use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner}; -use crate::{fmt, ptr, slice, thread}; +use crate::sys::{Align8, c, cvt}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::{fmt, ptr, slice}; + +mod remove_dir_all; +use remove_dir_all::remove_dir_all_iterative; pub struct File { handle: Handle, @@ -322,7 +323,7 @@ impl File { let result = c::SetFileInformationByHandle( handle.as_raw_handle(), c::FileEndOfFileInfo, - ptr::addr_of!(eof).cast::(), + (&raw const eof).cast::(), mem::size_of::() as u32, ); if result == 0 { @@ -361,7 +362,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileAttributeTagInfo, - ptr::addr_of_mut!(attr_tag).cast(), + (&raw mut attr_tag).cast(), mem::size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { @@ -393,7 +394,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; let mut attr = FileAttr { @@ -425,7 +426,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileStandardInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; attr.file_size = info.AllocationSize as u64; @@ -435,7 +436,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileAttributeTagInfo, - ptr::addr_of_mut!(attr_tag).cast(), + (&raw mut attr_tag).cast(), mem::size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { @@ -542,22 +543,20 @@ impl File { unsafe { let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag { c::IO_REPARSE_TAG_SYMLINK => { - let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER = - ptr::addr_of_mut!((*buf).rest).cast(); + let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER = (&raw mut (*buf).rest).cast(); assert!(info.is_aligned()); ( - ptr::addr_of_mut!((*info).PathBuffer).cast::(), + (&raw mut (*info).PathBuffer).cast::(), (*info).SubstituteNameOffset / 2, (*info).SubstituteNameLength / 2, (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0, ) } c::IO_REPARSE_TAG_MOUNT_POINT => { - let info: *mut c::MOUNT_POINT_REPARSE_BUFFER = - ptr::addr_of_mut!((*buf).rest).cast(); + let info: *mut c::MOUNT_POINT_REPARSE_BUFFER = (&raw mut (*buf).rest).cast(); assert!(info.is_aligned()); ( - ptr::addr_of_mut!((*info).PathBuffer).cast::(), + (&raw mut (*info).PathBuffer).cast::(), (*info).SubstituteNameOffset / 2, (*info).SubstituteNameLength / 2, false, @@ -640,12 +639,28 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; Ok(info) } } + + /// Deletes the file, consuming the file handle to ensure the delete occurs + /// as immediately as possible. + /// This attempts to use `posix_delete` but falls back to `win32_delete` + /// if that is not supported by the filesystem. + #[allow(unused)] + fn delete(self) -> Result<(), WinError> { + // If POSIX delete is not supported for this filesystem then fallback to win32 delete. + match self.posix_delete() { + Err(WinError::INVALID_PARAMETER) + | Err(WinError::NOT_SUPPORTED) + | Err(WinError::INVALID_FUNCTION) => self.win32_delete(), + result => result, + } + } + /// Delete using POSIX semantics. /// /// Files will be deleted as soon as the handle is closed. This is supported @@ -654,21 +669,23 @@ impl File { /// /// If the operation is not supported for this filesystem or OS version /// then errors will be `ERROR_NOT_SUPPORTED` or `ERROR_INVALID_PARAMETER`. - fn posix_delete(&self) -> io::Result<()> { + #[allow(unused)] + fn posix_delete(&self) -> Result<(), WinError> { let info = c::FILE_DISPOSITION_INFO_EX { Flags: c::FILE_DISPOSITION_FLAG_DELETE | c::FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | c::FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE, }; - api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result() + api::set_file_information_by_handle(self.handle.as_raw_handle(), &info) } /// Delete a file using win32 semantics. The file won't actually be deleted /// until all file handles are closed. However, marking a file for deletion /// will prevent anyone from opening a new handle to the file. - fn win32_delete(&self) -> io::Result<()> { + #[allow(unused)] + fn win32_delete(&self) -> Result<(), WinError> { let info = c::FILE_DISPOSITION_INFO { DeleteFile: c::TRUE as _ }; - api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result() + api::set_file_information_by_handle(self.handle.as_raw_handle(), &info) } /// Fill the given buffer with as many directory entries as will fit. @@ -684,21 +701,23 @@ impl File { /// A symlink directory is simply an empty directory with some "reparse" metadata attached. /// So if you open a link (not its target) and iterate the directory, /// you will always iterate an empty directory regardless of the target. - fn fill_dir_buff(&self, buffer: &mut DirBuff, restart: bool) -> io::Result { + #[allow(unused)] + fn fill_dir_buff(&self, buffer: &mut DirBuff, restart: bool) -> Result { let class = if restart { c::FileIdBothDirectoryRestartInfo } else { c::FileIdBothDirectoryInfo }; unsafe { - let result = cvt(c::GetFileInformationByHandleEx( - self.handle.as_raw_handle(), + let result = c::GetFileInformationByHandleEx( + self.as_raw_handle(), class, buffer.as_mut_ptr().cast(), buffer.capacity() as _, - )); - match result { - Ok(_) => Ok(true), - Err(e) if e.raw_os_error() == Some(c::ERROR_NO_MORE_FILES as _) => Ok(false), - Err(e) => Err(e), + ); + if result == 0 { + let err = api::get_last_error(); + if err.code == c::ERROR_NO_MORE_FILES { Ok(false) } else { Err(err) } + } else { + Ok(true) } } } @@ -767,11 +786,11 @@ impl<'a> Iterator for DirBuffIter<'a> { // it does not seem that reality is so kind, and assuming this // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530) // presumably, this can be blamed on buggy filesystem drivers, but who knows. - let next_entry = ptr::addr_of!((*info).NextEntryOffset).read_unaligned() as usize; - let length = ptr::addr_of!((*info).FileNameLength).read_unaligned() as usize; - let attrs = ptr::addr_of!((*info).FileAttributes).read_unaligned(); + let next_entry = (&raw const (*info).NextEntryOffset).read_unaligned() as usize; + let length = (&raw const (*info).FileNameLength).read_unaligned() as usize; + let attrs = (&raw const (*info).FileAttributes).read_unaligned(); let name = from_maybe_unaligned( - ptr::addr_of!((*info).FileName).cast::(), + (&raw const (*info).FileName).cast::(), length / size_of::(), ); let is_directory = (attrs & c::FILE_ATTRIBUTE_DIRECTORY) != 0; @@ -804,62 +823,6 @@ unsafe fn from_maybe_unaligned<'a>(p: *const u16, len: usize) -> Cow<'a, [u16]> } } -/// Open a link relative to the parent directory, ensure no symlinks are followed. -fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result { - // This is implemented using the lower level `NtCreateFile` function as - // unfortunately opening a file relative to a parent is not supported by - // win32 functions. It is however a fundamental feature of the NT kernel. - // - // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile - unsafe { - let mut handle = ptr::null_mut(); - let mut io_status = c::IO_STATUS_BLOCK::PENDING; - let mut name_str = c::UNICODE_STRING::from_ref(name); - use crate::sync::atomic::{AtomicU32, Ordering}; - // The `OBJ_DONT_REPARSE` attribute ensures that we haven't been - // tricked into following a symlink. However, it may not be available in - // earlier versions of Windows. - static ATTRIBUTES: AtomicU32 = AtomicU32::new(c::OBJ_DONT_REPARSE); - let object = c::OBJECT_ATTRIBUTES { - ObjectName: &mut name_str, - RootDirectory: parent.as_raw_handle(), - Attributes: ATTRIBUTES.load(Ordering::Relaxed), - ..c::OBJECT_ATTRIBUTES::default() - }; - let status = c::NtCreateFile( - &mut handle, - access, - &object, - &mut io_status, - crate::ptr::null_mut(), - 0, - c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE, - c::FILE_OPEN, - // If `name` is a symlink then open the link rather than the target. - c::FILE_OPEN_REPARSE_POINT, - crate::ptr::null_mut(), - 0, - ); - // Convert an NTSTATUS to the more familiar Win32 error codes (aka "DosError") - if c::nt_success(status) { - Ok(File::from_raw_handle(handle)) - } else if status == c::STATUS_DELETE_PENDING { - // We make a special exception for `STATUS_DELETE_PENDING` because - // otherwise this will be mapped to `ERROR_ACCESS_DENIED` which is - // very unhelpful. - Err(io::Error::from_raw_os_error(c::ERROR_DELETE_PENDING as i32)) - } else if status == c::STATUS_INVALID_PARAMETER - && ATTRIBUTES.load(Ordering::Relaxed) == c::OBJ_DONT_REPARSE - { - // Try without `OBJ_DONT_REPARSE`. See above. - ATTRIBUTES.store(0, Ordering::Relaxed); - open_link_no_reparse(parent, name, access) - } else { - Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as _)) - } - } -} - impl AsInner for File { #[inline] fn as_inner(&self) -> &Handle { @@ -1142,114 +1105,22 @@ pub fn rmdir(p: &Path) -> io::Result<()> { Ok(()) } -/// Open a file or directory without following symlinks. -fn open_link(path: &Path, access_mode: u32) -> io::Result { +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + // Open a file or directory without following symlinks. let mut opts = OpenOptions::new(); - opts.access_mode(access_mode); + opts.access_mode(c::FILE_LIST_DIRECTORY); // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories. // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target. opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - File::open(path, &opts) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let file = open_link(path, c::DELETE | c::FILE_LIST_DIRECTORY)?; + let file = File::open(path, &opts)?; // Test if the file is not a directory or a symlink to a directory. if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _)); } - match ignore_notfound(remove_dir_all_iterative(&file, File::posix_delete)) { - Err(e) => { - if let Some(code) = e.raw_os_error() { - match code as u32 { - // If POSIX delete is not supported for this filesystem then fallback to win32 delete. - c::ERROR_NOT_SUPPORTED - | c::ERROR_INVALID_FUNCTION - | c::ERROR_INVALID_PARAMETER => { - remove_dir_all_iterative(&file, File::win32_delete) - } - _ => Err(e), - } - } else { - Err(e) - } - } - ok => ok, - } -} - -fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io::Result<()> { - // When deleting files we may loop this many times when certain error conditions occur. - // This allows remove_dir_all to succeed when the error is temporary. - const MAX_RETRIES: u32 = 10; - - let mut buffer = DirBuff::new(); - let mut dirlist = vec![f.duplicate()?]; - - // FIXME: This is a hack so we can push to the dirlist vec after borrowing from it. - fn copy_handle(f: &File) -> mem::ManuallyDrop { - unsafe { mem::ManuallyDrop::new(File::from_raw_handle(f.as_raw_handle())) } - } - - let mut restart = true; - while let Some(dir) = dirlist.last() { - let dir = copy_handle(dir); - - // Fill the buffer and iterate the entries. - let more_data = dir.fill_dir_buff(&mut buffer, restart)?; - restart = false; - for (name, is_directory) in buffer.iter() { - if is_directory { - let child_dir = open_link_no_reparse( - &dir, - &name, - c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY, - ); - // On success, add the handle to the queue. - // If opening the directory fails we treat it the same as a file - if let Ok(child_dir) = child_dir { - dirlist.push(child_dir); - continue; - } - } - for i in 1..=MAX_RETRIES { - let result = open_link_no_reparse(&dir, &name, c::SYNCHRONIZE | c::DELETE); - match result { - Ok(f) => delete(&f)?, - // Already deleted, so skip. - Err(e) if e.kind() == io::ErrorKind::NotFound => break, - // Retry a few times if the file is locked or a delete is already in progress. - Err(e) - if i < MAX_RETRIES - && (e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _) - || e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _)) => {} - // Otherwise return the error. - Err(e) => return Err(e), - } - thread::yield_now(); - } - } - // If there were no more files then delete the directory. - if !more_data { - if let Some(dir) = dirlist.pop() { - // Retry deleting a few times in case we need to wait for a file to be deleted. - for i in 1..=MAX_RETRIES { - let result = delete(&dir); - if let Err(e) = result { - if i == MAX_RETRIES || e.kind() != io::ErrorKind::DirectoryNotEmpty { - return Err(e); - } - thread::yield_now(); - } else { - break; - } - } - } - } - } - Ok(()) + // Remove the directory and all its contents. + remove_dir_all_iterative(file).io_result() } pub fn readlink(path: &Path) -> io::Result { @@ -1451,7 +1322,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { pfrom.as_ptr(), pto.as_ptr(), Some(callback), - core::ptr::addr_of_mut!(size) as *mut _, + (&raw mut size) as *mut _, ptr::null_mut(), 0, ) @@ -1530,7 +1401,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { cvt(c::DeviceIoControl( d.as_raw_handle(), c::FSCTL_SET_REPARSE_POINT, - addr_of!(header).cast::(), + (&raw const header).cast::(), data_len as u32 + 8, ptr::null_mut(), 0, diff --git a/library/std/src/sys/pal/windows/fs/remove_dir_all.rs b/library/std/src/sys/pal/windows/fs/remove_dir_all.rs new file mode 100644 index 0000000000000..9416049da78f8 --- /dev/null +++ b/library/std/src/sys/pal/windows/fs/remove_dir_all.rs @@ -0,0 +1,205 @@ +//! The Windows implementation of std::fs::remove_dir_all. +//! +//! This needs to address two issues: +//! +//! - It must not be possible to trick this into deleting files outside of +//! the parent directory (see CVE-2022-21658). +//! - It should not fail if many threads or processes call `remove_dir_all` +//! on the same path. +//! +//! The first is handled by using the low-level `NtOpenFile` API to open a file +//! relative to a parent directory. +//! +//! The second is trickier. Deleting a file works by setting its "disposition" +//! to delete. However, it isn't actually deleted until the file is closed. +//! During the gap between these two events, the file is in a kind of limbo +//! state where it still exists in the filesystem but anything trying to open +//! it fails with an error. +//! +//! The mitigations we use here are: +//! +//! - When attempting to open the file, we treat ERROR_DELETE_PENDING as a +//! successful delete. +//! - If the file still hasn't been removed from the filesystem by the time we +//! attempt to delete the parent directory, we try to wait for it to finish. +//! We can't wait indefinitely though so after some number of spins, we give +//! up and return an error. +//! +//! In short, we can't guarantee this will always succeed in the event of a +//! race but we do make a best effort such that it *should* do so. + +use core::ptr; +use core::sync::atomic::{AtomicU32, Ordering}; + +use super::{AsRawHandle, DirBuff, File, FromRawHandle}; +use crate::sys::c; +use crate::sys::pal::windows::api::WinError; +use crate::thread; + +// The maximum number of times to spin when waiting for deletes to complete. +const MAX_RETRIES: usize = 50; + +/// A wrapper around a raw NtOpenFile call. +/// +/// This isn't completely safe because `OBJECT_ATTRIBUTES` contains raw pointers. +unsafe fn nt_open_file( + access: u32, + object_attribute: &c::OBJECT_ATTRIBUTES, + share: u32, + options: u32, +) -> Result { + unsafe { + let mut handle = ptr::null_mut(); + let mut io_status = c::IO_STATUS_BLOCK::PENDING; + let status = + c::NtOpenFile(&mut handle, access, object_attribute, &mut io_status, share, options); + if c::nt_success(status) { + Ok(File::from_raw_handle(handle)) + } else { + // Convert an NTSTATUS to the more familiar Win32 error code (aka "DosError") + let win_error = if status == c::STATUS_DELETE_PENDING { + // We make a special exception for `STATUS_DELETE_PENDING` because + // otherwise this will be mapped to `ERROR_ACCESS_DENIED` which is + // very unhelpful because that can also mean a permission error. + WinError::DELETE_PENDING + } else { + WinError::new(c::RtlNtStatusToDosError(status)) + }; + Err(win_error) + } + } +} + +/// Open the file `path` in the directory `parent`, requesting the given `access` rights. +/// `options` will be OR'd with `FILE_OPEN_REPARSE_POINT`. +fn open_link_no_reparse( + parent: &File, + path: &[u16], + access: u32, + options: u32, +) -> Result, WinError> { + // This is implemented using the lower level `NtOpenFile` function as + // unfortunately opening a file relative to a parent is not supported by + // win32 functions. + // + // See https://learn.microsoft.com/windows/win32/api/winternl/nf-winternl-ntopenfile + + // The `OBJ_DONT_REPARSE` attribute ensures that we haven't been + // tricked into following a symlink. However, it may not be available in + // earlier versions of Windows. + static ATTRIBUTES: AtomicU32 = AtomicU32::new(c::OBJ_DONT_REPARSE); + + let result = unsafe { + let mut path_str = c::UNICODE_STRING::from_ref(path); + let mut object = c::OBJECT_ATTRIBUTES { + ObjectName: &mut path_str, + RootDirectory: parent.as_raw_handle(), + Attributes: ATTRIBUTES.load(Ordering::Relaxed), + ..c::OBJECT_ATTRIBUTES::default() + }; + let share = c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE; + let options = c::FILE_OPEN_REPARSE_POINT | options; + let result = nt_open_file(access, &object, share, options); + + // Retry without OBJ_DONT_REPARSE if it's not supported. + if matches!(result, Err(WinError::INVALID_PARAMETER)) + && ATTRIBUTES.load(Ordering::Relaxed) == c::OBJ_DONT_REPARSE + { + ATTRIBUTES.store(0, Ordering::Relaxed); + object.Attributes = 0; + nt_open_file(access, &object, share, options) + } else { + result + } + }; + + // Ignore not found errors + match result { + Ok(f) => Ok(Some(f)), + Err( + WinError::FILE_NOT_FOUND + | WinError::PATH_NOT_FOUND + | WinError::BAD_NETPATH + | WinError::BAD_NET_NAME + // `DELETE_PENDING` means something else is already trying to delete it + // so we assume that will eventually succeed. + | WinError::DELETE_PENDING, + ) => Ok(None), + Err(e) => Err(e), + } +} + +fn open_dir(parent: &File, name: &[u16]) -> Result, WinError> { + // Open the directory for synchronous directory listing. + open_link_no_reparse( + parent, + name, + c::SYNCHRONIZE | c::FILE_LIST_DIRECTORY, + // "_IO_NONALERT" means that a synchronous call won't be interrupted. + c::FILE_SYNCHRONOUS_IO_NONALERT, + ) +} + +fn delete(parent: &File, name: &[u16]) -> Result<(), WinError> { + // Note that the `delete` function consumes the opened file to ensure it's + // dropped immediately. See module comments for why this is important. + match open_link_no_reparse(parent, name, c::DELETE, 0) { + Ok(Some(f)) => f.delete(), + Ok(None) => Ok(()), + Err(e) => Err(e), + } +} + +/// A simple retry loop that keeps running `f` while it fails with the given +/// error code or until `MAX_RETRIES` is reached. +fn retry( + mut f: impl FnMut() -> Result, + ignore: WinError, +) -> Result { + let mut i = MAX_RETRIES; + loop { + i -= 1; + if i == 0 { + return f(); + } else { + let result = f(); + if result != Err(ignore) { + return result; + } + } + thread::yield_now(); + } +} + +pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { + let mut buffer = DirBuff::new(); + let mut dirlist = vec![dir]; + + let mut restart = true; + 'outer: while let Some(dir) = dirlist.pop() { + let more_data = dir.fill_dir_buff(&mut buffer, restart)?; + for (name, is_directory) in buffer.iter() { + if is_directory { + let Some(subdir) = open_dir(&dir, &name)? else { continue }; + dirlist.push(dir); + dirlist.push(subdir); + continue 'outer; + } else { + // Attempt to delete, retrying on sharing violation errors as these + // can often be very temporary. E.g. if something takes just a + // bit longer than expected to release a file handle. + retry(|| delete(&dir, &name), WinError::SHARING_VIOLATION)?; + } + } + if more_data { + dirlist.push(dir); + restart = false; + } else { + // Attempt to delete, retrying on not empty errors because we may + // need to wait some time for files to be removed from the filesystem. + retry(|| delete(&dir, &[]), WinError::DIR_NOT_EMPTY)?; + restart = true; + } + } + Ok(()) +} diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index 8c5081a607aa3..4d6c4df9a5a90 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -1,7 +1,7 @@ use core::ffi::c_void; use core::sync::atomic::{ - AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, - AtomicU32, AtomicU64, AtomicU8, AtomicUsize, + AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr, AtomicU8, + AtomicU16, AtomicU32, AtomicU64, AtomicUsize, }; use core::time::Duration; use core::{mem, ptr}; @@ -57,7 +57,7 @@ pub fn wait_on_address( unsafe { let addr = ptr::from_ref(address).cast::(); let size = mem::size_of::(); - let compare_addr = ptr::addr_of!(compare).cast::(); + let compare_addr = (&raw const compare).cast::(); let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE); c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE } diff --git a/library/std/src/sys/pal/windows/handle/tests.rs b/library/std/src/sys/pal/windows/handle/tests.rs index d836dae4c305b..0c976ed84e6ba 100644 --- a/library/std/src/sys/pal/windows/handle/tests.rs +++ b/library/std/src/sys/pal/windows/handle/tests.rs @@ -1,4 +1,4 @@ -use crate::sys::pipe::{anon_pipe, Pipes}; +use crate::sys::pipe::{Pipes, anon_pipe}; use crate::{thread, time}; /// Test the synchronous fallback for overlapped I/O. diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 785a3f6768b70..1e7d02908f63d 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -122,7 +122,7 @@ fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool { c::GetFileInformationByHandleEx( handle.as_raw_handle(), c::FileNameInfo, - core::ptr::addr_of_mut!(name_info) as *mut c_void, + (&raw mut name_info) as *mut c_void, size_of::() as u32, ) }; diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 272fadd915005..1ea253e5e5263 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -1,7 +1,6 @@ #![allow(missing_docs, nonstandard_style)] #![forbid(unsafe_op_in_unsafe_fn)] -pub use self::rand::hashmap_random_keys; use crate::ffi::{OsStr, OsString}; use crate::io::ErrorKind; use crate::mem::MaybeUninit; @@ -13,7 +12,7 @@ use crate::time::Duration; #[macro_use] pub mod compat; -mod api; +pub mod api; pub mod args; pub mod c; @@ -27,7 +26,6 @@ pub mod net; pub mod os; pub mod pipe; pub mod process; -pub mod rand; pub mod stdio; pub mod thread; pub mod time; @@ -122,6 +120,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_NOT_SAME_DEVICE => return CrossesDevices, c::ERROR_TOO_MANY_LINKS => return TooManyLinks, c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename, + c::ERROR_CANT_RESOLVE_FILENAME => return FilesystemLoop, _ => {} } @@ -139,6 +138,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::WSAEHOSTUNREACH => HostUnreachable, c::WSAENETDOWN => NetworkDown, c::WSAENETUNREACH => NetworkUnreachable, + c::WSAEDQUOT => FilesystemQuotaExceeded, _ => Uncategorized, } diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index ce995f5ed5af7..fd62d1f407c27 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -9,7 +9,7 @@ use crate::os::windows::io::{ }; use crate::sync::OnceLock; use crate::sys::c; -use crate::sys_common::{net, AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner, net}; use crate::time::Duration; use crate::{cmp, mem, ptr, sys}; @@ -27,12 +27,12 @@ pub mod netc { use crate::sys::c::{self, ADDRESS_FAMILY, ADDRINFOA, SOCKADDR, SOCKET}; // re-exports from Windows API bindings. pub use crate::sys::c::{ - bind, connect, freeaddrinfo, getpeername, getsockname, getsockopt, listen, setsockopt, - ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IPPROTO_IP, IPPROTO_IPV6, - IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, - IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, - SOCKADDR as sockaddr, SOCKADDR_STORAGE as sockaddr_storage, SOCK_DGRAM, SOCK_STREAM, - SOL_SOCKET, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO, + ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IP_ADD_MEMBERSHIP, + IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, IPPROTO_IP, IPPROTO_IPV6, + IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, SO_BROADCAST, + SO_RCVTIMEO, SO_SNDTIMEO, SOCK_DGRAM, SOCK_STREAM, SOCKADDR as sockaddr, + SOCKADDR_STORAGE as sockaddr_storage, SOL_SOCKET, bind, connect, freeaddrinfo, getpeername, + getsockname, getsockopt, listen, setsockopt, }; #[allow(non_camel_case_types)] @@ -390,7 +390,7 @@ impl Socket { buf.as_mut_ptr() as *mut _, length, flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) }; diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index 7d1b5aca1d5fe..a8f6617c9dc8f 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -2,12 +2,13 @@ use crate::ffi::OsStr; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::os::windows::prelude::*; use crate::path::Path; +use crate::random::{DefaultRandomSource, Random}; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::Relaxed; +use crate::sys::c; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; use crate::sys::pal::windows::api::{self, WinError}; -use crate::sys::{c, hashmap_random_keys}; use crate::sys_common::{FromInner, IntoInner}; use crate::{mem, ptr}; @@ -79,7 +80,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res name = format!( r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}", c::GetCurrentProcessId(), - random_number() + random_number(), ); let wide_name = OsStr::new(&name).encode_wide().chain(Some(0)).collect::>(); let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE | c::FILE_FLAG_OVERLAPPED; @@ -214,7 +215,7 @@ fn random_number() -> usize { return N.fetch_add(1, Relaxed); } - N.store(hashmap_random_keys().0 as usize, Relaxed); + N.store(usize::random(&mut DefaultRandomSource), Relaxed); } } @@ -374,7 +375,7 @@ impl AnonPipe { let mut overlapped: c::OVERLAPPED = unsafe { crate::mem::zeroed() }; // `hEvent` is unused by `ReadFileEx` and `WriteFileEx`. // Therefore the documentation suggests using it to smuggle a pointer to the callback. - overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _; + overlapped.hEvent = (&raw mut async_result) as *mut _; // Asynchronous read of the pipe. // If successful, `callback` will be called once it completes. diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 06eae5a07b068..95b51e704f9d4 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -22,8 +22,8 @@ use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::IntoInner; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::{cmp, env, fmt, mem, ptr}; //////////////////////////////////////////////////////////////////////////////// @@ -253,10 +253,10 @@ impl Command { attribute: usize, value: T, ) { - self.proc_thread_attributes.insert( - attribute, - ProcThreadAttributeValue { size: mem::size_of::(), data: Box::new(value) }, - ); + self.proc_thread_attributes.insert(attribute, ProcThreadAttributeValue { + size: mem::size_of::(), + data: Box::new(value), + }); } pub fn spawn( @@ -272,11 +272,24 @@ impl Command { None }; let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?; - // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd" - let is_batch_file = matches!( - program.len().checked_sub(5).and_then(|i| program.get(i..)), - Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0]) - ); + let has_bat_extension = |program: &[u16]| { + matches!( + // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd" + program.len().checked_sub(4).and_then(|i| program.get(i..)), + Some([46, 98 | 66, 97 | 65, 116 | 84] | [46, 99 | 67, 109 | 77, 100 | 68]) + ) + }; + let is_batch_file = if path::is_verbatim(&program) { + has_bat_extension(&program[..program.len() - 1]) + } else { + super::fill_utf16_buf( + |buffer, size| unsafe { + // resolve the path so we can test the final file name. + c::GetFullPathNameW(program.as_ptr(), size, buffer, ptr::null_mut()) + }, + |program| has_bat_extension(program), + )? + }; let (program, mut cmd_str) = if is_batch_file { ( command_prompt()?, @@ -355,10 +368,10 @@ impl Command { StartupInfo: si, lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _, }; - si_ptr = core::ptr::addr_of_mut!(si_ex) as _; + si_ptr = (&raw mut si_ex) as _; } else { si.cb = mem::size_of::() as u32; - si_ptr = core::ptr::addr_of_mut!(si) as _; + si_ptr = (&raw mut si) as _; } unsafe { @@ -940,7 +953,7 @@ fn make_proc_thread_attribute_list( // It's theoretically possible for the attribute count to exceed a u32 value. // Therefore, we ensure that we don't add more attributes than the buffer was initialized for. for (&attribute, value) in attributes.iter().take(attribute_count as usize) { - let value_ptr = core::ptr::addr_of!(*value.data) as _; + let value_ptr = (&raw const *value.data) as _; cvt(unsafe { c::UpdateProcThreadAttribute( proc_thread_attribute_list.0.as_mut_ptr() as _, diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/pal/windows/process/tests.rs index 65325fa64a077..b567151b72142 100644 --- a/library/std/src/sys/pal/windows/process/tests.rs +++ b/library/std/src/sys/pal/windows/process/tests.rs @@ -1,4 +1,4 @@ -use super::{make_command_line, Arg}; +use super::{Arg, make_command_line}; use crate::env; use crate::ffi::{OsStr, OsString}; use crate::process::Command; diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs deleted file mode 100644 index e366bb995626a..0000000000000 --- a/library/std/src/sys/pal/windows/rand.rs +++ /dev/null @@ -1,27 +0,0 @@ -use core::{mem, ptr}; - -use crate::sys::c; - -#[cfg(not(target_vendor = "win7"))] -#[inline] -pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - let ret = unsafe { c::ProcessPrng(ptr::addr_of_mut!(v).cast::(), mem::size_of_val(&v)) }; - // ProcessPrng is documented as always returning `TRUE`. - // https://learn.microsoft.com/en-us/windows/win32/seccng/processprng#return-value - debug_assert_eq!(ret, c::TRUE); - v -} - -#[cfg(target_vendor = "win7")] -pub fn hashmap_random_keys() -> (u64, u64) { - use crate::ffi::c_void; - use crate::io; - - let mut v = (0, 0); - let ret = unsafe { - c::RtlGenRandom(ptr::addr_of_mut!(v).cast::(), mem::size_of_val(&v) as u32) - }; - - if ret != 0 { v } else { panic!("RNG broken: {}", io::Error::last_os_error()) } -} diff --git a/library/std/src/sys/pal/xous/net/dns.rs b/library/std/src/sys/pal/xous/net/dns.rs index 50efe978c4a83..d0083c6183793 100644 --- a/library/std/src/sys/pal/xous/net/dns.rs +++ b/library/std/src/sys/pal/xous/net/dns.rs @@ -3,7 +3,7 @@ use core::convert::{TryFrom, TryInto}; use crate::io; use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::os::xous::ffi::lend_mut; -use crate::os::xous::services::{dns_server, DnsLendMut}; +use crate::os::xous::services::{DnsLendMut, dns_server}; pub struct DnsError { pub code: u8, diff --git a/library/std/src/sys/pal/xous/stdio.rs b/library/std/src/sys/pal/xous/stdio.rs index 11608964b52e6..dfd47a1775ae2 100644 --- a/library/std/src/sys/pal/xous/stdio.rs +++ b/library/std/src/sys/pal/xous/stdio.rs @@ -4,8 +4,8 @@ pub struct Stdin; pub struct Stdout {} pub struct Stderr; -use crate::os::xous::ffi::{lend, try_lend, try_scalar, Connection}; -use crate::os::xous::services::{log_server, try_connect, LogLend, LogScalar}; +use crate::os::xous::ffi::{Connection, lend, try_lend, try_scalar}; +use crate::os::xous::services::{LogLend, LogScalar, log_server, try_connect}; impl Stdin { pub const fn new() -> Stdin { diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs index a95b0aa14d255..0ebb46dc19faa 100644 --- a/library/std/src/sys/pal/xous/thread.rs +++ b/library/std/src/sys/pal/xous/thread.rs @@ -4,10 +4,10 @@ use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::os::xous::ffi::{ - blocking_scalar, create_thread, do_yield, join_thread, map_memory, update_memory_flags, - MemoryFlags, Syscall, ThreadId, + MemoryFlags, Syscall, ThreadId, blocking_scalar, create_thread, do_yield, join_thread, + map_memory, update_memory_flags, }; -use crate::os::xous::services::{ticktimer_server, TicktimerScalar}; +use crate::os::xous::services::{TicktimerScalar, ticktimer_server}; use crate::time::Duration; pub struct Thread { diff --git a/library/std/src/sys/pal/zkvm/args.rs b/library/std/src/sys/pal/zkvm/args.rs index 583c16e3a4721..47857f6c448bc 100644 --- a/library/std/src/sys/pal/zkvm/args.rs +++ b/library/std/src/sys/pal/zkvm/args.rs @@ -1,4 +1,4 @@ -use super::{abi, WORD_SIZE}; +use super::{WORD_SIZE, abi}; use crate::ffi::OsString; use crate::fmt; use crate::sys::os_str; diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 20fdb7468a40d..6ea057720296d 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -60,11 +60,3 @@ pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { pub fn abort_internal() -> ! { core::intrinsics::abort(); } - -pub fn hashmap_random_keys() -> (u64, u64) { - let mut buf = [0u32; 4]; - unsafe { - abi::sys_rand(buf.as_mut_ptr(), 4); - }; - ((buf[0] as u64) << 32 + buf[1] as u64, (buf[2] as u64) << 32 + buf[3] as u64) -} diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs index 68d91a123acd4..5d224ffd1ba5a 100644 --- a/library/std/src/sys/pal/zkvm/os.rs +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -1,4 +1,4 @@ -use super::{abi, unsupported, WORD_SIZE}; +use super::{WORD_SIZE, abi, unsupported}; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index 21841eb18cc0e..9267602cb9715 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -1,5 +1,6 @@ use crate::ffi::{OsStr, OsString}; use crate::path::{Path, PathBuf, Prefix}; +use crate::sys::api::utf16; use crate::sys::pal::{c, fill_utf16_buf, os2path, to_u16s}; use crate::{io, ptr}; @@ -19,6 +20,10 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'\\' } +pub fn is_verbatim(path: &[u16]) -> bool { + path.starts_with(utf16!(r"\\?\")) || path.starts_with(utf16!(r"\??\")) +} + /// Returns true if `path` looks like a lone filename. pub(crate) fn is_file_name(path: &OsStr) -> bool { !path.as_encoded_bytes().iter().copied().any(is_sep_byte) @@ -94,7 +99,7 @@ impl<'a> PrefixParserSlice<'a, '_> { } pub fn parse_prefix(path: &OsStr) -> Option> { - use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC}; + use Prefix::{DeviceNS, Disk, UNC, Verbatim, VerbatimDisk, VerbatimUNC}; let parser = PrefixParser::<8>::new(path); let parser = parser.as_slice(); diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs index c37c3e442aea6..778d8686f023e 100644 --- a/library/std/src/sys/personality/dwarf/eh.rs +++ b/library/std/src/sys/personality/dwarf/eh.rs @@ -54,10 +54,10 @@ pub enum EHAction { Terminate, } -/// 32-bit Apple ARM uses SjLj exceptions, except for watchOS. +/// 32-bit ARM Darwin platforms uses SjLj exceptions. /// -/// I.e. iOS and tvOS, as those are the only Apple OSes that used 32-bit ARM -/// devices. +/// The exception is watchOS armv7k (specifically that subarchitecture), which +/// instead uses DWARF Call Frame Information (CFI) unwinding. /// /// pub const USING_SJLJ_EXCEPTIONS: bool = diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs index f6b1844e153fd..ad596ecff65d5 100644 --- a/library/std/src/sys/personality/gcc.rs +++ b/library/std/src/sys/personality/gcc.rs @@ -95,14 +95,15 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 cfg_if::cfg_if! { if #[cfg(all( - target_arch = "arm", - not(all(target_vendor = "apple", not(target_os = "watchos"))), - not(target_os = "netbsd"), - ))] { + target_arch = "arm", + not(target_vendor = "apple"), + not(target_os = "netbsd"), + ))] { /// personality fn called by [ARM EHABI][armeabi-eh] /// - /// Apple 32-bit ARM (but not watchOS) uses the default routine instead - /// since it uses "setjmp-longjmp" unwinding. + /// 32-bit ARM on iOS/tvOS/watchOS does not use ARM EHABI, it uses + /// either "setjmp-longjmp" unwinding or DWARF CFI unwinding, which is + /// handled by the default routine. /// /// [armeabi-eh]: https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf #[lang = "eh_personality"] diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index 1a6ea1dafcb53..9754e840d151a 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -31,7 +31,7 @@ cfg_if::cfg_if! { target_os = "psp", target_os = "xous", target_os = "solid_asp3", - all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")), + all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems"), not(target_os = "nuttx")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { mod gcc; diff --git a/library/std/src/sys/random/apple.rs b/library/std/src/sys/random/apple.rs new file mode 100644 index 0000000000000..417198c9d850a --- /dev/null +++ b/library/std/src/sys/random/apple.rs @@ -0,0 +1,15 @@ +//! Random data on Apple platforms. +//! +//! `CCRandomGenerateBytes` calls into `CCRandomCopyBytes` with `kCCRandomDefault`. +//! `CCRandomCopyBytes` manages a CSPRNG which is seeded from the kernel's CSPRNG. +//! We use `CCRandomGenerateBytes` instead of `SecCopyBytes` because it is accessible via +//! `libSystem` (libc) while the other needs to link to `Security.framework`. +//! +//! Note that technically, `arc4random_buf` is available as well, but that calls +//! into the same system service anyway, and `CCRandomGenerateBytes` has been +//! proven to be App Store-compatible. + +pub fn fill_bytes(bytes: &mut [u8]) { + let ret = unsafe { libc::CCRandomGenerateBytes(bytes.as_mut_ptr().cast(), bytes.len()) }; + assert_eq!(ret, libc::kCCSuccess, "failed to generate random data"); +} diff --git a/library/std/src/sys/random/arc4random.rs b/library/std/src/sys/random/arc4random.rs new file mode 100644 index 0000000000000..32467e9ebaa64 --- /dev/null +++ b/library/std/src/sys/random/arc4random.rs @@ -0,0 +1,34 @@ +//! Random data generation with `arc4random_buf`. +//! +//! Contrary to its name, `arc4random` doesn't actually use the horribly-broken +//! RC4 cypher anymore, at least not on modern systems, but rather something +//! like ChaCha20 with continual reseeding from the OS. That makes it an ideal +//! source of large quantities of cryptographically secure data, which is exactly +//! what we need for `DefaultRandomSource`. Unfortunately, it's not available +//! on all UNIX systems, most notably Linux (until recently, but it's just a +//! wrapper for `getrandom`. Since we need to hook into `getrandom` directly +//! for `HashMap` keys anyway, we just keep our version). + +#[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "solaris", + target_os = "vita", +)))] +use libc::arc4random_buf; + +// FIXME: move these to libc (except Haiku, that one needs to link to libbsd.so). +#[cfg(any( + target_os = "haiku", // See https://git.haiku-os.org/haiku/tree/headers/compatibility/bsd/stdlib.h + target_os = "illumos", // See https://www.illumos.org/man/3C/arc4random + target_os = "solaris", // See https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html + target_os = "vita", // See https://github.com/vitasdk/newlib/blob/b89e5bc183b516945f9ee07eef483ecb916e45ff/newlib/libc/include/stdlib.h#L74 +))] +#[cfg_attr(target_os = "haiku", link(name = "bsd"))] +extern "C" { + fn arc4random_buf(buf: *mut core::ffi::c_void, nbytes: libc::size_t); +} + +pub fn fill_bytes(bytes: &mut [u8]) { + unsafe { arc4random_buf(bytes.as_mut_ptr().cast(), bytes.len()) } +} diff --git a/library/std/src/sys/random/espidf.rs b/library/std/src/sys/random/espidf.rs new file mode 100644 index 0000000000000..fd52cb5559ce5 --- /dev/null +++ b/library/std/src/sys/random/espidf.rs @@ -0,0 +1,9 @@ +use crate::ffi::c_void; + +extern "C" { + fn esp_fill_random(buf: *mut c_void, len: usize); +} + +pub fn fill_bytes(bytes: &mut [u8]) { + unsafe { esp_fill_random(bytes.as_mut_ptr().cast(), bytes.len()) } +} diff --git a/library/std/src/sys/random/fuchsia.rs b/library/std/src/sys/random/fuchsia.rs new file mode 100644 index 0000000000000..77d72b3c5b784 --- /dev/null +++ b/library/std/src/sys/random/fuchsia.rs @@ -0,0 +1,13 @@ +//! Random data generation using the Zircon kernel. +//! +//! Fuchsia, as always, is quite nice and provides exactly the API we need: +//! . + +#[link(name = "zircon")] +extern "C" { + fn zx_cprng_draw(buffer: *mut u8, len: usize); +} + +pub fn fill_bytes(bytes: &mut [u8]) { + unsafe { zx_cprng_draw(bytes.as_mut_ptr(), bytes.len()) } +} diff --git a/library/std/src/sys/random/getentropy.rs b/library/std/src/sys/random/getentropy.rs new file mode 100644 index 0000000000000..110ac134c1f47 --- /dev/null +++ b/library/std/src/sys/random/getentropy.rs @@ -0,0 +1,17 @@ +//! Random data generation through `getentropy`. +//! +//! Since issue 8 (2024), the POSIX specification mandates the existence of the +//! `getentropy` function, which fills a slice of up to `GETENTROPY_MAX` bytes +//! (256 on all known platforms) with random data. Unfortunately, it's only +//! meant to be used to seed other CPRNGs, which we don't have, so we only use +//! it where `arc4random_buf` and friends aren't available or secure (currently +//! that's only the case on Emscripten). + +pub fn fill_bytes(bytes: &mut [u8]) { + // GETENTROPY_MAX isn't defined yet on most platforms, but it's mandated + // to be at least 256, so just use that as limit. + for chunk in bytes.chunks_mut(256) { + let r = unsafe { libc::getentropy(chunk.as_mut_ptr().cast(), chunk.len()) }; + assert_ne!(r, -1, "failed to generate random data"); + } +} diff --git a/library/std/src/sys/random/hermit.rs b/library/std/src/sys/random/hermit.rs new file mode 100644 index 0000000000000..92c0550d2d584 --- /dev/null +++ b/library/std/src/sys/random/hermit.rs @@ -0,0 +1,7 @@ +pub fn fill_bytes(mut bytes: &mut [u8]) { + while !bytes.is_empty() { + let res = unsafe { hermit_abi::read_entropy(bytes.as_mut_ptr(), bytes.len(), 0) }; + assert_ne!(res, -1, "failed to generate random data"); + bytes = &mut bytes[res as usize..]; + } +} diff --git a/library/std/src/sys/random/horizon.rs b/library/std/src/sys/random/horizon.rs new file mode 100644 index 0000000000000..0be2eae20a727 --- /dev/null +++ b/library/std/src/sys/random/horizon.rs @@ -0,0 +1,7 @@ +pub fn fill_bytes(mut bytes: &mut [u8]) { + while !bytes.is_empty() { + let r = unsafe { libc::getrandom(bytes.as_mut_ptr().cast(), bytes.len(), 0) }; + assert_ne!(r, -1, "failed to generate random data"); + bytes = &mut bytes[r as usize..]; + } +} diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs new file mode 100644 index 0000000000000..073fdc45e611e --- /dev/null +++ b/library/std/src/sys/random/linux.rs @@ -0,0 +1,170 @@ +//! Random data generation with the Linux kernel. +//! +//! The first interface random data interface to be introduced on Linux were +//! the `/dev/random` and `/dev/urandom` special files. As paths can become +//! unreachable when inside a chroot and when the file descriptors are exhausted, +//! this was not enough to provide userspace with a reliable source of randomness, +//! so when the OpenBSD 5.6 introduced the `getentropy` syscall, Linux 3.17 got +//! its very own `getrandom` syscall to match.[^1] Unfortunately, even if our +//! minimum supported version were high enough, we still couldn't rely on the +//! syscall being available, as it is blocked in `seccomp` by default. +//! +//! The question is therefore which of the random sources to use. Historically, +//! the kernel contained two pools: the blocking and non-blocking pool. The +//! blocking pool used entropy estimation to limit the amount of available +//! bytes, while the non-blocking pool, once initialized using the blocking +//! pool, uses a CPRNG to return an unlimited number of random bytes. With a +//! strong enough CPRNG however, the entropy estimation didn't contribute that +//! much towards security while being an excellent vector for DoS attacs. Thus, +//! the blocking pool was removed in kernel version 5.6.[^2] That patch did not +//! magically increase the quality of the non-blocking pool, however, so we can +//! safely consider it strong enough even in older kernel versions and use it +//! unconditionally. +//! +//! One additional consideration to make is that the non-blocking pool is not +//! always initialized during early boot. We want the best quality of randomness +//! for the output of `DefaultRandomSource` so we simply wait until it is +//! initialized. When `HashMap` keys however, this represents a potential source +//! of deadlocks, as the additional entropy may only be generated once the +//! program makes forward progress. In that case, we just use the best random +//! data the system has available at the time. +//! +//! So in conclusion, we always want the output of the non-blocking pool, but +//! may need to wait until it is initalized. The default behaviour of `getrandom` +//! is to wait until the non-blocking pool is initialized and then draw from there, +//! so if `getrandom` is available, we use its default to generate the bytes. For +//! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that +//! is only available starting with kernel version 5.6. Thus, if we detect that +//! the flag is unsupported, we try `GRND_NONBLOCK` instead, which will only +//! succeed if the pool is initialized. If it isn't, we fall back to the file +//! access method. +//! +//! The behaviour of `/dev/urandom` is inverse to that of `getrandom`: it always +//! yields data, even when the pool is not initialized. For generating `HashMap` +//! keys, this is not important, so we can use it directly. For secure data +//! however, we need to wait until initialization, which we can do by `poll`ing +//! `/dev/random`. +//! +//! TLDR: our fallback strategies are: +//! +//! Secure data | `HashMap` keys +//! --------------------------------------------|------------------ +//! getrandom(0) | getrandom(GRND_INSECURE) +//! poll("/dev/random") && read("/dev/urandom") | getrandom(GRND_NONBLOCK) +//! | read("/dev/urandom") +//! +//! [^1]: +//! [^2]: +//! +// FIXME(in 2040 or so): once the minimum kernel version is 5.6, remove the +// `GRND_NONBLOCK` fallback and use `/dev/random` instead of `/dev/urandom` +// when secure data is required. + +use crate::fs::File; +use crate::io::Read; +use crate::os::fd::AsRawFd; +use crate::sync::OnceLock; +use crate::sync::atomic::AtomicBool; +use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; +use crate::sys::pal::os::errno; +use crate::sys::pal::weak::syscall; + +fn getrandom(mut bytes: &mut [u8], insecure: bool) { + // A weak symbol allows interposition, e.g. for perf measurements that want to + // disable randomness for consistency. Otherwise, we'll try a raw syscall. + // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28) + syscall! { + fn getrandom( + buffer: *mut libc::c_void, + length: libc::size_t, + flags: libc::c_uint + ) -> libc::ssize_t + } + + static GETRANDOM_AVAILABLE: AtomicBool = AtomicBool::new(true); + static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true); + static URANDOM_READY: AtomicBool = AtomicBool::new(false); + static DEVICE: OnceLock = OnceLock::new(); + + if GETRANDOM_AVAILABLE.load(Relaxed) { + loop { + if bytes.is_empty() { + return; + } + + let flags = if insecure { + if GRND_INSECURE_AVAILABLE.load(Relaxed) { + libc::GRND_INSECURE + } else { + libc::GRND_NONBLOCK + } + } else { + 0 + }; + + let ret = unsafe { getrandom(bytes.as_mut_ptr().cast(), bytes.len(), flags) }; + if ret != -1 { + bytes = &mut bytes[ret as usize..]; + } else { + match errno() { + libc::EINTR => continue, + // `GRND_INSECURE` is not available, try + // `GRND_NONBLOCK`. + libc::EINVAL if flags == libc::GRND_INSECURE => { + GRND_INSECURE_AVAILABLE.store(false, Relaxed); + continue; + } + // The pool is not initialized yet, fall back to + // /dev/urandom for now. + libc::EAGAIN if flags == libc::GRND_NONBLOCK => break, + // `getrandom` is unavailable or blocked by seccomp. + // Don't try it again and fall back to /dev/urandom. + libc::ENOSYS | libc::EPERM => { + GETRANDOM_AVAILABLE.store(false, Relaxed); + break; + } + _ => panic!("failed to generate random data"), + } + } + } + } + + // When we want cryptographic strength, we need to wait for the CPRNG-pool + // to become initialized. Do this by polling `/dev/random` until it is ready. + if !insecure { + if !URANDOM_READY.load(Acquire) { + let random = File::open("/dev/random").expect("failed to open /dev/random"); + let mut fd = libc::pollfd { fd: random.as_raw_fd(), events: libc::POLLIN, revents: 0 }; + + while !URANDOM_READY.load(Acquire) { + let ret = unsafe { libc::poll(&mut fd, 1, -1) }; + match ret { + 1 => { + assert_eq!(fd.revents, libc::POLLIN); + URANDOM_READY.store(true, Release); + break; + } + -1 if errno() == libc::EINTR => continue, + _ => panic!("poll(\"/dev/random\") failed"), + } + } + } + } + + DEVICE + .get_or_try_init(|| File::open("/dev/urandom")) + .and_then(|mut dev| dev.read_exact(bytes)) + .expect("failed to generate random data"); +} + +pub fn fill_bytes(bytes: &mut [u8]) { + getrandom(bytes, false); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + let mut bytes = [0; 16]; + getrandom(&mut bytes, true); + let k1 = u64::from_ne_bytes(bytes[..8].try_into().unwrap()); + let k2 = u64::from_ne_bytes(bytes[8..].try_into().unwrap()); + (k1, k2) +} diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs new file mode 100644 index 0000000000000..d625814d15b39 --- /dev/null +++ b/library/std/src/sys/random/mod.rs @@ -0,0 +1,96 @@ +cfg_if::cfg_if! { + // Tier 1 + if #[cfg(any(target_os = "linux", target_os = "android"))] { + mod linux; + pub use linux::{fill_bytes, hashmap_random_keys}; + } else if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::fill_bytes; + } else if #[cfg(target_vendor = "apple")] { + mod apple; + pub use apple::fill_bytes; + // Others, in alphabetical ordering. + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "vita", + ))] { + mod arc4random; + pub use arc4random::fill_bytes; + } else if #[cfg(target_os = "emscripten")] { + mod getentropy; + pub use getentropy::fill_bytes; + } else if #[cfg(target_os = "espidf")] { + mod espidf; + pub use espidf::fill_bytes; + } else if #[cfg(target_os = "fuchsia")] { + mod fuchsia; + pub use fuchsia::fill_bytes; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::fill_bytes; + } else if #[cfg(target_os = "horizon")] { + // FIXME: add arc4random_buf to shim-3ds + mod horizon; + pub use horizon::fill_bytes; + } else if #[cfg(any( + target_os = "hurd", + target_os = "l4re", + target_os = "nto", + target_os = "nuttx", + ))] { + mod unix_legacy; + pub use unix_legacy::fill_bytes; + } else if #[cfg(target_os = "redox")] { + mod redox; + pub use redox::fill_bytes; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::fill_bytes; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use solid::fill_bytes; + } else if #[cfg(target_os = "teeos")] { + mod teeos; + pub use teeos::fill_bytes; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::fill_bytes; + } else if #[cfg(target_os = "vxworks")] { + mod vxworks; + pub use vxworks::fill_bytes; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::fill_bytes; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use zkvm::fill_bytes; + } else if #[cfg(any( + all(target_family = "wasm", target_os = "unknown"), + target_os = "xous", + ))] { + // FIXME: finally remove std support for wasm32-unknown-unknown + // FIXME: add random data generation to xous + mod unsupported; + pub use unsupported::{fill_bytes, hashmap_random_keys}; + } +} + +#[cfg(not(any( + target_os = "linux", + target_os = "android", + all(target_family = "wasm", target_os = "unknown"), + target_os = "xous", +)))] +pub fn hashmap_random_keys() -> (u64, u64) { + let mut buf = [0; 16]; + fill_bytes(&mut buf); + let k1 = u64::from_ne_bytes(buf[..8].try_into().unwrap()); + let k2 = u64::from_ne_bytes(buf[8..].try_into().unwrap()); + (k1, k2) +} diff --git a/library/std/src/sys/random/redox.rs b/library/std/src/sys/random/redox.rs new file mode 100644 index 0000000000000..b004335a35176 --- /dev/null +++ b/library/std/src/sys/random/redox.rs @@ -0,0 +1,12 @@ +use crate::fs::File; +use crate::io::Read; +use crate::sync::OnceLock; + +static SCHEME: OnceLock = OnceLock::new(); + +pub fn fill_bytes(bytes: &mut [u8]) { + SCHEME + .get_or_try_init(|| File::open("/scheme/rand")) + .and_then(|mut scheme| scheme.read_exact(bytes)) + .expect("failed to generate random data"); +} diff --git a/library/std/src/sys/random/sgx.rs b/library/std/src/sys/random/sgx.rs new file mode 100644 index 0000000000000..c3647a8df220e --- /dev/null +++ b/library/std/src/sys/random/sgx.rs @@ -0,0 +1,67 @@ +use crate::arch::x86_64::{_rdrand16_step, _rdrand32_step, _rdrand64_step}; + +const RETRIES: u32 = 10; + +fn fail() -> ! { + panic!("failed to generate random data"); +} + +fn rdrand64() -> u64 { + unsafe { + let mut ret: u64 = 0; + for _ in 0..RETRIES { + if _rdrand64_step(&mut ret) == 1 { + return ret; + } + } + + fail(); + } +} + +fn rdrand32() -> u32 { + unsafe { + let mut ret: u32 = 0; + for _ in 0..RETRIES { + if _rdrand32_step(&mut ret) == 1 { + return ret; + } + } + + fail(); + } +} + +fn rdrand16() -> u16 { + unsafe { + let mut ret: u16 = 0; + for _ in 0..RETRIES { + if _rdrand16_step(&mut ret) == 1 { + return ret; + } + } + + fail(); + } +} + +pub fn fill_bytes(bytes: &mut [u8]) { + let mut chunks = bytes.array_chunks_mut(); + for chunk in &mut chunks { + *chunk = rdrand64().to_ne_bytes(); + } + + let mut chunks = chunks.into_remainder().array_chunks_mut(); + for chunk in &mut chunks { + *chunk = rdrand32().to_ne_bytes(); + } + + let mut chunks = chunks.into_remainder().array_chunks_mut(); + for chunk in &mut chunks { + *chunk = rdrand16().to_ne_bytes(); + } + + if let [byte] = chunks.into_remainder() { + *byte = rdrand16() as u8; + } +} diff --git a/library/std/src/sys/random/solid.rs b/library/std/src/sys/random/solid.rs new file mode 100644 index 0000000000000..545771150e284 --- /dev/null +++ b/library/std/src/sys/random/solid.rs @@ -0,0 +1,8 @@ +use crate::sys::pal::abi; + +pub fn fill_bytes(bytes: &mut [u8]) { + unsafe { + let result = abi::SOLID_RNG_SampleRandomBytes(bytes.as_mut_ptr(), bytes.len()); + assert_eq!(result, 0, "failed to generate random data"); + } +} diff --git a/library/std/src/sys/random/teeos.rs b/library/std/src/sys/random/teeos.rs new file mode 100644 index 0000000000000..fd6b24e19e982 --- /dev/null +++ b/library/std/src/sys/random/teeos.rs @@ -0,0 +1,7 @@ +extern "C" { + fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t); +} + +pub fn fill_bytes(bytes: &mut [u8]) { + unsafe { TEE_GenerateRandom(bytes.as_mut_ptr().cast(), bytes.len()) } +} diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs new file mode 100644 index 0000000000000..a4d29e66f3875 --- /dev/null +++ b/library/std/src/sys/random/uefi.rs @@ -0,0 +1,27 @@ +use r_efi::protocols::rng; + +use crate::sys::pal::helpers; + +pub fn fill_bytes(bytes: &mut [u8]) { + let handles = + helpers::locate_handles(rng::PROTOCOL_GUID).expect("failed to generate random data"); + for handle in handles { + if let Ok(protocol) = helpers::open_protocol::(handle, rng::PROTOCOL_GUID) { + let r = unsafe { + ((*protocol.as_ptr()).get_rng)( + protocol.as_ptr(), + crate::ptr::null_mut(), + bytes.len(), + bytes.as_mut_ptr(), + ) + }; + if r.is_error() { + continue; + } else { + return; + } + } + } + + panic!("failed to generate random data"); +} diff --git a/library/std/src/sys/random/unix_legacy.rs b/library/std/src/sys/random/unix_legacy.rs new file mode 100644 index 0000000000000..587068b0d6641 --- /dev/null +++ b/library/std/src/sys/random/unix_legacy.rs @@ -0,0 +1,20 @@ +//! Random data from `/dev/urandom` +//! +//! Before `getentropy` was standardized in 2024, UNIX didn't have a standardized +//! way of getting random data, so systems just followed the precedent set by +//! Linux and exposed random devices at `/dev/random` and `/dev/urandom`. Thus, +//! for the few systems that support neither `arc4random_buf` nor `getentropy` +//! yet, we just read from the file. + +use crate::fs::File; +use crate::io::Read; +use crate::sync::OnceLock; + +static DEVICE: OnceLock = OnceLock::new(); + +pub fn fill_bytes(bytes: &mut [u8]) { + DEVICE + .get_or_try_init(|| File::open("/dev/urandom")) + .and_then(|mut dev| dev.read_exact(bytes)) + .expect("failed to generate random data"); +} diff --git a/library/std/src/sys/random/unsupported.rs b/library/std/src/sys/random/unsupported.rs new file mode 100644 index 0000000000000..d68ce4a9e8703 --- /dev/null +++ b/library/std/src/sys/random/unsupported.rs @@ -0,0 +1,15 @@ +use crate::ptr; + +pub fn fill_bytes(_: &mut [u8]) { + panic!("this target does not support random data generation"); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + // Use allocation addresses for a bit of randomness. This isn't + // particularily secure, but there isn't really an alternative. + let stack = 0u8; + let heap = Box::new(0u8); + let k1 = ptr::from_ref(&stack).addr() as u64; + let k2 = ptr::from_ref(&*heap).addr() as u64; + (k1, k2) +} diff --git a/library/std/src/sys/random/vxworks.rs b/library/std/src/sys/random/vxworks.rs new file mode 100644 index 0000000000000..d549ccebdb2cd --- /dev/null +++ b/library/std/src/sys/random/vxworks.rs @@ -0,0 +1,25 @@ +use crate::sync::atomic::AtomicBool; +use crate::sync::atomic::Ordering::Relaxed; + +static RNG_INIT: AtomicBool = AtomicBool::new(false); + +pub fn fill_bytes(mut bytes: &mut [u8]) { + while !RNG_INIT.load(Relaxed) { + let ret = unsafe { libc::randSecure() }; + if ret < 0 { + panic!("failed to generate random data"); + } else if ret > 0 { + RNG_INIT.store(true, Relaxed); + break; + } + + unsafe { libc::usleep(10) }; + } + + while !bytes.is_empty() { + let len = bytes.len().try_into().unwrap_or(libc::c_int::MAX); + let ret = unsafe { libc::randABytes(bytes.as_mut_ptr(), len) }; + assert!(ret >= 0, "failed to generate random data"); + bytes = &mut bytes[len as usize..]; + } +} diff --git a/library/std/src/sys/random/wasi.rs b/library/std/src/sys/random/wasi.rs new file mode 100644 index 0000000000000..d41da3751fc04 --- /dev/null +++ b/library/std/src/sys/random/wasi.rs @@ -0,0 +1,5 @@ +pub fn fill_bytes(bytes: &mut [u8]) { + unsafe { + wasi::random_get(bytes.as_mut_ptr(), bytes.len()).expect("failed to generate random data") + } +} diff --git a/library/std/src/sys/random/windows.rs b/library/std/src/sys/random/windows.rs new file mode 100644 index 0000000000000..7566000f9e6ff --- /dev/null +++ b/library/std/src/sys/random/windows.rs @@ -0,0 +1,20 @@ +use crate::sys::c; + +#[cfg(not(target_vendor = "win7"))] +#[inline] +pub fn fill_bytes(bytes: &mut [u8]) { + let ret = unsafe { c::ProcessPrng(bytes.as_mut_ptr(), bytes.len()) }; + // ProcessPrng is documented as always returning `TRUE`. + // https://learn.microsoft.com/en-us/windows/win32/seccng/processprng#return-value + debug_assert_eq!(ret, c::TRUE); +} + +#[cfg(target_vendor = "win7")] +pub fn fill_bytes(mut bytes: &mut [u8]) { + while !bytes.is_empty() { + let len = bytes.len().try_into().unwrap_or(u32::MAX); + let ret = unsafe { c::RtlGenRandom(bytes.as_mut_ptr().cast(), len) }; + assert_ne!(ret, 0, "failed to generate random data"); + bytes = &mut bytes[len as usize..]; + } +} diff --git a/library/std/src/sys/random/zkvm.rs b/library/std/src/sys/random/zkvm.rs new file mode 100644 index 0000000000000..3011942f6b26b --- /dev/null +++ b/library/std/src/sys/random/zkvm.rs @@ -0,0 +1,21 @@ +use crate::sys::pal::abi; + +pub fn fill_bytes(bytes: &mut [u8]) { + let (pre, words, post) = unsafe { bytes.align_to_mut::() }; + if !words.is_empty() { + unsafe { + abi::sys_rand(words.as_mut_ptr(), words.len()); + } + } + + let mut buf = [0u32; 2]; + let len = (pre.len() + post.len() + size_of::() - 1) / size_of::(); + if len != 0 { + unsafe { abi::sys_rand(buf.as_mut_ptr(), len) }; + } + + let buf = buf.map(u32::to_ne_bytes); + let buf = buf.as_flattened(); + pre.copy_from_slice(&buf[..pre.len()]); + post.copy_from_slice(&buf[pre.len()..pre.len() + post.len()]); +} diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs index 2b4bdfe415c80..5b5e7770b0627 100644 --- a/library/std/src/sys/sync/condvar/pthread.rs +++ b/library/std/src/sys/sync/condvar/pthread.rs @@ -2,7 +2,7 @@ use crate::cell::UnsafeCell; use crate::ptr; use crate::sync::atomic::AtomicPtr; use crate::sync::atomic::Ordering::Relaxed; -use crate::sys::sync::{mutex, Mutex}; +use crate::sys::sync::{Mutex, mutex}; #[cfg(not(target_os = "nto"))] use crate::sys::time::TIMESPEC_MAX; #[cfg(target_os = "nto")] diff --git a/library/std/src/sys/sync/condvar/windows7.rs b/library/std/src/sys/sync/condvar/windows7.rs index 56eeeda551ebb..f03feef222124 100644 --- a/library/std/src/sys/sync/condvar/windows7.rs +++ b/library/std/src/sys/sync/condvar/windows7.rs @@ -1,5 +1,5 @@ use crate::cell::UnsafeCell; -use crate::sys::sync::{mutex, Mutex}; +use crate::sys::sync::{Mutex, mutex}; use crate::sys::{c, os}; use crate::time::Duration; diff --git a/library/std/src/sys/sync/condvar/xous.rs b/library/std/src/sys/sync/condvar/xous.rs index 007383479a100..cb55a3e3369bd 100644 --- a/library/std/src/sys/sync/condvar/xous.rs +++ b/library/std/src/sys/sync/condvar/xous.rs @@ -1,7 +1,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use crate::os::xous::ffi::{blocking_scalar, scalar}; -use crate::os::xous::services::{ticktimer_server, TicktimerScalar}; +use crate::os::xous::services::{TicktimerScalar, ticktimer_server}; use crate::sys::sync::Mutex; use crate::time::Duration; diff --git a/library/std/src/sys/sync/mutex/fuchsia.rs b/library/std/src/sys/sync/mutex/fuchsia.rs index 81a6361a83a49..3e871285bea01 100644 --- a/library/std/src/sys/sync/mutex/fuchsia.rs +++ b/library/std/src/sys/sync/mutex/fuchsia.rs @@ -40,9 +40,9 @@ use crate::sync::atomic::AtomicU32; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sys::futex::zircon::{ - zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t, zx_thread_self, ZX_ERR_BAD_HANDLE, - ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE, ZX_OK, - ZX_TIME_INFINITE, + ZX_ERR_BAD_HANDLE, ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE, + ZX_OK, ZX_TIME_INFINITE, zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t, + zx_thread_self, }; // The lowest two bits of a `zx_handle_t` are always set, so the lowest bit is used to mark the diff --git a/library/std/src/sys/sync/mutex/itron.rs b/library/std/src/sys/sync/mutex/itron.rs index 8440ffdd33772..dcdfff0c81cd7 100644 --- a/library/std/src/sys/sync/mutex/itron.rs +++ b/library/std/src/sys/sync/mutex/itron.rs @@ -3,7 +3,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] use crate::sys::pal::itron::abi; -use crate::sys::pal::itron::error::{expect_success, expect_success_aborting, fail, ItronError}; +use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting, fail}; use crate::sys::pal::itron::spin::SpinIdOnceCell; pub struct Mutex { diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs index ee0794334fbe3..1c407bc253776 100644 --- a/library/std/src/sys/sync/mutex/pthread.rs +++ b/library/std/src/sys/sync/mutex/pthread.rs @@ -1,6 +1,6 @@ use crate::cell::UnsafeCell; use crate::io::Error; -use crate::mem::{forget, MaybeUninit}; +use crate::mem::{MaybeUninit, forget}; use crate::sys::cvt_nz; use crate::sys_common::lazy_box::{LazyBox, LazyInit}; diff --git a/library/std/src/sys/sync/mutex/sgx.rs b/library/std/src/sys/sync/mutex/sgx.rs index d37bd02adf8dd..65d1e880f7baf 100644 --- a/library/std/src/sys/sync/mutex/sgx.rs +++ b/library/std/src/sys/sync/mutex/sgx.rs @@ -1,4 +1,4 @@ -use crate::sys::pal::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable}; +use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable, try_lock_or_false}; use crate::sys_common::lazy_box::{LazyBox, LazyInit}; /// FIXME: `UnsafeList` is not movable. diff --git a/library/std/src/sys/sync/mutex/xous.rs b/library/std/src/sys/sync/mutex/xous.rs index 63efa5a0210ab..233e638f9130b 100644 --- a/library/std/src/sys/sync/mutex/xous.rs +++ b/library/std/src/sys/sync/mutex/xous.rs @@ -1,5 +1,5 @@ use crate::os::xous::ffi::{blocking_scalar, do_yield}; -use crate::os::xous::services::{ticktimer_server, TicktimerScalar}; +use crate::os::xous::services::{TicktimerScalar, ticktimer_server}; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicBool, AtomicUsize}; diff --git a/library/std/src/sys/sync/once/futex.rs b/library/std/src/sys/sync/once/futex.rs index 2c8a054282b01..25588a4217b62 100644 --- a/library/std/src/sys/sync/once/futex.rs +++ b/library/std/src/sys/sync/once/futex.rs @@ -91,6 +91,15 @@ impl Once { } } + #[inline] + pub(crate) fn set_state(&mut self, new_state: ExclusiveState) { + *self.state_and_queued.get_mut() = match new_state { + ExclusiveState::Incomplete => INCOMPLETE, + ExclusiveState::Poisoned => POISONED, + ExclusiveState::Complete => COMPLETE, + }; + } + #[cold] #[track_caller] pub fn wait(&self, ignore_poisoning: bool) { diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs index 12c1d9f5a6c98..cdcffe790f54b 100644 --- a/library/std/src/sys/sync/once/no_threads.rs +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -55,6 +55,15 @@ impl Once { } } + #[inline] + pub(crate) fn set_state(&mut self, new_state: ExclusiveState) { + self.state.set(match new_state { + ExclusiveState::Incomplete => State::Incomplete, + ExclusiveState::Poisoned => State::Poisoned, + ExclusiveState::Complete => State::Complete, + }); + } + #[cold] #[track_caller] pub fn wait(&self, _ignore_poisoning: bool) { diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index 86f72c82008bc..17abaf0bf267b 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -140,6 +140,15 @@ impl Once { } } + #[inline] + pub(crate) fn set_state(&mut self, new_state: ExclusiveState) { + *self.state_and_queue.get_mut() = match new_state { + ExclusiveState::Incomplete => ptr::without_provenance_mut(INCOMPLETE), + ExclusiveState::Poisoned => ptr::without_provenance_mut(POISONED), + ExclusiveState::Complete => ptr::without_provenance_mut(COMPLETE), + }; + } + #[cold] #[track_caller] pub fn wait(&self, ignore_poisoning: bool) { diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs index 458c16516bbe1..0e658328c2e2d 100644 --- a/library/std/src/sys/sync/rwlock/queue.rs +++ b/library/std/src/sys/sync/rwlock/queue.rs @@ -110,7 +110,7 @@ use crate::cell::OnceCell; use crate::hint::spin_loop; use crate::mem; -use crate::ptr::{self, null_mut, without_provenance_mut, NonNull}; +use crate::ptr::{self, NonNull, null_mut, without_provenance_mut}; use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicBool, AtomicPtr}; use crate::thread::{self, Thread}; diff --git a/library/std/src/sys/sync/rwlock/solid.rs b/library/std/src/sys/sync/rwlock/solid.rs index 0537140202091..7703082f95116 100644 --- a/library/std/src/sys/sync/rwlock/solid.rs +++ b/library/std/src/sys/sync/rwlock/solid.rs @@ -2,7 +2,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] use crate::sys::pal::abi; -use crate::sys::pal::itron::error::{expect_success, expect_success_aborting, fail, ItronError}; +use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting, fail}; use crate::sys::pal::itron::spin::SpinIdOnceCell; pub struct RwLock { diff --git a/library/std/src/sys/sync/thread_parking/id.rs b/library/std/src/sys/sync/thread_parking/id.rs index a7b07b509dfd8..6496435183770 100644 --- a/library/std/src/sys/sync/thread_parking/id.rs +++ b/library/std/src/sys/sync/thread_parking/id.rs @@ -10,8 +10,8 @@ use crate::cell::UnsafeCell; use crate::pin::Pin; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; -use crate::sync::atomic::{fence, AtomicI8}; -use crate::sys::thread_parking::{current, park, park_timeout, unpark, ThreadId}; +use crate::sync::atomic::{AtomicI8, fence}; +use crate::sys::thread_parking::{ThreadId, current, park, park_timeout, unpark}; use crate::time::Duration; pub struct Parker { diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs index c64600e9e29c3..5f195d0bb0cf5 100644 --- a/library/std/src/sys/sync/thread_parking/pthread.rs +++ b/library/std/src/sys/sync/thread_parking/pthread.rs @@ -3,7 +3,6 @@ use crate::cell::UnsafeCell; use crate::marker::PhantomPinned; use crate::pin::Pin; -use crate::ptr::addr_of_mut; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; #[cfg(not(target_os = "nto"))] @@ -101,8 +100,8 @@ impl Parker { // This could lead to undefined behaviour when deadlocking. This is avoided // by not deadlocking. Note in particular the unlocking operation before any // panic, as code after the panic could try to park again. - addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY)); - addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); + (&raw mut (*parker).state).write(AtomicUsize::new(EMPTY)); + (&raw mut (*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); cfg_if::cfg_if! { if #[cfg(any( @@ -112,9 +111,9 @@ impl Parker { target_os = "vita", target_vendor = "apple", ))] { - addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); + (&raw mut (*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { - let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null()); + let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), crate::ptr::null()); assert_eq!(r, 0); } else { use crate::mem::MaybeUninit; @@ -123,7 +122,7 @@ impl Parker { assert_eq!(r, 0); let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); assert_eq!(r, 0); - let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr()); + let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), attr.as_ptr()); assert_eq!(r, 0); let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); assert_eq!(r, 0); diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs index 1000b63b6d01a..8f7e66c46ef7f 100644 --- a/library/std/src/sys/sync/thread_parking/windows7.rs +++ b/library/std/src/sys/sync/thread_parking/windows7.rs @@ -178,7 +178,7 @@ impl Parker { } fn ptr(&self) -> *const c_void { - core::ptr::addr_of!(self.state).cast::() + (&raw const self.state).cast::() } } @@ -190,7 +190,7 @@ mod keyed_events { use core::sync::atomic::Ordering::{Acquire, Relaxed}; use core::time::Duration; - use super::{Parker, EMPTY, NOTIFIED}; + use super::{EMPTY, NOTIFIED, Parker}; use crate::sys::c; pub unsafe fn park(parker: Pin<&Parker>) { diff --git a/library/std/src/sys/sync/thread_parking/xous.rs b/library/std/src/sys/sync/thread_parking/xous.rs index 64b6f731f2377..28c90249dc2c2 100644 --- a/library/std/src/sys/sync/thread_parking/xous.rs +++ b/library/std/src/sys/sync/thread_parking/xous.rs @@ -1,5 +1,5 @@ use crate::os::xous::ffi::{blocking_scalar, scalar}; -use crate::os::xous::services::{ticktimer_server, TicktimerScalar}; +use crate::os::xous::services::{TicktimerScalar, ticktimer_server}; use crate::pin::Pin; use crate::ptr; use crate::sync::atomic::AtomicI8; diff --git a/library/std/src/sys/thread_local/destructors/linux_like.rs b/library/std/src/sys/thread_local/destructors/linux_like.rs index c381be0bf8c76..f473dc4d79df5 100644 --- a/library/std/src/sys/thread_local/destructors/linux_like.rs +++ b/library/std/src/sys/thread_local/destructors/linux_like.rs @@ -47,7 +47,7 @@ pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { dtor, ), t.cast(), - core::ptr::addr_of!(__dso_handle) as *mut _, + (&raw const __dso_handle) as *mut _, ); } } else { diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs index 67c3ca8862767..77575547c1498 100644 --- a/library/std/src/sys/thread_local/guard/key.rs +++ b/library/std/src/sys/thread_local/guard/key.rs @@ -4,7 +4,7 @@ use crate::ptr; use crate::sys::thread_local::destructors; -use crate::sys::thread_local::key::{set, LazyKey}; +use crate::sys::thread_local::key::{LazyKey, set}; pub fn enable() { static DTORS: LazyKey = LazyKey::new(Some(run)); diff --git a/library/std/src/sys/thread_local/key/tests.rs b/library/std/src/sys/thread_local/key/tests.rs index d82b34e71f0e4..c7d2c8e6301ef 100644 --- a/library/std/src/sys/thread_local/key/tests.rs +++ b/library/std/src/sys/thread_local/key/tests.rs @@ -1,4 +1,4 @@ -use super::{get, set, LazyKey}; +use super::{LazyKey, get, set}; use crate::ptr; #[test] diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs index 4fb2fdcc61925..295fb848b304d 100644 --- a/library/std/src/sys/thread_local/key/xous.rs +++ b/library/std/src/sys/thread_local/key/xous.rs @@ -39,7 +39,7 @@ use core::arch::asm; use crate::mem::ManuallyDrop; -use crate::os::xous::ffi::{map_memory, unmap_memory, MemoryFlags}; +use crate::os::xous::ffi::{MemoryFlags, map_memory, unmap_memory}; use crate::ptr; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicPtr, AtomicUsize}; diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index e27b47c3f4536..f09c396ef0f1e 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -2,7 +2,7 @@ use super::abort_on_dtor_unwind; use crate::cell::Cell; use crate::marker::PhantomData; use crate::ptr; -use crate::sys::thread_local::key::{get, set, Key, LazyKey}; +use crate::sys::thread_local::key::{Key, LazyKey, get, set}; #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 25ebeb3502d20..5a0ad90758101 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -5,7 +5,7 @@ use crate::ffi::{c_int, c_void}; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::sys::common::small_c_string::run_with_cstr; -use crate::sys::net::{cvt, cvt_gai, cvt_r, init, netc as c, wrlen_t, Socket}; +use crate::sys::net::{Socket, cvt, cvt_gai, cvt_r, init, netc as c, wrlen_t}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use crate::{cmp, fmt, mem, ptr}; @@ -21,6 +21,7 @@ cfg_if::cfg_if! { target_os = "haiku", target_os = "l4re", target_os = "nto", + target_os = "nuttx", target_vendor = "apple", ))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; @@ -73,7 +74,7 @@ pub fn setsockopt( sock.as_raw(), level, option_name, - core::ptr::addr_of!(option_value) as *const _, + (&raw const option_value) as *const _, mem::size_of::() as c::socklen_t, ))?; Ok(()) @@ -88,7 +89,7 @@ pub fn getsockopt(sock: &Socket, level: c_int, option_name: c_int) -> i sock.as_raw(), level, option_name, - core::ptr::addr_of_mut!(option_value) as *mut _, + (&raw mut option_value) as *mut _, &mut option_len, ))?; Ok(option_value) @@ -102,7 +103,7 @@ where unsafe { let mut storage: c::sockaddr_storage = mem::zeroed(); let mut len = mem::size_of_val(&storage) as c::socklen_t; - cvt(f(core::ptr::addr_of_mut!(storage) as *mut _, &mut len))?; + cvt(f((&raw mut storage) as *mut _, &mut len))?; sockaddr_to_addr(&storage, len as usize) } } @@ -451,7 +452,7 @@ impl TcpListener { pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as c::socklen_t; - let sock = self.inner.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?; + let sock = self.inner.accept((&raw mut storage) as *mut _, &mut len)?; let addr = sockaddr_to_addr(&storage, len as usize)?; Ok((TcpStream { inner: sock }, addr)) } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 063451ad54e1c..19d4c94f45099 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -18,7 +18,7 @@ #[cfg(test)] mod tests; -use core::char::{encode_utf16_raw, encode_utf8_raw}; +use core::char::{encode_utf8_raw, encode_utf16_raw}; use core::clone::CloneToUninit; use core::str::next_code_point; @@ -26,7 +26,6 @@ use crate::borrow::Cow; use crate::collections::TryReserveError; use crate::hash::{Hash, Hasher}; use crate::iter::FusedIterator; -use crate::ptr::addr_of_mut; use crate::rc::Rc; use crate::sync::Arc; use crate::sys_common::AsInner; @@ -1055,6 +1054,6 @@ unsafe impl CloneToUninit for Wtf8 { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around [u8] - unsafe { self.bytes.clone_to_uninit(addr_of_mut!((*dst).bytes)) } + unsafe { self.bytes.clone_to_uninit(&raw mut (*dst).bytes) } } } diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs index b57c99a8452a1..bc06eaa2b8fa1 100644 --- a/library/std/src/sys_common/wtf8/tests.rs +++ b/library/std/src/sys_common/wtf8/tests.rs @@ -356,32 +356,32 @@ fn wtf8buf_from_iterator() { fn f(values: &[u32]) -> Wtf8Buf { values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() } - assert_eq!( - f(&[0x61, 0xE9, 0x20, 0x1F4A9]), - Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } - ); + assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]), Wtf8Buf { + bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), + is_known_utf8: true + }); assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!( - f(&[0xD83D, 0x20, 0xDCA9]), - Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } - ); - assert_eq!( - f(&[0xD800, 0xDBFF]), - Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } - ); - assert_eq!( - f(&[0xD800, 0xE000]), - Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - f(&[0xD7FF, 0xDC00]), - Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - f(&[0x61, 0xDC00]), - Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); + assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]), Wtf8Buf { + bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), + is_known_utf8: false + }); + assert_eq!(f(&[0xD800, 0xDBFF]), Wtf8Buf { + bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), + is_known_utf8: false + }); + assert_eq!(f(&[0xD800, 0xE000]), Wtf8Buf { + bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), + is_known_utf8: false + }); + assert_eq!(f(&[0xD7FF, 0xDC00]), Wtf8Buf { + bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), + is_known_utf8: false + }); + assert_eq!(f(&[0x61, 0xDC00]), Wtf8Buf { + bytes: b"\x61\xED\xB0\x80".to_vec(), + is_known_utf8: false + }); assert_eq!(f(&[0xDC00]), Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false }); } @@ -396,36 +396,36 @@ fn wtf8buf_extend() { string } - assert_eq!( - e(&[0x61, 0xE9], &[0x20, 0x1F4A9]), - Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } - ); + assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]), Wtf8Buf { + bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), + is_known_utf8: true + }); assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!( - e(&[0xD83D, 0x20], &[0xDCA9]), - Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[0xD800], &[0xDBFF]), - Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[0xD800], &[0xE000]), - Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[0xD7FF], &[0xDC00]), - Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[0x61], &[0xDC00]), - Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[], &[0xDC00]), - Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); + assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]), Wtf8Buf { + bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), + is_known_utf8: false + }); + assert_eq!(e(&[0xD800], &[0xDBFF]), Wtf8Buf { + bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), + is_known_utf8: false + }); + assert_eq!(e(&[0xD800], &[0xE000]), Wtf8Buf { + bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), + is_known_utf8: false + }); + assert_eq!(e(&[0xD7FF], &[0xDC00]), Wtf8Buf { + bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), + is_known_utf8: false + }); + assert_eq!(e(&[0x61], &[0xDC00]), Wtf8Buf { + bytes: b"\x61\xED\xB0\x80".to_vec(), + is_known_utf8: false + }); + assert_eq!(e(&[], &[0xDC00]), Wtf8Buf { + bytes: b"\xED\xB0\x80".to_vec(), + is_known_utf8: false + }); } #[test] @@ -556,10 +556,9 @@ fn wtf8_encode_wide() { let mut string = Wtf8Buf::from_str("aé "); string.push(CodePoint::from_u32(0xD83D).unwrap()); string.push_char('💩'); - assert_eq!( - string.encode_wide().collect::>(), - vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] - ); + assert_eq!(string.encode_wide().collect::>(), vec![ + 0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9 + ]); } #[test] diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs index 25019b554bb6a..6abb9b85a2e29 100644 --- a/library/std/src/thread/local/tests.rs +++ b/library/std/src/thread/local/tests.rs @@ -103,6 +103,9 @@ fn smoke_dtor() { #[test] fn circular() { + // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint + #![allow(static_mut_refs)] + struct S1(&'static LocalKey>>, &'static LocalKey>>); struct S2(&'static LocalKey>>, &'static LocalKey>>); thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e29c28f3c7ec2..41f02af93668e 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -162,12 +162,11 @@ use crate::any::Any; use crate::cell::{Cell, OnceCell, UnsafeCell}; use crate::ffi::CStr; use crate::marker::PhantomData; -use crate::mem::{self, forget, ManuallyDrop}; +use crate::mem::{self, ManuallyDrop, forget}; use crate::num::NonZero; use crate::pin::Pin; -use crate::ptr::addr_of_mut; -use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::Arc; +use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::sync::Parker; use crate::sys::thread as imp; use crate::sys_common::{AsInner, IntoInner}; @@ -178,7 +177,7 @@ use crate::{env, fmt, io, panic, panicking, str}; mod scoped; #[stable(feature = "scoped_threads", since = "1.63.0")] -pub use scoped::{scope, Scope, ScopedJoinHandle}; +pub use scoped::{Scope, ScopedJoinHandle, scope}; //////////////////////////////////////////////////////////////////////////////// // Thread-local storage @@ -432,7 +431,7 @@ impl Builder { /// ``` /// /// [`io::Result`]: crate::io::Result - #[stable(feature = "thread_spawn_unchecked", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "thread_spawn_unchecked", since = "1.82.0")] pub unsafe fn spawn_unchecked(self, f: F) -> io::Result> where F: FnOnce() -> T, @@ -1386,9 +1385,9 @@ impl Thread { let inner = unsafe { let mut arc = Arc::::new_uninit(); let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr(); - addr_of_mut!((*ptr).name).write(name); - addr_of_mut!((*ptr).id).write(ThreadId::new()); - Parker::new_in_place(addr_of_mut!((*ptr).parker)); + (&raw mut (*ptr).name).write(name); + (&raw mut (*ptr).id).write(ThreadId::new()); + Parker::new_in_place(&raw mut (*ptr).parker); Pin::new_unchecked(arc.assume_init()) }; @@ -1503,6 +1502,54 @@ impl Thread { self.inner.name.as_str() } + /// Consumes the `Thread`, returning a raw pointer. + /// + /// To avoid a memory leak the pointer must be converted + /// back into a `Thread` using [`Thread::from_raw`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(thread_raw)] + /// + /// use std::thread::{self, Thread}; + /// + /// let thread = thread::current(); + /// let id = thread.id(); + /// let ptr = Thread::into_raw(thread); + /// unsafe { + /// assert_eq!(Thread::from_raw(ptr).id(), id); + /// } + /// ``` + #[unstable(feature = "thread_raw", issue = "97523")] + pub fn into_raw(self) -> *const () { + // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant. + let inner = unsafe { Pin::into_inner_unchecked(self.inner) }; + Arc::into_raw(inner) as *const () + } + + /// Constructs a `Thread` from a raw pointer. + /// + /// The raw pointer must have been previously returned + /// by a call to [`Thread::into_raw`]. + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead + /// to memory unsafety, even if the returned `Thread` is never + /// accessed. + /// + /// Creating a `Thread` from a pointer other than one returned + /// from [`Thread::into_raw`] is **undefined behavior**. + /// + /// Calling this function twice on the same raw pointer can lead + /// to a double-free if both `Thread` instances are dropped. + #[unstable(feature = "thread_raw", issue = "97523")] + pub unsafe fn from_raw(ptr: *const ()) -> Thread { + // Safety: Upheld by caller. + unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } } + } + fn cname(&self) -> Option<&CStr> { self.inner.name.as_cstr() } diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index ba27c9220aea5..b2305b1eda7e1 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -1,8 +1,8 @@ -use super::{current, park, Builder, JoinInner, Result, Thread}; +use super::{Builder, JoinInner, Result, Thread, current, park}; use crate::marker::PhantomData; -use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; -use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; use crate::sync::Arc; +use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use crate::{fmt, io}; /// A scope to spawn scoped threads in. diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index aa464d56f95b2..ff45e82bd9c71 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -2,7 +2,7 @@ use super::Builder; use crate::any::Any; use crate::panic::panic_any; use crate::sync::atomic::{AtomicBool, Ordering}; -use crate::sync::mpsc::{channel, Sender}; +use crate::sync::mpsc::{Sender, channel}; use crate::sync::{Arc, Barrier}; use crate::thread::{self, Scope, ThreadId}; use crate::time::{Duration, Instant}; diff --git a/library/std/src/time.rs b/library/std/src/time.rs index ae46670c25e61..f28a0568a3c3d 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -280,6 +280,7 @@ impl Instant { /// ``` #[must_use] #[stable(feature = "time2", since = "1.8.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "instant_now")] pub fn now() -> Instant { Instant(time::Instant::now()) } diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs index de36dc4c9fd16..e88f2d5e80676 100644 --- a/library/std/src/time/tests.rs +++ b/library/std/src/time/tests.rs @@ -1,7 +1,7 @@ use core::fmt::Debug; #[cfg(not(target_arch = "wasm32"))] -use test::{black_box, Bencher}; +use test::{Bencher, black_box}; use super::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -235,8 +235,8 @@ macro_rules! bench_instant_threaded { #[bench] #[cfg(not(target_arch = "wasm32"))] fn $bench_name(b: &mut Bencher) -> crate::thread::Result<()> { - use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::Arc; + use crate::sync::atomic::{AtomicBool, Ordering}; let running = Arc::new(AtomicBool::new(true)); diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index 79a981d0b0d18..fc9917178b244 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -37,3 +37,21 @@ fn thread_local_containing_const_statements() { assert_eq!(CELL.get(), 1); assert_eq!(REFCELL.take(), 1); } + +#[test] +// Include an ignore list on purpose, so that new platforms don't miss it +#[cfg_attr( + any( + target_os = "redox", + target_os = "l4re", + target_env = "sgx", + target_os = "solid_asp3", + target_os = "teeos", + target_os = "wasi" + ), + should_panic +)] +fn available_parallelism() { + // check that std::thread::available_parallelism() returns a valid value + assert!(thread::available_parallelism().is_ok()); +} diff --git a/library/stdarch b/library/stdarch index d9466edb4c53c..ace72223a0e32 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit d9466edb4c53cece8686ee6e17b028436ddf4151 +Subproject commit ace72223a0e321c1b0a37b5862aa756fe8ab5111 diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs index b71def3b03223..62e51026b818c 100644 --- a/library/test/src/bench.rs +++ b/library/test/src/bench.rs @@ -1,15 +1,15 @@ //! Benchmarking module. -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{AssertUnwindSafe, catch_unwind}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use std::{cmp, io}; +use super::Sender; use super::event::CompletedTest; use super::options::BenchMode; use super::test_result::TestResult; use super::types::{TestDesc, TestId}; -use super::Sender; use crate::stats; /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 632f8d161affa..4b2c65cfdf548 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -18,6 +18,7 @@ #![doc(test(attr(deny(warnings))))] #![doc(rust_logo)] #![feature(rustdoc_internals)] +#![feature(file_buffered)] #![feature(internal_output_capture)] #![feature(staged_api)] #![feature(process_exitcode_internals)] @@ -28,17 +29,17 @@ pub use cli::TestOpts; -pub use self::bench::{black_box, Bencher}; +pub use self::ColorConfig::*; +pub use self::bench::{Bencher, black_box}; pub use self::console::run_tests_console; pub use self::options::{ColorConfig, Options, OutputFormat, RunIgnored, ShouldPanic}; pub use self::types::TestName::*; pub use self::types::*; -pub use self::ColorConfig::*; // Module to be used by rustc to compile tests in libtest pub mod test { pub use crate::bench::Bencher; - pub use crate::cli::{parse_opts, TestOpts}; + pub use crate::cli::{TestOpts, parse_opts}; pub use crate::helpers::metrics::{Metric, MetricMap}; pub use crate::options::{Options, RunIgnored, RunStrategy, ShouldPanic}; pub use crate::test_result::{TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk}; @@ -53,9 +54,9 @@ pub mod test { use std::collections::VecDeque; use std::io::prelude::Write; use std::mem::ManuallyDrop; -use std::panic::{self, catch_unwind, AssertUnwindSafe, PanicHookInfo}; +use std::panic::{self, AssertUnwindSafe, PanicHookInfo, catch_unwind}; use std::process::{self, Command, Termination}; -use std::sync::mpsc::{channel, Sender}; +use std::sync::mpsc::{Sender, channel}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use std::{env, io, thread}; diff --git a/library/test/src/term/terminfo/mod.rs b/library/test/src/term/terminfo/mod.rs index 67eec3ca50f48..974b8afd598dd 100644 --- a/library/test/src/term/terminfo/mod.rs +++ b/library/test/src/term/terminfo/mod.rs @@ -3,15 +3,14 @@ use std::collections::HashMap; use std::fs::File; use std::io::prelude::*; -use std::io::{self, BufReader}; use std::path::Path; -use std::{env, error, fmt}; +use std::{env, error, fmt, io}; -use parm::{expand, Param, Variables}; +use parm::{Param, Variables, expand}; use parser::compiled::{msys_terminfo, parse}; use searcher::get_dbpath_for_term; -use super::{color, Terminal}; +use super::{Terminal, color}; /// A parsed terminfo database entry. #[allow(unused)] @@ -102,8 +101,7 @@ impl TermInfo { } // Keep the metadata small fn _from_path(path: &Path) -> Result { - let file = File::open(path).map_err(Error::IoError)?; - let mut reader = BufReader::new(file); + let mut reader = File::open_buffered(path).map_err(Error::IoError)?; parse(&mut reader, false).map_err(Error::MalformedTerminfo) } } diff --git a/library/test/src/term/win.rs b/library/test/src/term/win.rs index ce9cad37f306b..c77e6aac478bc 100644 --- a/library/test/src/term/win.rs +++ b/library/test/src/term/win.rs @@ -5,7 +5,7 @@ use std::io; use std::io::prelude::*; -use super::{color, Terminal}; +use super::{Terminal, color}; /// A Terminal implementation that uses the Win32 Console API. pub(crate) struct WinConsole { diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index ba2f35362c54f..e85e61090a91b 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -3,11 +3,11 @@ use crate::{ console::OutputLocation, formatters::PrettyFormatter, test::{ - parse_opts, MetricMap, // FIXME (introduced by #65251) // ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TestTimeOptions, // TestType, TrFailedMsg, TrIgnored, TrOk, + parse_opts, }, time::{TestTimeOptions, TimeThreshold}, }; diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index bbd1db8dfa57f..590de31a678ca 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -34,3 +34,10 @@ llvm-libunwind = [] # If crt-static is enabled, static link to `libunwind.a` provided by system # If crt-static is disabled, dynamic link to `libunwind.so` provided by system system-llvm-libunwind = [] + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + # #[cfg(bootstrap)] rtems + 'cfg(target_os, values("rtems"))', +] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 250af912e072d..46026324d2f82 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -22,6 +22,8 @@ cfg_if::cfg_if! { target_os = "l4re", target_os = "none", target_os = "espidf", + target_os = "rtems", + target_os = "nuttx", ))] { // These "unix" family members do not have unwinder. } else if #[cfg(any( diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index e5e28f32e4dbf..715f8b57876ae 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -33,10 +33,10 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(all(target_arch = "x86_64", target_os = "windows"))] pub const unwinder_private_data_size: usize = 6; -#[cfg(all(target_arch = "arm", not(all(target_vendor = "apple", not(target_os = "watchos")))))] +#[cfg(all(target_arch = "arm", not(target_vendor = "apple")))] pub const unwinder_private_data_size: usize = 20; -#[cfg(all(target_arch = "arm", all(target_vendor = "apple", not(target_os = "watchos"))))] +#[cfg(all(target_arch = "arm", target_vendor = "apple"))] pub const unwinder_private_data_size: usize = 5; #[cfg(all(target_arch = "aarch64", target_pointer_width = "64", not(target_os = "windows")))] @@ -123,8 +123,11 @@ extern "C" { } cfg_if::cfg_if! { -if #[cfg(any(all(target_vendor = "apple", not(target_os = "watchos")), target_os = "netbsd", not(target_arch = "arm")))] { +if #[cfg(any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "arm")))] { // Not ARM EHABI + // + // 32-bit ARM on iOS/tvOS/watchOS use either DWARF/Compact unwinding or + // "setjmp-longjmp" / SjLj unwinding. #[repr(C)] #[derive(Copy, Clone, PartialEq)] pub enum _Unwind_Action { @@ -219,14 +222,14 @@ if #[cfg(any(all(target_vendor = "apple", not(target_os = "watchos")), target_os pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word { let mut val: _Unwind_Word = core::ptr::null(); _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - core::ptr::addr_of_mut!(val) as *mut c_void); + (&raw mut val) as *mut c_void); val } pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) { let mut value = value; _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - core::ptr::addr_of_mut!(value) as *mut c_void); + (&raw mut value) as *mut c_void); } pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) @@ -259,8 +262,8 @@ if #[cfg(any(all(target_vendor = "apple", not(target_os = "watchos")), target_os cfg_if::cfg_if! { if #[cfg(all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm"))] { - // 32-bit ARM Apple (except for watchOS) uses SjLj and does not provide - // _Unwind_Backtrace() + // 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj and + // does not provide _Unwind_Backtrace() extern "C-unwind" { pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } diff --git a/library/unwind/src/unwinding.rs b/library/unwind/src/unwinding.rs index b3460791ce5ca..1b94005ab6cd0 100644 --- a/library/unwind/src/unwinding.rs +++ b/library/unwind/src/unwinding.rs @@ -32,7 +32,7 @@ pub use unwinding::abi::{UnwindContext, UnwindException}; pub enum _Unwind_Context {} pub use unwinding::custom_eh_frame_finder::{ - set_custom_eh_frame_finder, EhFrameFinder, FrameInfo, FrameInfoKind, + EhFrameFinder, FrameInfo, FrameInfoKind, set_custom_eh_frame_finder, }; pub type _Unwind_Exception_Class = u64; diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index 1965b6cf4ce8f..395cd6a4bab55 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -38,4 +38,5 @@ pub macro link { #[link(name = "ntdll")] #[link(name = "userenv")] #[link(name = "ws2_32")] +#[link(name = "dbghelp")] // required for backtrace-rs symbolization extern "C" {} diff --git a/rustfmt.toml b/rustfmt.toml index 60cd03484007d..4d48236a393c4 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,5 +1,5 @@ # Run rustfmt with this config (it should be picked up automatically). -version = "Two" +style_edition = "2024" use_small_heuristics = "Max" merge_derives = false group_imports = "StdExternalCrate" @@ -45,6 +45,7 @@ ignore = [ "src/tools/rust-analyzer", "src/tools/rustc-perf", "src/tools/rustfmt", + "src/gcc", # These are ignored by a standard cargo fmt run. "compiler/rustc_codegen_cranelift/scripts", diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 357c6175152d4..952db063636e0 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -84,9 +84,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.97" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -536,6 +539,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "syn" version = "2.0.75" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 07f7444aaff64..1959d0a9662da 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -37,7 +37,7 @@ test = false # Most of the time updating these dependencies requires modifications to the # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565); # otherwise, some targets will fail. That's why these dependencies are explicitly pinned. -cc = "=1.0.97" +cc = "=1.1.19" cmake = "=0.1.48" build_helper = { path = "../tools/build_helper" } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 71f69e03a9fee..666df49012c13 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -106,22 +106,29 @@ def _download(path, url, probably_big, verbose, exception): try: if (probably_big or verbose) and "GITHUB_ACTIONS" not in os.environ: - option = "-#" + option = "--progress-bar" else: - option = "-s" + option = "--silent" # If curl is not present on Win32, we should not sys.exit # but raise `CalledProcessError` or `OSError` instead require(["curl", "--version"], exception=platform_is_win32()) extra_flags = [] if curl_version() > (7, 70): extra_flags = [ "--retry-all-errors" ] + # options should be kept in sync with + # src/bootstrap/src/core/download.rs + # for consistency. + # they are also more compreprensivly explained in that file. run(["curl", option] + extra_flags + [ - "-L", # Follow redirect. - "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds - "--connect-timeout", "30", # timeout if cannot connect within 30 seconds - "-o", path, + # Follow redirect. + "--location", + # timeout if speed is < 10 bytes/sec for > 30 seconds + "--speed-time", "30", "--speed-limit", "10", + # timeout if cannot connect within 30 seconds + "--connect-timeout", "30", + "--output", path, "--continue-at", "-", - "--retry", "3", "-SRf", url], + "--retry", "3", "--show-error", "--remote-time", "--fail", url], verbose=verbose, exception=True, # Will raise RuntimeError on failure ) diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 768aac912ce47..49d564642bd65 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -71,6 +71,7 @@ def v(*args): # channel, etc. o("optimize-llvm", "llvm.optimize", "build optimized LLVM") o("llvm-assertions", "llvm.assertions", "build LLVM with assertions") +o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme") o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface") o("debug-assertions", "rust.debug-assertions", "build with debugging assertions") o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions") diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index 789586b58f706..147939d2047e8 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -27,4 +27,5 @@ assertions = false # Enable warnings during the LLVM compilation (when LLVM is changed, causing a compilation) enable-warnings = true # Will download LLVM from CI if available on your platform. -download-ci-llvm = "if-unchanged" +# If you intend to modify `src/llvm-project`, use `"if-unchanged"` or `false` instead. +download-ci-llvm = true diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml index 087544397f5ea..5447565a4b04c 100644 --- a/src/bootstrap/defaults/config.library.toml +++ b/src/bootstrap/defaults/config.library.toml @@ -13,4 +13,5 @@ lto = "off" [llvm] # Will download LLVM from CI if available on your platform. -download-ci-llvm = "if-unchanged" +# If you intend to modify `src/llvm-project`, use `"if-unchanged"` or `false` instead. +download-ci-llvm = true diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml index 75ad37ce33549..efb56996bcd45 100644 --- a/src/bootstrap/defaults/config.tools.toml +++ b/src/bootstrap/defaults/config.tools.toml @@ -17,4 +17,5 @@ compiler-docs = true [llvm] # Will download LLVM from CI if available on your platform. -download-ci-llvm = "if-unchanged" +# If you intend to modify `src/llvm-project`, use `"if-unchanged"` or `false` instead. +download-ci-llvm = true diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 909015305015b..42cecbf5df9bb 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/129116 +Last change is for: https://github.com/rust-lang/rust/pull/129788 diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 9acd85cddde6a..92c8f5dc452fc 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -54,30 +54,34 @@ check-aux: src/etc/test-float-parse \ $(BOOTSTRAP_ARGS) # Run standard library tests in Miri. - $(Q)BOOTSTRAP_SKIP_TARGET_SANITY=1 \ - $(BOOTSTRAP) miri --stage 2 \ + $(Q)$(BOOTSTRAP) miri --stage 2 \ library/core \ library/alloc \ + $(BOOTSTRAP_ARGS) \ --no-doc # Some doctests use file system operations to demonstrate dealing with `Result`. $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/core \ library/alloc \ + $(BOOTSTRAP_ARGS) \ --doc # In `std` we cannot test everything, so we skip some modules. $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 library/std \ + $(BOOTSTRAP_ARGS) \ --no-doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 library/std \ + $(BOOTSTRAP_ARGS) \ --doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: # Also test some very target-specific modules on other targets # (making sure to cover an i686 target as well). $(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ $(BOOTSTRAP) miri --stage 2 library/std \ + $(BOOTSTRAP_ARGS) \ --target aarch64-apple-darwin,i686-pc-windows-msvc \ --no-doc -- \ time:: sync:: thread:: env:: @@ -91,7 +95,7 @@ install: tidy: $(Q)$(BOOTSTRAP) test --stage 2 src/tools/tidy $(BOOTSTRAP_ARGS) prepare: - $(Q)$(BOOTSTRAP) build --stage 2 nonexistent/path/to/trigger/cargo/metadata + $(Q)$(BOOTSTRAP) build --stage 2 --dry-run ## MSVC native builders diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index f03f03e2d9398..b9df7336cca0b 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -11,8 +11,8 @@ use std::str::FromStr; use std::{env, process}; use bootstrap::{ - find_recent_config_change_ids, human_readable_changes, t, Build, Config, Flags, Subcommand, - CONFIG_CHANGE_HISTORY, + Build, CONFIG_CHANGE_HISTORY, Config, Flags, Subcommand, find_recent_config_change_ids, + human_readable_changes, t, }; fn main() { diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 7f7faf077d047..7671fc7e013b7 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -5,9 +5,9 @@ use std::path::PathBuf; use crate::core::build_steps::compile::{ add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, }; -use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType}; +use crate::core::build_steps::tool::{SourceType, prepare_tool_cargo}; use crate::core::builder::{ - self, crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step, + self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description, }; use crate::core::config::TargetSelection; use crate::{Compiler, Mode, Subcommand}; @@ -228,7 +228,7 @@ impl Step for Rustc { self.override_build_kind.unwrap_or(builder.kind), ); - rustc_cargo(builder, &mut cargo, target, &compiler); + rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); // For ./x.py clippy, don't run with --all-targets because // linting tests and benchmarks can produce very noisy results diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index f608e5d715e49..040690623a108 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -9,7 +9,7 @@ use std::fs; use std::io::{self, ErrorKind}; use std::path::Path; -use crate::core::builder::{crate_description, Builder, RunConfig, ShouldRun, Step}; +use crate::core::builder::{Builder, RunConfig, ShouldRun, Step, crate_description}; use crate::utils::helpers::t; use crate::{Build, Compiler, Kind, Mode, Subcommand}; diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index a2bb03cd5ac81..cd198c425c008 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -1,12 +1,12 @@ //! Implementation of running clippy on the compiler, standard library and various tools. use super::compile::{librustc_stamp, libstd_stamp, run_cargo, rustc_cargo, std_cargo}; -use super::tool::{prepare_tool_cargo, SourceType}; +use super::tool::{SourceType, prepare_tool_cargo}; use super::{check, compile}; use crate::builder::{Builder, ShouldRun}; use crate::core::build_steps::compile::std_crates_for_run_make; use crate::core::builder; -use crate::core::builder::{crate_description, Alias, Kind, RunConfig, Step}; +use crate::core::builder::{Alias, Kind, RunConfig, Step, crate_description}; use crate::{Mode, Subcommand, TargetSelection}; /// Disable the most spammy clippy lints @@ -197,7 +197,7 @@ impl Step for Rustc { Kind::Clippy, ); - rustc_cargo(builder, &mut cargo, target, &compiler); + rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); // Explicitly pass -p for all compiler crates -- this will force cargo // to also lint the tests/benches/examples for these crates, rather diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index edf18e2ebf33b..0e596f0da0ec7 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -9,27 +9,27 @@ use std::borrow::Cow; use std::collections::HashSet; use std::ffi::OsStr; -use std::io::prelude::*; use std::io::BufReader; +use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Stdio; use std::{env, fs, str}; +use build_helper::git::get_closest_merge_commit; use serde_derive::Deserialize; use crate::core::build_steps::tool::SourceType; use crate::core::build_steps::{dist, llvm}; use crate::core::builder; use crate::core::builder::{ - crate_description, Builder, Cargo, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath, + Builder, Cargo, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath, crate_description, }; use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; use crate::utils::exec::command; use crate::utils::helpers::{ - self, exe, get_clang_cl_resource_dir, get_closest_merge_base_commit, is_debug_info, is_dylib, - symlink_dir, t, up_to_date, + self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; -use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS}; +use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Std { @@ -127,13 +127,9 @@ impl Step for Std { // the `rust.download-rustc=true` option. let force_recompile = if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() { - let closest_merge_commit = get_closest_merge_base_commit( - Some(&builder.src), - &builder.config.git_config(), - &builder.config.stage0_metadata.config.git_merge_commit_email, - &[], - ) - .unwrap(); + let closest_merge_commit = + get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[]) + .unwrap(); // Check if `library` has changes (returns false otherwise) !t!(helpers::git(Some(&builder.src)) @@ -931,7 +927,12 @@ impl Step for Rustc { // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler, // so its artifacts can't be reused. if builder.download_rustc() && compiler.stage != 0 { - builder.ensure(Sysroot { compiler, force_recompile: false }); + let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false }); + cp_rustc_component_to_ci_sysroot( + builder, + &sysroot, + builder.config.ci_rustc_dev_contents(), + ); return compiler.stage; } @@ -983,7 +984,7 @@ impl Step for Rustc { Kind::Build, ); - rustc_cargo(builder, &mut cargo, target, &compiler); + rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); // NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be // consistently applied by check/doc/test modes too. @@ -1042,10 +1043,11 @@ pub fn rustc_cargo( cargo: &mut Cargo, target: TargetSelection, compiler: &Compiler, + crates: &[String], ) { cargo .arg("--features") - .arg(builder.rustc_features(builder.kind, target)) + .arg(builder.rustc_features(builder.kind, target, crates)) .arg("--manifest-path") .arg(builder.src.join("compiler/rustc/Cargo.toml")); @@ -1055,6 +1057,10 @@ pub fn rustc_cargo( // killed, rather than having an error bubble up and cause a panic. cargo.rustflag("-Zon-broken-pipe=kill"); + if builder.config.llvm_enzyme { + cargo.rustflag("-l").rustflag("Enzyme-19"); + } + // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary // and may just be a time sink. if compiler.stage != 0 { @@ -1189,6 +1195,10 @@ pub fn rustc_cargo_env( cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); } + if builder.config.llvm_enzyme { + cargo.rustflag("--cfg=llvm_enzyme"); + } + // Note that this is disabled if LLVM itself is disabled or we're in a check // build. If we are in a check build we still go ahead here presuming we've // detected that LLVM is already built and good to go which helps prevent @@ -1692,16 +1702,8 @@ impl Step for Sysroot { build_helper::exit!(1); } - // Unlike rust-src component, we have to handle rustc-src a bit differently. - // When using CI rustc, we copy rustc-src component from its sysroot, - // otherwise we handle it in a similar way what we do for rust-src above. - if builder.download_rustc() { - cp_rustc_component_to_ci_sysroot( - builder, - &sysroot, - builder.config.ci_rustc_dev_contents(), - ); - } else { + // rustc-src component is already part of CI rustc's sysroot + if !builder.download_rustc() { let sysroot_lib_rustlib_rustcsrc = sysroot.join("lib/rustlib/rustc-src"); t!(fs::create_dir_all(&sysroot_lib_rustlib_rustcsrc)); let sysroot_lib_rustlib_rustcsrc_rust = sysroot_lib_rustlib_rustcsrc.join("rust"); @@ -1762,6 +1764,49 @@ impl Step for Assemble { return target_compiler; } + // We prepend this bin directory to the user PATH when linking Rust binaries. To + // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. + let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host); + let libdir_bin = libdir.parent().unwrap().join("bin"); + t!(fs::create_dir_all(&libdir_bin)); + + if builder.config.llvm_enabled(target_compiler.host) { + let llvm::LlvmResult { llvm_config, .. } = + builder.ensure(llvm::Llvm { target: target_compiler.host }); + if !builder.config.dry_run() && builder.config.llvm_tools_enabled { + let llvm_bin_dir = + command(llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); + let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); + + // Since we've already built the LLVM tools, install them to the sysroot. + // This is the equivalent of installing the `llvm-tools-preview` component via + // rustup, and lets developers use a locally built toolchain to + // build projects that expect llvm tools to be present in the sysroot + // (e.g. the `bootimage` crate). + for tool in LLVM_TOOLS { + let tool_exe = exe(tool, target_compiler.host); + let src_path = llvm_bin_dir.join(&tool_exe); + // When using `download-ci-llvm`, some of the tools + // may not exist, so skip trying to copy them. + if src_path.exists() { + builder.copy_link(&src_path, &libdir_bin.join(&tool_exe)); + } + } + } + } + + let maybe_install_llvm_bitcode_linker = |compiler| { + if builder.config.llvm_bitcode_linker_enabled { + let src_path = builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker { + compiler, + target: target_compiler.host, + extra_features: vec![], + }); + let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); + builder.copy_link(&src_path, &libdir_bin.join(tool_exe)); + } + }; + // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0. if builder.download_rustc() { builder.ensure(Std::new(target_compiler, target_compiler.host)); @@ -1774,6 +1819,9 @@ impl Step for Assemble { if target_compiler.stage == builder.top_stage { builder.info(&format!("Creating a sysroot for stage{stage} compiler (use `rustup toolchain link 'name' build/host/stage{stage}`)", stage=target_compiler.stage)); } + + maybe_install_llvm_bitcode_linker(target_compiler); + return target_compiler; } @@ -1792,6 +1840,24 @@ impl Step for Assemble { // use that to bootstrap this compiler forward. let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); + // Build enzyme + let enzyme_install = if builder.config.llvm_enzyme { + Some(builder.ensure(llvm::Enzyme { target: build_compiler.host })) + } else { + None + }; + + if let Some(enzyme_install) = enzyme_install { + let lib_ext = std::env::consts::DLL_EXTENSION; + let src_lib = enzyme_install.join("build/Enzyme/libEnzyme-19").with_extension(lib_ext); + let libdir = builder.sysroot_libdir(build_compiler, build_compiler.host); + let target_libdir = builder.sysroot_libdir(target_compiler, target_compiler.host); + let dst_lib = libdir.join("libEnzyme-19").with_extension(lib_ext); + let target_dst_lib = target_libdir.join("libEnzyme-19").with_extension(lib_ext); + builder.copy_link(&src_lib, &dst_lib); + builder.copy_link(&src_lib, &target_dst_lib); + } + // Build the libraries for this compiler to link to (i.e., the libraries // it uses at runtime). NOTE: Crates the target compiler compiles don't // link to these. (FIXME: Is that correct? It seems to be correct most @@ -1864,11 +1930,6 @@ impl Step for Assemble { copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); - // We prepend this bin directory to the user PATH when linking Rust binaries. To - // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. - let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host); - let libdir_bin = libdir.parent().unwrap().join("bin"); - t!(fs::create_dir_all(&libdir_bin)); if let Some(lld_install) = lld_install { let src_exe = exe("lld", target_compiler.host); let dst_exe = exe("rust-lld", target_compiler.host); @@ -1892,7 +1953,7 @@ impl Step for Assemble { // delegates to the `rust-lld` binary for linking and then runs // logic to create the final binary. This is used by the // `wasm32-wasip2` target of Rust. - if builder.build_wasm_component_ld() { + if builder.tool_enabled("wasm-component-ld") { let wasm_component_ld_exe = builder.ensure(crate::core::build_steps::tool::WasmComponentLd { compiler: build_compiler, @@ -1904,40 +1965,7 @@ impl Step for Assemble { ); } - if builder.config.llvm_enabled(target_compiler.host) { - let llvm::LlvmResult { llvm_config, .. } = - builder.ensure(llvm::Llvm { target: target_compiler.host }); - if !builder.config.dry_run() && builder.config.llvm_tools_enabled { - let llvm_bin_dir = - command(llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); - let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); - - // Since we've already built the LLVM tools, install them to the sysroot. - // This is the equivalent of installing the `llvm-tools-preview` component via - // rustup, and lets developers use a locally built toolchain to - // build projects that expect llvm tools to be present in the sysroot - // (e.g. the `bootimage` crate). - for tool in LLVM_TOOLS { - let tool_exe = exe(tool, target_compiler.host); - let src_path = llvm_bin_dir.join(&tool_exe); - // When using `download-ci-llvm`, some of the tools - // may not exist, so skip trying to copy them. - if src_path.exists() { - builder.copy_link(&src_path, &libdir_bin.join(&tool_exe)); - } - } - } - } - - if builder.config.llvm_bitcode_linker_enabled { - let src_path = builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker { - compiler: build_compiler, - target: target_compiler.host, - extra_features: vec![], - }); - let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); - builder.copy_link(&src_path, &libdir_bin.join(tool_exe)); - } + maybe_install_llvm_bitcode_linker(build_compiler); // Ensure that `libLLVM.so` ends up in the newly build compiler directory, // so that it can be found when the newly built `rustc` is run. diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 4957de2e1b791..4c557366297ed 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -14,8 +14,8 @@ use std::io::Write; use std::path::{Path, PathBuf}; use std::{env, fs}; -use object::read::archive::ArchiveFile; use object::BinaryFormat; +use object::read::archive::ArchiveFile; use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::tool::{self, Tool}; @@ -24,12 +24,12 @@ use crate::core::build_steps::{compile, llvm}; use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::{self, Info}; -use crate::utils::exec::{command, BootstrapCommand}; +use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{ exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit, }; use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; -use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; +use crate::{Compiler, DependencyType, LLVM_TOOLS, Mode}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { format!("{}-{}", component, builder.rust_package_vers()) @@ -473,7 +473,7 @@ impl Step for Rustc { ); } } - if builder.build_wasm_component_ld() { + if builder.tool_enabled("wasm-component-ld") { let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin"); let ld = exe("wasm-component-ld", compiler.host); builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld)); @@ -1011,11 +1011,7 @@ impl Step for PlainSourceTarball { write_git_info(builder.rust_info().info(), plain_dst_src); write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo")); - // If we're building from git or tarball sources, we need to vendor - // a complete distribution. - if builder.rust_info().is_managed_git_subrepository() - || builder.rust_info().is_from_tarball() - { + if builder.config.dist_vendor { builder.require_and_update_all_submodules(); // Vendor all Cargo dependencies @@ -1348,18 +1344,9 @@ impl Step for CodegenBackend { return None; } - if self.backend == "cranelift" { - if !target_supports_cranelift_backend(self.compiler.host) { - builder.info("target not supported by rustc_codegen_cranelift. skipping"); - return None; - } - - if self.compiler.host.is_windows() { - builder.info( - "dist currently disabled for windows by rustc_codegen_cranelift. skipping", - ); - return None; - } + if self.backend == "cranelift" && !target_supports_cranelift_backend(self.compiler.host) { + builder.info("target not supported by rustc_codegen_cranelift. skipping"); + return None; } let compiler = self.compiler; diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index ffb617c642baf..3d504c3771fb2 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -11,14 +11,14 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::{env, fs, mem}; +use crate::Mode; use crate::core::build_steps::compile; -use crate::core::build_steps::tool::{self, prepare_tool_cargo, SourceType, Tool}; +use crate::core::build_steps::tool::{self, SourceType, Tool, prepare_tool_cargo}; use crate::core::builder::{ - self, crate_description, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, + self, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, crate_description, }; use crate::core::config::{Config, TargetSelection}; use crate::utils::helpers::{symlink_dir, t, up_to_date}; -use crate::Mode; macro_rules! submodule_helper { ($path:expr, submodule) => { @@ -63,7 +63,7 @@ macro_rules! book { src: builder.src.join($path), parent: Some(self), languages: $lang.into(), - rustdoc: None, + rustdoc_compiler: None, }) } } @@ -113,7 +113,7 @@ impl Step for UnstableBook { src: builder.md_doc_out(self.target).join("unstable-book"), parent: Some(self), languages: vec![], - rustdoc: None, + rustdoc_compiler: None, }) } } @@ -125,7 +125,7 @@ struct RustbookSrc { src: PathBuf, parent: Option

, languages: Vec<&'static str>, - rustdoc: Option, + rustdoc_compiler: Option, } impl Step for RustbookSrc

{ @@ -157,7 +157,9 @@ impl Step for RustbookSrc

{ let _ = fs::remove_dir_all(&out); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); - if let Some(mut rustdoc) = self.rustdoc { + + if let Some(compiler) = self.rustdoc_compiler { + let mut rustdoc = builder.rustdoc(compiler); rustdoc.pop(); let old_path = env::var_os("PATH").unwrap_or_default(); let new_path = @@ -165,6 +167,7 @@ impl Step for RustbookSrc

{ .expect("could not add rustdoc to PATH"); rustbook_cmd.env("PATH", new_path); + builder.add_rustc_lib_path(compiler, &mut rustbook_cmd); } rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder); @@ -240,7 +243,7 @@ impl Step for TheBook { src: absolute_path.clone(), parent: Some(self), languages: vec![], - rustdoc: None, + rustdoc_compiler: None, }); // building older edition redirects @@ -253,7 +256,7 @@ impl Step for TheBook { // treat the other editions as not having a parent. parent: Option::::None, languages: vec![], - rustdoc: None, + rustdoc_compiler: None, }); } @@ -826,7 +829,7 @@ impl Step for Rustc { // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 // cargo.rustdocflag("--generate-link-to-definition"); - compile::rustc_cargo(builder, &mut cargo, target, &compiler); + compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); cargo.arg("-Zskip-rustdoc-fingerprint"); // Only include compiler crates, no dependencies of those, such as `libc`. @@ -1013,6 +1016,14 @@ macro_rules! tool_doc { } } +// NOTE: make sure to register these in `Builder::get_step_description`. +tool_doc!( + BuildHelper, + "src/tools/build_helper", + rustc_tool = false, + is_library = true, + crates = ["build_helper"] +); tool_doc!(Rustdoc, "src/tools/rustdoc", crates = ["rustdoc", "rustdoc-json-types"]); tool_doc!(Rustfmt, "src/tools/rustfmt", crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]); tool_doc!(Clippy, "src/tools/clippy", crates = ["clippy_config", "clippy_utils"]); @@ -1050,6 +1061,13 @@ tool_doc!( is_library = true, crates = ["run_make_support"] ); +tool_doc!( + Compiletest, + "src/tools/compiletest", + rustc_tool = false, + is_library = true, + crates = ["compiletest"] +); #[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { @@ -1186,6 +1204,9 @@ impl Step for RustcBook { cmd.arg("--rustc"); cmd.arg(&rustc); cmd.arg("--rustc-target").arg(self.target.rustc_target_arg()); + if let Some(target_linker) = builder.linker(self.target) { + cmd.arg("--rustc-linker").arg(target_linker); + } if builder.is_verbose() { cmd.arg("--verbose"); } @@ -1218,7 +1239,7 @@ impl Step for RustcBook { src: out_base, parent: Some(self), languages: vec![], - rustdoc: None, + rustdoc_compiler: None, }); } } @@ -1252,16 +1273,15 @@ impl Step for Reference { // This is needed for generating links to the standard library using // the mdbook-spec plugin. builder.ensure(compile::Std::new(self.compiler, builder.config.build)); - let rustdoc = builder.rustdoc(self.compiler); // Run rustbook/mdbook to generate the HTML pages. builder.ensure(RustbookSrc { target: self.target, name: "reference".to_owned(), src: builder.src.join("src/doc/reference"), + rustdoc_compiler: Some(self.compiler), parent: Some(self), languages: vec![], - rustdoc: Some(rustdoc), }); } } diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 8c52df78ab685..952d8d73328fb 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -3,8 +3,8 @@ use std::collections::VecDeque; use std::path::{Path, PathBuf}; use std::process::Command; -use std::sync::mpsc::SyncSender; use std::sync::Mutex; +use std::sync::mpsc::SyncSender; use build_helper::ci::CiEnv; use build_helper::git::get_git_modified_files; @@ -93,7 +93,6 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result>, Str if !verify_rustfmt_version(build) { return Ok(None); } - get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]) } @@ -201,6 +200,11 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { adjective = Some("modified"); match get_modified_rs_files(build) { Ok(Some(files)) => { + if files.is_empty() { + println!("fmt info: No modified files detected for formatting."); + return; + } + for file in files { override_builder.add(&format!("/{file}")).expect(&file); } diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs new file mode 100644 index 0000000000000..b950bec11fd01 --- /dev/null +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -0,0 +1,137 @@ +//! Compilation of native dependencies like GCC. +//! +//! Native projects like GCC unfortunately aren't suited just yet for +//! compilation in build scripts that Cargo has. This is because the +//! compilation takes a *very* long time but also because we don't want to +//! compile GCC 3 times as part of a normal bootstrap (we want it cached). +//! +//! GCC and compiler-rt are essentially just wired up to everything else to +//! ensure that they're always in place if needed. + +use std::fs; +use std::path::PathBuf; +use std::sync::OnceLock; + +use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::core::config::TargetSelection; +use crate::utils::exec::command; +use crate::utils::helpers::{self, HashStamp, t}; +use crate::{Kind, generate_smart_stamp_hash}; + +pub struct Meta { + stamp: HashStamp, + out_dir: PathBuf, + install_dir: PathBuf, + root: PathBuf, +} + +pub enum GccBuildStatus { + AlreadyBuilt, + ShouldBuild(Meta), +} + +/// This returns whether we've already previously built GCC. +/// +/// It's used to avoid busting caches during x.py check -- if we've already built +/// GCC, it's fine for us to not try to avoid doing so. +pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus { + // Initialize the gcc submodule if not initialized already. + builder.config.update_submodule("src/gcc"); + + // FIXME (GuillaumeGomez): To be done once gccjit has been built in the CI. + // builder.config.maybe_download_ci_gcc(); + + let root = builder.src.join("src/gcc"); + let out_dir = builder.gcc_out(target).join("build"); + let install_dir = builder.gcc_out(target).join("install"); + + static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); + let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { + generate_smart_stamp_hash( + builder, + &builder.config.src.join("src/gcc"), + builder.in_tree_gcc_info.sha().unwrap_or_default(), + ) + }); + + let stamp = out_dir.join("gcc-finished-building"); + let stamp = HashStamp::new(stamp, Some(smart_stamp_hash)); + + if stamp.is_done() { + if stamp.hash.is_none() { + builder.info( + "Could not determine the GCC submodule commit hash. \ + Assuming that an GCC rebuild is not necessary.", + ); + builder.info(&format!( + "To force GCC to rebuild, remove the file `{}`", + stamp.path.display() + )); + } + return GccBuildStatus::AlreadyBuilt; + } + + GccBuildStatus::ShouldBuild(Meta { stamp, out_dir, install_dir, root }) +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Gcc { + pub target: TargetSelection, +} + +impl Step for Gcc { + type Output = bool; + + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/gcc").alias("gcc") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Gcc { target: run.target }); + } + + /// Compile GCC for `target`. + fn run(self, builder: &Builder<'_>) -> bool { + let target = self.target; + + // If GCC has already been built, we avoid building it again. + let Meta { stamp, out_dir, install_dir, root } = match prebuilt_gcc_config(builder, target) + { + GccBuildStatus::AlreadyBuilt => return true, + GccBuildStatus::ShouldBuild(m) => m, + }; + + let _guard = builder.msg_unstaged(Kind::Build, "GCC", target); + t!(stamp.remove()); + let _time = helpers::timeit(builder); + t!(fs::create_dir_all(&out_dir)); + + if builder.config.dry_run() { + return true; + } + + command(root.join("contrib/download_prerequisites")).current_dir(&root).run(builder); + command(root.join("configure")) + .current_dir(&out_dir) + .arg("--enable-host-shared") + .arg("--enable-languages=jit") + .arg("--enable-checking=release") + .arg("--disable-bootstrap") + .arg("--disable-multilib") + .arg(format!("--prefix={}", install_dir.display())) + .run(builder); + command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder); + command("make").current_dir(&out_dir).arg("install").run(builder); + + let lib_alias = install_dir.join("lib/libgccjit.so.0"); + if !lib_alias.exists() { + t!(builder.symlink_file(install_dir.join("lib/libgccjit.so"), lib_alias,)); + } + + t!(stamp.write()); + + true + } +} diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index e1eea31b3bbf3..b3bc6df1f87f4 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -8,23 +8,24 @@ //! LLVM and compiler-rt are essentially just wired up to everything else to //! ensure that they're always in place if needed. +use std::env; use std::env::consts::EXE_EXTENSION; use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::sync::OnceLock; -use std::{env, io}; use build_helper::ci::CiEnv; +use build_helper::git::get_closest_merge_commit; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; use crate::utils::channel; use crate::utils::exec::command; use crate::utils::helpers::{ - self, exe, get_clang_cl_resource_dir, output, t, unhashed_basename, up_to_date, + self, HashStamp, exe, get_clang_cl_resource_dir, output, t, unhashed_basename, up_to_date, }; -use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind}; +use crate::{CLang, GitRepo, Kind, generate_smart_stamp_hash}; #[derive(Clone)] pub struct LlvmResult { @@ -153,17 +154,12 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L /// This retrieves the LLVM sha we *want* to use, according to git history. pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { let llvm_sha = if is_git { - helpers::get_closest_merge_base_commit( - Some(&config.src), - &config.git_config(), - &config.stage0_metadata.config.git_merge_commit_email, - &[ - config.src.join("src/llvm-project"), - config.src.join("src/bootstrap/download-ci-llvm-stamp"), - // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` - config.src.join("src/version"), - ], - ) + get_closest_merge_commit(Some(&config.src), &config.git_config(), &[ + config.src.join("src/llvm-project"), + config.src.join("src/bootstrap/download-ci-llvm-stamp"), + // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` + config.src.join("src/version"), + ]) .unwrap() } else if let Some(info) = channel::read_commit_info_file(&config.src) { info.sha.trim().to_owned() @@ -529,6 +525,7 @@ impl Step for Llvm { } }; + // FIXME(ZuseZ4): Do we need that for Enzyme too? // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned // libLLVM.dylib will be built. However, llvm-config will still look // for a versioned path like libLLVM-14.dylib. Manually create a symbolic @@ -579,11 +576,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { let version = command(llvm_config).arg("--version").run_capture_stdout(builder).stdout(); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { - if major >= 17 { + if major >= 18 { return; } } - panic!("\n\nbad LLVM version: {version}, need >=17.0\n\n") + panic!("\n\nbad LLVM version: {version}, need >=18\n\n") } fn configure_cmake( @@ -849,6 +846,100 @@ fn get_var(var_base: &str, host: &str, target: &str) -> Option { .or_else(|| env::var_os(var_base)) } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Enzyme { + pub target: TargetSelection, +} + +impl Step for Enzyme { + type Output = PathBuf; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/enzyme/enzyme") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Enzyme { target: run.target }); + } + + /// Compile Enzyme for `target`. + fn run(self, builder: &Builder<'_>) -> PathBuf { + builder.require_submodule( + "src/tools/enzyme", + Some("The Enzyme sources are required for autodiff."), + ); + if builder.config.dry_run() { + let out_dir = builder.enzyme_out(self.target); + return out_dir; + } + let target = self.target; + + let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: self.target }); + + static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); + let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { + generate_smart_stamp_hash( + builder, + &builder.config.src.join("src/tools/enzyme"), + builder.enzyme_info.sha().unwrap_or_default(), + ) + }); + + let out_dir = builder.enzyme_out(target); + let stamp = out_dir.join("enzyme-finished-building"); + let stamp = HashStamp::new(stamp, Some(smart_stamp_hash)); + + if stamp.is_done() { + if stamp.hash.is_none() { + builder.info( + "Could not determine the Enzyme submodule commit hash. \ + Assuming that an Enzyme rebuild is not necessary.", + ); + builder.info(&format!( + "To force Enzyme to rebuild, remove the file `{}`", + stamp.path.display() + )); + } + return out_dir; + } + + builder.info(&format!("Building Enzyme for {}", target)); + t!(stamp.remove()); + let _time = helpers::timeit(builder); + t!(fs::create_dir_all(&out_dir)); + + builder + .config + .update_submodule(Path::new("src").join("tools").join("enzyme").to_str().unwrap()); + let mut cfg = cmake::Config::new(builder.src.join("src/tools/enzyme/enzyme/")); + // FIXME(ZuseZ4): Find a nicer way to use Enzyme Debug builds + //cfg.profile("Debug"); + //cfg.define("CMAKE_BUILD_TYPE", "Debug"); + configure_cmake(builder, target, &mut cfg, true, LdFlags::default(), &[]); + + // Re-use the same flags as llvm to control the level of debug information + // generated for lld. + let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { + (false, _) => "Debug", + (true, false) => "Release", + (true, true) => "RelWithDebInfo", + }; + + cfg.out_dir(&out_dir) + .profile(profile) + .env("LLVM_CONFIG_REAL", &llvm_config) + .define("LLVM_ENABLE_ASSERTIONS", "ON") + .define("ENZYME_EXTERNAL_SHARED_LIB", "ON") + .define("LLVM_DIR", builder.llvm_out(target)); + + cfg.build(); + + t!(stamp.write()); + out_dir + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Lld { pub target: TargetSelection, @@ -1147,44 +1238,6 @@ fn supported_sanitizers( } } -struct HashStamp { - path: PathBuf, - hash: Option>, -} - -impl HashStamp { - fn new(path: PathBuf, hash: Option<&str>) -> Self { - HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) } - } - - fn is_done(&self) -> bool { - match fs::read(&self.path) { - Ok(h) => self.hash.as_deref().unwrap_or(b"") == h.as_slice(), - Err(e) if e.kind() == io::ErrorKind::NotFound => false, - Err(e) => { - panic!("failed to read stamp file `{}`: {}", self.path.display(), e); - } - } - } - - fn remove(&self) -> io::Result<()> { - match fs::remove_file(&self.path) { - Ok(()) => Ok(()), - Err(e) => { - if e.kind() == io::ErrorKind::NotFound { - Ok(()) - } else { - Err(e) - } - } - } - } - - fn write(&self) -> io::Result<()> { - fs::write(&self.path, self.hash.as_deref().unwrap_or(b"")) - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrtBeginEnd { pub target: TargetSelection, diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs index 004174e35e1d1..fcb6abea43472 100644 --- a/src/bootstrap/src/core/build_steps/mod.rs +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -5,6 +5,7 @@ pub(crate) mod compile; pub(crate) mod dist; pub(crate) mod doc; pub(crate) mod format; +pub(crate) mod gcc; pub(crate) mod install; pub(crate) mod llvm; pub(crate) mod perf; diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 65d635c0bd69f..c7bcd76caddb9 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -5,14 +5,14 @@ use std::path::PathBuf; +use crate::Mode; use crate::core::build_steps::dist::distdir; use crate::core::build_steps::test; use crate::core::build_steps::tool::{self, SourceType, Tool}; use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; -use crate::core::config::flags::get_completion; use crate::core::config::TargetSelection; +use crate::core::config::flags::get_completion; use crate::utils::exec::command; -use crate::Mode; #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct BuildManifest; diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index f7b26712cabd6..f4c5fe5ff941c 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -9,7 +9,7 @@ use std::env::consts::EXE_SUFFIX; use std::fmt::Write as _; use std::fs::File; use std::io::Write; -use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR}; +use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf}; use std::str::FromStr; use std::{fmt, fs, io}; @@ -19,7 +19,7 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; use crate::utils::exec::command; use crate::utils::helpers::{self, hex_encode}; -use crate::{t, Config}; +use crate::{Config, t}; #[cfg(test)] mod tests; diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index 8aaffab514d88..ba9b1b2fc3317 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -17,6 +17,7 @@ pub fn suggest(builder: &Builder<'_>, run: bool) { .tool_cmd(Tool::SuggestTests) .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository) .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) + .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email) .run_capture_stdout(builder) .stdout(); diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 04297c01d10aa..477ff9553a480 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -7,10 +7,10 @@ //! one of the target specs already defined in this module, or create new ones by adding a new step //! that calls create_synthetic_target. +use crate::Compiler; use crate::core::builder::{Builder, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::exec::command; -use crate::Compiler; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct MirOptPanicAbortSyntheticTarget { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 84a6b26a491ed..870fe6a9f1658 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -15,17 +15,17 @@ use crate::core::build_steps::tool::{self, SourceType, Tool}; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, dist, llvm}; use crate::core::builder::{ - self, crate_description, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, + self, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, crate_description, }; -use crate::core::config::flags::{get_completion, Subcommand}; use crate::core::config::TargetSelection; -use crate::utils::exec::{command, BootstrapCommand}; +use crate::core::config::flags::{Subcommand, get_completion}; +use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{ - self, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, - linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, LldThreads, + self, LldThreads, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, + linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, }; use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; -use crate::{envify, CLang, DocTests, GitRepo, Mode}; +use crate::{CLang, DocTests, GitRepo, Mode, envify}; const ADB_TEST_DIR: &str = "/data/local/tmp/work"; @@ -1075,12 +1075,8 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to crate::exit!(1); } let all = false; - crate::core::build_steps::format::format( - builder, - !builder.config.cmd.bless(), - all, - &[], - ); + crate::core::build_steps::format::format(builder, !builder.config.cmd.bless(), all, &[ + ]); } builder.info("tidy check"); @@ -1733,6 +1729,26 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js"); + if mode == "run-make" { + let cargo_path = if builder.top_stage == 0 { + // If we're using `--stage 0`, we should provide the bootstrap cargo. + builder.initial_cargo.clone() + } else { + // We need to properly build cargo using the suitable stage compiler. + + // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if + // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built + // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off + // the compiler stage by 1 to align with expected `./x test run-make --stage N` + // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri + // which does a similar hack. + let compiler = builder.compiler(builder.top_stage - 1, compiler.host); + builder.ensure(tool::Cargo { compiler, target: compiler.host }) + }; + + cmd.arg("--cargo-path").arg(cargo_path); + } + // Avoid depending on rustdoc when we don't need it. if mode == "rustdoc" || mode == "run-make" @@ -1810,6 +1826,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the if builder.config.rust_optimize_tests { cmd.arg("--optimize-tests"); } + if builder.config.rust_randomize_layout { + cmd.arg("--rust-randomized-layout"); + } if builder.config.cmd.only_modified() { cmd.arg("--only-modified"); } @@ -2084,8 +2103,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--rustfix-coverage"); } - cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo); - cmd.arg("--channel").arg(&builder.config.channel); if !builder.config.omit_git_hash { @@ -2095,6 +2112,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let git_config = builder.config.git_config(); cmd.arg("--git-repository").arg(git_config.git_repository); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); + cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email); cmd.force_coloring_in_ci(); #[cfg(feature = "build-metrics")] @@ -2687,7 +2705,7 @@ impl Step for Crate { } } Mode::Rustc => { - compile::rustc_cargo(builder, &mut cargo, target, &compiler); + compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); } _ => panic!("can only test libraries"), }; @@ -3431,11 +3449,10 @@ impl Step for CodegenGCC { let compiler = self.compiler; let target = self.target; - builder.ensure(compile::Std::new_with_extra_rust_args( - compiler, - target, - &["-Csymbol-mangling-version=v0", "-Cpanic=abort"], - )); + builder.ensure(compile::Std::new_with_extra_rust_args(compiler, target, &[ + "-Csymbol-mangling-version=v0", + "-Cpanic=abort", + ])); // If we're not doing a full bootstrap but we're testing a stage2 // version of libstd, then what we're actually testing is the libstd @@ -3526,11 +3543,13 @@ impl Step for TestFloatParse { fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.build; - let compiler = builder.compiler(0, bootstrap_host); + let compiler = builder.compiler(builder.top_stage, bootstrap_host); let path = self.path.to_str().unwrap(); let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap(); - builder.ensure(compile::Std::new(compiler, self.host)); + if !builder.download_rustc() { + builder.ensure(compile::Std::new(compiler, self.host)); + } // Run any unit tests in the crate let cargo_test = tool::prepare_tool_cargo( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 3a1eb43b801f5..64dfe054d9c77 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1,15 +1,17 @@ use std::path::PathBuf; use std::{env, fs}; +use build_helper::git::get_closest_merge_commit; + use crate::core::build_steps::compile; use crate::core::build_steps::toolstate::ToolState; use crate::core::builder; use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; -use crate::utils::exec::{command, BootstrapCommand}; -use crate::utils::helpers::{add_dylib_path, exe, get_closest_merge_base_commit, git, t}; -use crate::{gha, Compiler, Kind, Mode}; +use crate::utils::exec::{BootstrapCommand, command}; +use crate::utils::helpers::{add_dylib_path, exe, git, t}; +use crate::{Compiler, Kind, Mode, gha}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum SourceType { @@ -576,10 +578,9 @@ impl Step for Rustdoc { && target_compiler.stage > 0 && builder.rust_info().is_managed_git_subrepository() { - let commit = get_closest_merge_base_commit( + let commit = get_closest_merge_commit( Some(&builder.config.src), &builder.config.git_config(), - &builder.config.stage0_metadata.config.git_merge_commit_email, &[], ) .unwrap(); @@ -693,14 +694,7 @@ impl Step for Cargo { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.path("src/tools/cargo").default_condition( - builder.config.extended - && builder.config.tools.as_ref().map_or( - true, - // If `tools` is set, search list for this tool. - |tools| tools.iter().any(|tool| tool == "cargo"), - ), - ) + run.path("src/tools/cargo").default_condition(builder.tool_enabled("cargo")) } fn make_run(run: RunConfig<'_>) { @@ -772,14 +766,7 @@ impl Step for RustAnalyzer { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.path("src/tools/rust-analyzer").default_condition( - builder.config.extended - && builder - .config - .tools - .as_ref() - .map_or(true, |tools| tools.iter().any(|tool| tool == "rust-analyzer")), - ) + run.path("src/tools/rust-analyzer").default_condition(builder.tool_enabled("rust-analyzer")) } fn make_run(run: RunConfig<'_>) { @@ -821,12 +808,8 @@ impl Step for RustAnalyzerProcMacroSrv { run.path("src/tools/rust-analyzer") .path("src/tools/rust-analyzer/crates/proc-macro-srv-cli") .default_condition( - builder.config.extended - && builder.config.tools.as_ref().map_or(true, |tools| { - tools.iter().any(|tool| { - tool == "rust-analyzer" || tool == "rust-analyzer-proc-macro-srv" - }) - }), + builder.tool_enabled("rust-analyzer") + || builder.tool_enabled("rust-analyzer-proc-macro-srv"), ) } @@ -874,16 +857,8 @@ impl Step for LlvmBitcodeLinker { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.path("src/tools/llvm-bitcode-linker").default_condition( - builder.config.extended - && builder - .config - .tools - .as_ref() - .map_or(builder.build.unstable_features(), |tools| { - tools.iter().any(|tool| tool == "llvm-bitcode-linker") - }), - ) + run.path("src/tools/llvm-bitcode-linker") + .default_condition(builder.tool_enabled("llvm-bitcode-linker")) } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index b73961062f684..8ac311b249318 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -42,15 +42,11 @@ pub enum ToolState { impl fmt::Display for ToolState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match self { - ToolState::TestFail => "test-fail", - ToolState::TestPass => "test-pass", - ToolState::BuildFail => "build-fail", - } - ) + write!(f, "{}", match self { + ToolState::TestFail => "test-fail", + ToolState::TestPass => "test-pass", + ToolState::BuildFail => "build-fail", + }) } } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index ff0d1f3a725d2..47420f8fe72fb 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1,4 +1,4 @@ -use std::any::{type_name, Any}; +use std::any::{Any, type_name}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; use std::ffi::{OsStr, OsString}; @@ -12,21 +12,21 @@ use std::{env, fs}; use clap::ValueEnum; +pub use crate::Compiler; use crate::core::build_steps::tool::{self, SourceType}; use crate::core::build_steps::{ - check, clean, clippy, compile, dist, doc, install, llvm, run, setup, test, vendor, + check, clean, clippy, compile, dist, doc, gcc, install, llvm, run, setup, test, vendor, }; use crate::core::config::flags::{Color, Subcommand}; use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection}; use crate::utils::cache::Cache; -use crate::utils::exec::{command, BootstrapCommand}; +use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{ - self, add_dylib_path, add_link_lib_path, check_cfg_arg, exe, libdir, linker_args, linker_flags, - t, LldThreads, + self, LldThreads, add_dylib_path, add_link_lib_path, check_cfg_arg, exe, libdir, linker_args, + linker_flags, t, }; -pub use crate::Compiler; use crate::{ - prepare_behaviour_dump_dir, Build, CLang, Crate, DocTests, GitRepo, Mode, EXTRA_CHECK_CFGS, + Build, CLang, Crate, DocTests, EXTRA_CHECK_CFGS, GitRepo, Mode, prepare_behaviour_dump_dir, }; #[cfg(test)] @@ -314,33 +314,30 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ // actual path is `proc-macro-srv-cli` ("rust-analyzer-proc-macro-srv", &["src/tools/rust-analyzer/crates/proc-macro-srv-cli"]), // Make `x test tests` function the same as `x t tests/*` - ( - "tests", - &[ - // tidy-alphabetical-start - "tests/assembly", - "tests/codegen", - "tests/codegen-units", - "tests/coverage", - "tests/coverage-run-rustdoc", - "tests/crashes", - "tests/debuginfo", - "tests/incremental", - "tests/mir-opt", - "tests/pretty", - "tests/run-make", - "tests/run-pass-valgrind", - "tests/rustdoc", - "tests/rustdoc-gui", - "tests/rustdoc-js", - "tests/rustdoc-js-std", - "tests/rustdoc-json", - "tests/rustdoc-ui", - "tests/ui", - "tests/ui-fulldeps", - // tidy-alphabetical-end - ], - ), + ("tests", &[ + // tidy-alphabetical-start + "tests/assembly", + "tests/codegen", + "tests/codegen-units", + "tests/coverage", + "tests/coverage-run-rustdoc", + "tests/crashes", + "tests/debuginfo", + "tests/incremental", + "tests/mir-opt", + "tests/pretty", + "tests/run-make", + "tests/run-pass-valgrind", + "tests/rustdoc", + "tests/rustdoc-gui", + "tests/rustdoc-js", + "tests/rustdoc-js-std", + "tests/rustdoc-json", + "tests/rustdoc-ui", + "tests/ui", + "tests/ui-fulldeps", + // tidy-alphabetical-end + ]), ]; fn remap_paths(paths: &mut Vec) { @@ -793,11 +790,13 @@ impl<'a> Builder<'a> { tool::Clippy, tool::CargoClippy, llvm::Llvm, + gcc::Gcc, llvm::Sanitizers, tool::Rustfmt, tool::Miri, tool::CargoMiri, llvm::Lld, + llvm::Enzyme, llvm::CrtBeginEnd, tool::RustdocGUITest, tool::OptimizedDist, @@ -942,6 +941,8 @@ impl<'a> Builder<'a> { doc::Bootstrap, doc::Releases, doc::RunMakeSupport, + doc::BuildHelper, + doc::Compiletest, ), Kind::Dist => describe!( dist::Docs, @@ -1298,8 +1299,12 @@ impl<'a> Builder<'a> { pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { if run_compiler.stage == 0 { - // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy. - let cargo_clippy = self.build.config.download_clippy(); + let cargo_clippy = self + .config + .initial_cargo_clippy + .clone() + .unwrap_or_else(|| self.build.config.download_clippy()); + let mut cmd = command(cargo_clippy); cmd.env("CARGO", &self.initial_cargo); return cmd; @@ -1614,6 +1619,15 @@ impl<'a> Builder<'a> { rustflags.arg("-Csymbol-mangling-version=legacy"); } + // FIXME: the following components don't build with `-Zrandomize-layout` yet: + // - wasm-component-ld, due to the `wast`crate + // - rust-analyzer, due to the rowan crate + // so we exclude entire categories of steps here due to lack of fine-grained control over + // rustflags. + if self.config.rust_randomize_layout && mode != Mode::ToolStd && mode != Mode::ToolRustc { + rustflags.arg("-Zrandomize-layout"); + } + // Enable compile-time checking of `cfg` names, values and Cargo `features`. // // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like @@ -2189,6 +2203,9 @@ impl<'a> Builder<'a> { rustflags.arg("-Zvalidate-mir"); rustflags.arg(&format!("-Zmir-opt-level={mir_opt_level}")); } + if self.config.rust_randomize_layout { + rustflags.arg("--cfg=randomized_layouts"); + } // Always enable inlining MIR when building the standard library. // Without this flag, MIR inlining is disabled when incremental compilation is enabled. // That causes some mir-opt tests which inline functions from the standard library to @@ -2440,7 +2457,16 @@ impl Cargo { cmd_kind: Kind, ) -> Cargo { let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind); - cargo.configure_linker(builder); + + match cmd_kind { + // No need to configure the target linker for these command types, + // as they don't invoke rustc at all. + Kind::Clean | Kind::Suggest | Kind::Format | Kind::Setup => {} + _ => { + cargo.configure_linker(builder); + } + } + cargo } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index c554684d5a75b..bd81dc930be05 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1,9 +1,9 @@ use std::thread; use super::*; +use crate::Flags; use crate::core::build_steps::doc::DocumentationFormat; use crate::core::config::Config; -use crate::Flags; fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { configure_with_args(&[cmd.to_owned()], host, target) @@ -202,10 +202,10 @@ fn test_exclude_kind() { fn alias_and_path_for_library() { let mut cache = run_build(&["library".into(), "core".into()], configure("build", &["A-A"], &["A-A"])); - assert_eq!( - first(cache.all::()), - &[std!(A => A, stage = 0), std!(A => A, stage = 1)] - ); + assert_eq!(first(cache.all::()), &[ + std!(A => A, stage = 0), + std!(A => A, stage = 1) + ]); let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A-A"], &["A-A"])); @@ -216,18 +216,18 @@ mod defaults { use pretty_assertions::assert_eq; use super::{configure, first, run_build}; - use crate::core::builder::*; use crate::Config; + use crate::core::builder::*; #[test] fn build_default() { let mut cache = run_build(&[], configure("build", &["A-A"], &["A-A"])); let a = TargetSelection::from_user("A-A"); - assert_eq!( - first(cache.all::()), - &[std!(A => A, stage = 0), std!(A => A, stage = 1),] - ); + assert_eq!(first(cache.all::()), &[ + std!(A => A, stage = 0), + std!(A => A, stage = 1), + ]); assert!(!cache.all::().is_empty()); // Make sure rustdoc is only built once. assert_eq!( @@ -269,34 +269,25 @@ mod defaults { // there's not really a need for us to build for target A in this case // (since we're producing stage 1 libraries/binaries). But currently // bootstrap is just a bit buggy here; this should be fixed though. - assert_eq!( - first(cache.all::()), - &[ - std!(A => A, stage = 0), - std!(A => A, stage = 1), - std!(A => B, stage = 0), - std!(A => B, stage = 1), - ] - ); - assert_eq!( - first(cache.all::()), - &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, - ] - ); - assert_eq!( - first(cache.all::()), - &[ - tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, - tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, - ], - ); - assert_eq!( - first(cache.all::()), - &[rustc!(A => A, stage = 0), rustc!(A => B, stage = 0),] - ); + assert_eq!(first(cache.all::()), &[ + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => B, stage = 0), + std!(A => B, stage = 1), + ]); + assert_eq!(first(cache.all::()), &[ + compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, + compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, + ]); + assert_eq!(first(cache.all::()), &[ + tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, + tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, + ],); + assert_eq!(first(cache.all::()), &[ + rustc!(A => A, stage = 0), + rustc!(A => B, stage = 0), + ]); } #[test] @@ -310,24 +301,22 @@ mod defaults { // error_index_generator uses stage 0 to share rustdoc artifacts with the // rustdoc tool. assert_eq!(first(cache.all::()), &[doc::ErrorIndex { target: a },]); - assert_eq!( - first(cache.all::()), - &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 0 } }] - ); + assert_eq!(first(cache.all::()), &[tool::ErrorIndex { + compiler: Compiler { host: a, stage: 0 } + }]); // docs should be built with the beta compiler, not with the stage0 artifacts. // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to, // not the one it was built by. - assert_eq!( - first(cache.all::()), - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },] - ); + assert_eq!(first(cache.all::()), &[tool::Rustdoc { + compiler: Compiler { host: a, stage: 0 } + },]); } } mod dist { use pretty_assertions::assert_eq; - use super::{first, run_build, Config}; + use super::{Config, first, run_build}; use crate::core::builder::*; fn configure(host: &[&str], target: &[&str]) -> Config { @@ -342,20 +331,18 @@ mod dist { assert_eq!(first(cache.all::()), &[dist::Docs { host: a },]); assert_eq!(first(cache.all::()), &[dist::Mingw { host: a },]); - assert_eq!( - first(cache.all::()), - &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },] - ); - assert_eq!( - first(cache.all::()), - &[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },] - ); + assert_eq!(first(cache.all::()), &[dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + },]); + assert_eq!(first(cache.all::()), &[dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a + },]); assert_eq!(first(cache.all::()), &[dist::Src]); // Make sure rustdoc is only built once. - assert_eq!( - first(cache.all::()), - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },] - ); + assert_eq!(first(cache.all::()), &[tool::Rustdoc { + compiler: Compiler { host: a, stage: 2 } + },]); } #[test] @@ -365,25 +352,19 @@ mod dist { let a = TargetSelection::from_user("A-A"); let b = TargetSelection::from_user("B-B"); - assert_eq!( - first(cache.all::()), - &[dist::Docs { host: a }, dist::Docs { host: b },] - ); - assert_eq!( - first(cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b },] - ); - assert_eq!( - first(cache.all::()), - &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },] - ); - assert_eq!( - first(cache.all::()), - &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - ] - ); + assert_eq!(first(cache.all::()), &[dist::Docs { host: a }, dist::Docs { + host: b + },]); + assert_eq!(first(cache.all::()), &[dist::Mingw { host: a }, dist::Mingw { + host: b + },]); + assert_eq!(first(cache.all::()), &[dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + },]); + assert_eq!(first(cache.all::()), &[ + dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + ]); assert_eq!(first(cache.all::()), &[dist::Src]); } @@ -394,38 +375,27 @@ mod dist { let a = TargetSelection::from_user("A-A"); let b = TargetSelection::from_user("B-B"); - assert_eq!( - first(cache.all::()), - &[dist::Docs { host: a }, dist::Docs { host: b },] - ); - assert_eq!( - first(cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b },] - ); - assert_eq!( - first(cache.all::()), - &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ] - ); - assert_eq!( - first(cache.all::()), - &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - ] - ); - assert_eq!( - first(cache.all::()), - &[ - std!(A => A, stage = 0), - std!(A => A, stage = 1), - std!(A => A, stage = 2), - std!(A => B, stage = 1), - std!(A => B, stage = 2), - ], - ); + assert_eq!(first(cache.all::()), &[dist::Docs { host: a }, dist::Docs { + host: b + },]); + assert_eq!(first(cache.all::()), &[dist::Mingw { host: a }, dist::Mingw { + host: b + },]); + assert_eq!(first(cache.all::()), &[ + dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, + dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + ]); + assert_eq!(first(cache.all::()), &[ + dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + ]); + assert_eq!(first(cache.all::()), &[ + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => A, stage = 2), + std!(A => B, stage = 1), + std!(A => B, stage = 2), + ],); assert_eq!(first(cache.all::()), &[dist::Src]); } @@ -438,14 +408,13 @@ mod dist { config.hosts = vec![b]; let mut cache = run_build(&[], config); - assert_eq!( - first(cache.all::()), - &[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },] - ); - assert_eq!( - first(cache.all::()), - &[rustc!(A => A, stage = 0), rustc!(A => B, stage = 1),] - ); + assert_eq!(first(cache.all::()), &[dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + },]); + assert_eq!(first(cache.all::()), &[ + rustc!(A => A, stage = 0), + rustc!(A => B, stage = 1), + ]); } #[test] @@ -456,29 +425,25 @@ mod dist { let b = TargetSelection::from_user("B-B"); let c = TargetSelection::from_user("C-C"); - assert_eq!( - first(cache.all::()), - &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },] - ); - assert_eq!( - first(cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },] - ); - assert_eq!( - first(cache.all::()), - &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ] - ); - assert_eq!( - first(cache.all::()), - &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - ] - ); + assert_eq!(first(cache.all::()), &[ + dist::Docs { host: a }, + dist::Docs { host: b }, + dist::Docs { host: c }, + ]); + assert_eq!(first(cache.all::()), &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ]); + assert_eq!(first(cache.all::()), &[ + dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, + dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + ]); + assert_eq!(first(cache.all::()), &[ + dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, + ]); assert_eq!(first(cache.all::()), &[dist::Src]); } @@ -492,10 +457,10 @@ mod dist { assert_eq!(first(cache.all::()), &[dist::Docs { host: c },]); assert_eq!(first(cache.all::()), &[dist::Mingw { host: c },]); - assert_eq!( - first(cache.all::()), - &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },] - ); + assert_eq!(first(cache.all::()), &[dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c + },]); } #[test] @@ -505,81 +470,61 @@ mod dist { let a = TargetSelection::from_user("A-A"); let b = TargetSelection::from_user("B-B"); - assert_eq!( - first(cache.all::()), - &[dist::Docs { host: a }, dist::Docs { host: b },] - ); - assert_eq!( - first(cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b },] - ); - assert_eq!( - first(cache.all::()), - &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ] - ); - assert_eq!( - first(cache.all::()), - &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - ] - ); + assert_eq!(first(cache.all::()), &[dist::Docs { host: a }, dist::Docs { + host: b + },]); + assert_eq!(first(cache.all::()), &[dist::Mingw { host: a }, dist::Mingw { + host: b + },]); + assert_eq!(first(cache.all::()), &[ + dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, + dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + ]); + assert_eq!(first(cache.all::()), &[ + dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + ]); assert_eq!(first(cache.all::()), &[dist::Src]); - assert_eq!( - first(cache.all::()), - &[ - std!(A => A, stage = 0), - std!(A => A, stage = 1), - std!(A => A, stage = 2), - std!(A => B, stage = 1), - std!(A => B, stage = 2), - ] - ); - assert_eq!( - first(cache.all::()), - &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } }, - ] - ); + assert_eq!(first(cache.all::()), &[ + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => A, stage = 2), + std!(A => B, stage = 1), + std!(A => B, stage = 2), + ]); + assert_eq!(first(cache.all::()), &[ + compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, + compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } }, + ]); } #[test] fn build_all() { let build = Build::new(configure(&["A-A", "B-B"], &["A-A", "B-B", "C-C"])); let mut builder = Builder::new(&build); - builder.run_step_descriptions( - &Builder::get_step_descriptions(Kind::Build), - &["compiler/rustc".into(), "library".into()], - ); - - assert_eq!( - first(builder.cache.all::()), - &[ - std!(A => A, stage = 0), - std!(A => A, stage = 1), - std!(A => A, stage = 2), - std!(A => B, stage = 1), - std!(A => B, stage = 2), - std!(A => C, stage = 2), - ] - ); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[ + "compiler/rustc".into(), + "library".into(), + ]); + + assert_eq!(first(builder.cache.all::()), &[ + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => A, stage = 2), + std!(A => B, stage = 1), + std!(A => B, stage = 2), + std!(A => C, stage = 2), + ]); assert_eq!(builder.cache.all::().len(), 5); - assert_eq!( - first(builder.cache.all::()), - &[ - rustc!(A => A, stage = 0), - rustc!(A => A, stage = 1), - rustc!(A => A, stage = 2), - rustc!(A => B, stage = 1), - rustc!(A => B, stage = 2), - ] - ); + assert_eq!(first(builder.cache.all::()), &[ + rustc!(A => A, stage = 0), + rustc!(A => A, stage = 1), + rustc!(A => A, stage = 2), + rustc!(A => B, stage = 1), + rustc!(A => B, stage = 2), + ]); } #[test] @@ -608,22 +553,20 @@ mod dist { let a = TargetSelection::from_user("A-A"); - assert_eq!( - first(builder.cache.all::()), - &[std!(A => A, stage = 0), std!(A => A, stage = 1), std!(A => C, stage = 2),] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[rustc!(A => A, stage = 0), rustc!(A => A, stage = 1),] - ); + assert_eq!(first(builder.cache.all::()), &[ + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => C, stage = 2), + ]); + assert_eq!(first(builder.cache.all::()), &[ + compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + rustc!(A => A, stage = 0), + rustc!(A => A, stage = 1), + ]); } #[test] @@ -652,22 +595,18 @@ mod dist { let host = TargetSelection::from_user("A-A"); - builder.run_step_descriptions( - &[StepDescription::from::(Kind::Test)], - &["library/std".into()], - ); + builder.run_step_descriptions(&[StepDescription::from::(Kind::Test)], &[ + "library/std".into(), + ]); // Ensure we don't build any compiler artifacts. assert!(!builder.cache.contains::()); - assert_eq!( - first(builder.cache.all::()), - &[test::Crate { - compiler: Compiler { host, stage: 0 }, - target: host, - mode: Mode::Std, - crates: vec!["std".to_owned()], - },] - ); + assert_eq!(first(builder.cache.all::()), &[test::Crate { + compiler: Compiler { host, stage: 0 }, + target: host, + mode: Mode::Std, + crates: vec!["std".to_owned()], + },]); } #[test] @@ -686,16 +625,14 @@ mod dist { first(builder.cache.all::()), &[doc::ErrorIndex { target: a },] ); - assert_eq!( - first(builder.cache.all::()), - &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }] - ); + assert_eq!(first(builder.cache.all::()), &[tool::ErrorIndex { + compiler: Compiler { host: a, stage: 1 } + }]); // This is actually stage 1, but Rustdoc::run swaps out the compiler with // stage minus 1 if --stage is not 0. Very confusing! - assert_eq!( - first(builder.cache.all::()), - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },] - ); + assert_eq!(first(builder.cache.all::()), &[tool::Rustdoc { + compiler: Compiler { host: a, stage: 2 } + },]); } #[test] @@ -731,10 +668,9 @@ mod dist { first(builder.cache.all::()), &[doc::ErrorIndex { target: a },] ); - assert_eq!( - first(builder.cache.all::()), - &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }] - ); + assert_eq!(first(builder.cache.all::()), &[tool::ErrorIndex { + compiler: Compiler { host: a, stage: 1 } + }]); // Unfortunately rustdoc is built twice. Once from stage1 for compiletest // (and other things), and once from stage0 for std crates. Ideally it // would only be built once. If someone wants to fix this, it might be @@ -746,13 +682,10 @@ mod dist { // The stage 0 copy is the one downloaded for bootstrapping. It is // (currently) needed to run "cargo test" on the linkchecker, and // should be relatively "free". - assert_eq!( - first(builder.cache.all::()), - &[ - tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }, - tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, - tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } }, - ] - ); + assert_eq!(first(builder.cache.all::()), &[ + tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }, + tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, + tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } }, + ]); } } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index bdfee55d8d183..77e0ece31047f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -7,14 +7,14 @@ use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::fmt::{self, Display}; use std::io::IsTerminal; -use std::path::{absolute, Path, PathBuf}; +use std::path::{Path, PathBuf, absolute}; use std::process::Command; use std::str::FromStr; use std::sync::OnceLock; use std::{cmp, env, fs}; use build_helper::exit; -use build_helper::git::{output_result, GitConfig}; +use build_helper::git::{GitConfig, get_closest_merge_commit, output_result}; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -22,9 +22,9 @@ use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::llvm; pub use crate::core::config::flags::Subcommand; use crate::core::config::flags::{Color, Flags, Warnings}; -use crate::utils::cache::{Interned, INTERNER}; +use crate::utils::cache::{INTERNER, Interned}; use crate::utils::channel::{self, GitInfo}; -use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t}; +use crate::utils::helpers::{self, exe, output, t}; macro_rules! check_ci_llvm { ($name:expr) => { @@ -221,6 +221,7 @@ pub struct Config { // llvm codegen options pub llvm_assertions: bool, pub llvm_tests: bool, + pub llvm_enzyme: bool, pub llvm_plugins: bool, pub llvm_optimize: bool, pub llvm_thin_lto: bool, @@ -268,7 +269,6 @@ pub struct Config { pub rust_debuginfo_level_std: DebuginfoLevel, pub rust_debuginfo_level_tools: DebuginfoLevel, pub rust_debuginfo_level_tests: DebuginfoLevel, - pub rust_split_debuginfo_for_build_triple: Option, // FIXME: Deprecated field. Remove in Q3'24. pub rust_rpath: bool, pub rust_strip: bool, pub rust_frame_pointers: bool, @@ -280,6 +280,7 @@ pub struct Config { pub rust_codegen_backends: Vec, pub rust_verify_llvm_ir: bool, pub rust_thin_lto_import_instr_limit: Option, + pub rust_randomize_layout: bool, pub rust_remap_debuginfo: bool, pub rust_new_symbol_mangling: Option, pub rust_profile_use: Option, @@ -307,6 +308,7 @@ pub struct Config { pub dist_compression_formats: Option>, pub dist_compression_profile: String, pub dist_include_mingw_linker: bool, + pub dist_vendor: bool, // libstd features pub backtrace: bool, // support for RUST_BACKTRACE @@ -344,6 +346,7 @@ pub struct Config { // These are either the stage0 downloaded binaries or the locally installed ones. pub initial_cargo: PathBuf, pub initial_rustc: PathBuf, + pub initial_cargo_clippy: Option, #[cfg(not(test))] initial_rustfmt: RefCell, @@ -834,6 +837,7 @@ define_config! { cargo: Option = "cargo", rustc: Option = "rustc", rustfmt: Option = "rustfmt", + cargo_clippy: Option = "cargo-clippy", docs: Option = "docs", compiler_docs: Option = "compiler-docs", library_docs_private_items: Option = "library-docs-private-items", @@ -896,6 +900,7 @@ define_config! { release_debuginfo: Option = "release-debuginfo", assertions: Option = "assertions", tests: Option = "tests", + enzyme: Option = "enzyme", plugins: Option = "plugins", ccache: Option = "ccache", static_libstdcpp: Option = "static-libstdcpp", @@ -929,6 +934,7 @@ define_config! { compression_formats: Option> = "compression-formats", compression_profile: Option = "compression-profile", include_mingw_linker: Option = "include-mingw-linker", + vendor: Option = "vendor", } } @@ -1088,6 +1094,7 @@ define_config! { codegen_units: Option = "codegen-units", codegen_units_std: Option = "codegen-units-std", debug_assertions: Option = "debug-assertions", + randomize_layout: Option = "randomize-layout", debug_assertions_std: Option = "debug-assertions-std", overflow_checks: Option = "overflow-checks", overflow_checks_std: Option = "overflow-checks-std", @@ -1097,7 +1104,6 @@ define_config! { debuginfo_level_std: Option = "debuginfo-level-std", debuginfo_level_tools: Option = "debuginfo-level-tools", debuginfo_level_tests: Option = "debuginfo-level-tests", - split_debuginfo: Option = "split-debuginfo", backtrace: Option = "backtrace", incremental: Option = "incremental", parallel_compiler: Option = "parallel-compiler", @@ -1179,6 +1185,7 @@ impl Config { backtrace: true, rust_optimize: RustOptimize::Bool(true), rust_optimize_tests: true, + rust_randomize_layout: false, submodules: None, docs: true, docs_minification: true, @@ -1211,13 +1218,23 @@ impl Config { } } + pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result { + if self.dry_run() { + return Ok(TomlConfig::default()); + } + + let builder_config_path = + self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME); + Self::get_toml(&builder_config_path) + } + #[cfg(test)] - fn get_toml(_: &Path) -> Result { + pub(crate) fn get_toml(_: &Path) -> Result { Ok(TomlConfig::default()) } #[cfg(not(test))] - fn get_toml(file: &Path) -> Result { + pub(crate) fn get_toml(file: &Path) -> Result { let contents = t!(fs::read_to_string(file), format!("config file {} not found", file.display())); // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of @@ -1439,6 +1456,7 @@ impl Config { cargo, rustc, rustfmt, + cargo_clippy, docs, compiler_docs, library_docs_private_items, @@ -1491,6 +1509,14 @@ impl Config { config.out = absolute(&config.out).expect("can't make empty path absolute"); } + if cargo_clippy.is_some() && rustc.is_none() { + println!( + "WARNING: Using `build.cargo-clippy` without `build.rustc` usually fails due to toolchain conflict." + ); + } + + config.initial_cargo_clippy = cargo_clippy; + config.initial_rustc = if let Some(rustc) = rustc { if !flags.skip_stage0_validation { config.check_stage0_version(&rustc, "rustc"); @@ -1576,6 +1602,9 @@ impl Config { config.verbose = cmp::max(config.verbose, flags.verbose as usize); + // Verbose flag is a good default for `rust.verbose-tests`. + config.verbose_tests = config.is_verbose(); + if let Some(install) = toml.install { let Install { prefix, sysconfdir, docdir, bindir, libdir, mandir, datadir } = install; config.prefix = prefix.map(PathBuf::from); @@ -1591,6 +1620,7 @@ impl Config { // we'll infer default values for them later let mut llvm_assertions = None; let mut llvm_tests = None; + let mut llvm_enzyme = None; let mut llvm_plugins = None; let mut debug = None; let mut debug_assertions = None; @@ -1625,10 +1655,10 @@ impl Config { debuginfo_level_std: debuginfo_level_std_toml, debuginfo_level_tools: debuginfo_level_tools_toml, debuginfo_level_tests: debuginfo_level_tests_toml, - split_debuginfo, backtrace, incremental, parallel_compiler, + randomize_layout, default_linker, channel, description, @@ -1684,18 +1714,6 @@ impl Config { debuginfo_level_tests = debuginfo_level_tests_toml; lld_enabled = lld_enabled_toml; - config.rust_split_debuginfo_for_build_triple = split_debuginfo - .as_deref() - .map(SplitDebuginfo::from_str) - .map(|v| v.expect("invalid value for rust.split-debuginfo")); - - if config.rust_split_debuginfo_for_build_triple.is_some() { - println!( - "WARNING: specifying `rust.split-debuginfo` is deprecated, use `target.{}.split-debuginfo` instead", - config.build - ); - } - optimize = optimize_toml; omit_git_hash = omit_git_hash_toml; config.rust_new_symbol_mangling = new_symbol_mangling; @@ -1718,20 +1736,20 @@ impl Config { set(&mut config.lld_mode, lld_mode); set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker); + config.rust_randomize_layout = randomize_layout.unwrap_or_default(); config.llvm_tools_enabled = llvm_tools.unwrap_or(true); config.rustc_parallel = parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly"); + config.llvm_enzyme = + llvm_enzyme.unwrap_or(config.channel == "dev" || config.channel == "nightly"); config.rustc_default_linker = default_linker; config.musl_root = musl_root.map(PathBuf::from); config.save_toolstates = save_toolstates.map(PathBuf::from); - set( - &mut config.deny_warnings, - match flags.warnings { - Warnings::Deny => Some(true), - Warnings::Warn => Some(false), - Warnings::Default => deny_warnings, - }, - ); + set(&mut config.deny_warnings, match flags.warnings { + Warnings::Deny => Some(true), + Warnings::Warn => Some(false), + Warnings::Default => deny_warnings, + }); set(&mut config.backtrace_on_ice, backtrace_on_ice); set(&mut config.rust_verify_llvm_ir, verify_llvm_ir); config.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit; @@ -1805,6 +1823,7 @@ impl Config { release_debuginfo, assertions, tests, + enzyme, plugins, ccache, static_libstdcpp, @@ -1838,6 +1857,7 @@ impl Config { set(&mut config.ninja_in_file, ninja); llvm_assertions = assertions; llvm_tests = tests; + llvm_enzyme = enzyme; llvm_plugins = plugins; set(&mut config.llvm_optimize, optimize_toml); set(&mut config.llvm_thin_lto, thin_lto); @@ -1900,34 +1920,9 @@ impl Config { "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false." ); } - - // None of the LLVM options, except assertions, are supported - // when using downloaded LLVM. We could just ignore these but - // that's potentially confusing, so force them to not be - // explicitly set. The defaults and CI defaults don't - // necessarily match but forcing people to match (somewhat - // arbitrary) CI configuration locally seems bad/hard. - check_ci_llvm!(optimize_toml); - check_ci_llvm!(thin_lto); - check_ci_llvm!(release_debuginfo); - check_ci_llvm!(targets); - check_ci_llvm!(experimental_targets); - check_ci_llvm!(clang_cl); - check_ci_llvm!(version_suffix); - check_ci_llvm!(cflags); - check_ci_llvm!(cxxflags); - check_ci_llvm!(ldflags); - check_ci_llvm!(use_libcxx); - check_ci_llvm!(use_linker); - check_ci_llvm!(allow_old_toolchain); - check_ci_llvm!(polly); - check_ci_llvm!(clang); - check_ci_llvm!(build_config); - check_ci_llvm!(plugins); } - // NOTE: can never be hit when downloading from CI, since we call `check_ci_llvm!(thin_lto)` above. - if config.llvm_thin_lto && link_shared.is_none() { + if !config.llvm_from_ci && config.llvm_thin_lto && link_shared.is_none() { // If we're building with ThinLTO on, by default we want to link // to LLVM shared, to avoid re-doing ThinLTO (which happens in // the link step) with each stage. @@ -2032,13 +2027,19 @@ impl Config { compression_formats, compression_profile, include_mingw_linker, + vendor, } = dist; config.dist_sign_folder = sign_folder.map(PathBuf::from); config.dist_upload_addr = upload_addr; config.dist_compression_formats = compression_formats; set(&mut config.dist_compression_profile, compression_profile); set(&mut config.rust_dist_src, src_tarball); - set(&mut config.dist_include_mingw_linker, include_mingw_linker) + set(&mut config.dist_include_mingw_linker, include_mingw_linker); + config.dist_vendor = vendor.unwrap_or_else(|| { + // If we're building from git or tarball sources, enable it by default. + config.rust_info.is_managed_git_subrepository() + || config.rust_info.is_from_tarball() + }); } if let Some(r) = rustfmt { @@ -2054,6 +2055,7 @@ impl Config { config.llvm_assertions = llvm_assertions.unwrap_or(false); config.llvm_tests = llvm_tests.unwrap_or(false); + config.llvm_enzyme = llvm_enzyme.unwrap_or(false); config.llvm_plugins = llvm_plugins.unwrap_or(false); config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true)); @@ -2365,10 +2367,7 @@ impl Config { self.download_ci_rustc(commit); if let Some(config_path) = &self.config { - let builder_config_path = - self.out.join(self.build.triple).join("ci-rustc").join(BUILDER_CONFIG_FILENAME); - - let ci_config_toml = match Self::get_toml(&builder_config_path) { + let ci_config_toml = match self.get_builder_toml("ci-rustc") { Ok(ci_config_toml) => ci_config_toml, Err(e) if e.to_string().contains("unknown field") => { println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled."); @@ -2376,7 +2375,7 @@ impl Config { return None; }, Err(e) => { - eprintln!("ERROR: Failed to parse CI rustc config at '{}': {e}", builder_config_path.display()); + eprintln!("ERROR: Failed to parse CI rustc config.toml: {e}"); exit!(2); }, }; @@ -2493,9 +2492,6 @@ impl Config { self.target_config .get(&target) .and_then(|t| t.split_debuginfo) - .or_else(|| { - if self.build == target { self.rust_split_debuginfo_for_build_triple } else { None } - }) .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target)) } @@ -2521,6 +2517,7 @@ impl Config { GitConfig { git_repository: &self.stage0_metadata.config.git_repository, nightly_branch: &self.stage0_metadata.config.nightly_branch, + git_merge_commit_email: &self.stage0_metadata.config.git_merge_commit_email, } } @@ -2697,13 +2694,7 @@ impl Config { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let commit = get_closest_merge_base_commit( - Some(&self.src), - &self.git_config(), - &self.stage0_metadata.config.git_merge_commit_email, - &[], - ) - .unwrap(); + let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap(); if commit.is_empty() { println!("ERROR: could not find commit hash for downloading rustc"); println!("HELP: maybe your repository history is too shallow?"); @@ -2744,6 +2735,8 @@ impl Config { download_ci_llvm: Option, asserts: bool, ) -> bool { + let download_ci_llvm = download_ci_llvm.unwrap_or(StringOrBool::Bool(true)); + let if_unchanged = || { if self.rust_info.is_from_tarball() { // Git is needed for running "if-unchanged" logic. @@ -2753,6 +2746,8 @@ impl Config { return false; } + // Fetching the LLVM submodule is unnecessary for self-tests. + #[cfg(not(feature = "bootstrap-self-test"))] self.update_submodule("src/llvm-project"); // Check for untracked changes in `src/llvm-project`. @@ -2765,20 +2760,18 @@ impl Config { }; match download_ci_llvm { - None => { - (self.channel == "dev" || self.download_rustc_commit.is_some()) && if_unchanged() - } - Some(StringOrBool::Bool(b)) => { + StringOrBool::Bool(b) => { if !b && self.download_rustc_commit.is_some() { panic!( "`llvm.download-ci-llvm` cannot be set to `false` if `rust.download-rustc` is set to `true` or `if-unchanged`." ); } - b + // If download-ci-llvm=true we also want to check that CI llvm is available + b && llvm::is_ci_llvm_available(self, asserts) } - Some(StringOrBool::String(s)) if s == "if-unchanged" => if_unchanged(), - Some(StringOrBool::String(other)) => { + StringOrBool::String(s) if s == "if-unchanged" => if_unchanged(), + StringOrBool::String(other) => { panic!("unrecognized option for download-ci-llvm: {:?}", other) } } @@ -2794,13 +2787,7 @@ impl Config { ) -> Option { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let commit = get_closest_merge_base_commit( - Some(&self.src), - &self.git_config(), - &self.stage0_metadata.config.git_merge_commit_email, - &[], - ) - .unwrap(); + let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap(); if commit.is_empty() { println!("error: could not find commit hash for downloading components from CI"); println!("help: maybe your repository history is too shallow?"); @@ -2840,6 +2827,109 @@ impl Config { } } +/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options. +/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing. +#[cfg(not(feature = "bootstrap-self-test"))] +pub(crate) fn check_incompatible_options_for_ci_llvm( + current_config_toml: TomlConfig, + ci_config_toml: TomlConfig, +) -> Result<(), String> { + macro_rules! err { + ($current:expr, $expected:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + return Err(format!( + "ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \ + Current value: {:?}, Expected value(s): {}{:?}", + stringify!($expected).replace("_", "-"), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + )); + }; + }; + }; + } + + macro_rules! warn { + ($current:expr, $expected:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + println!( + "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \ + Current value: {:?}, Expected value(s): {}{:?}", + stringify!($expected).replace("_", "-"), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + ); + }; + }; + }; + } + + let (Some(current_llvm_config), Some(ci_llvm_config)) = + (current_config_toml.llvm, ci_config_toml.llvm) + else { + return Ok(()); + }; + + let Llvm { + optimize, + thin_lto, + release_debuginfo, + assertions: _, + tests: _, + plugins, + ccache: _, + static_libstdcpp: _, + libzstd, + ninja: _, + targets, + experimental_targets, + link_jobs: _, + link_shared: _, + version_suffix, + clang_cl, + cflags, + cxxflags, + ldflags, + use_libcxx, + use_linker, + allow_old_toolchain, + polly, + clang, + enable_warnings, + download_ci_llvm: _, + build_config, + enzyme, + } = ci_llvm_config; + + err!(current_llvm_config.optimize, optimize); + err!(current_llvm_config.thin_lto, thin_lto); + err!(current_llvm_config.release_debuginfo, release_debuginfo); + err!(current_llvm_config.libzstd, libzstd); + err!(current_llvm_config.targets, targets); + err!(current_llvm_config.experimental_targets, experimental_targets); + err!(current_llvm_config.clang_cl, clang_cl); + err!(current_llvm_config.version_suffix, version_suffix); + err!(current_llvm_config.cflags, cflags); + err!(current_llvm_config.cxxflags, cxxflags); + err!(current_llvm_config.ldflags, ldflags); + err!(current_llvm_config.use_libcxx, use_libcxx); + err!(current_llvm_config.use_linker, use_linker); + err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain); + err!(current_llvm_config.polly, polly); + err!(current_llvm_config.clang, clang); + err!(current_llvm_config.build_config, build_config); + err!(current_llvm_config.plugins, plugins); + err!(current_llvm_config.enzyme, enzyme); + + warn!(current_llvm_config.enable_warnings, enable_warnings); + + Ok(()) +} + /// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options. /// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing. fn check_incompatible_options_for_ci_rustc( @@ -2889,6 +2979,7 @@ fn check_incompatible_options_for_ci_rustc( let Rust { // Following options are the CI rustc incompatible ones. optimize, + randomize_layout, debug_logging, debuginfo_level_rustc, llvm_tools, @@ -2916,7 +3007,6 @@ fn check_incompatible_options_for_ci_rustc( debuginfo_level_std: _, debuginfo_level_tools: _, debuginfo_level_tests: _, - split_debuginfo: _, backtrace: _, parallel_compiler: _, musl_root: _, @@ -2953,6 +3043,7 @@ fn check_incompatible_options_for_ci_rustc( // otherwise, we just print a warning with `warn` macro. err!(current_rust_config.optimize, optimize); + err!(current_rust_config.randomize_layout, randomize_layout); err!(current_rust_config.debug_logging, debug_logging); err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc); err!(current_rust_config.rpath, rpath); diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index c3f1740281492..87db5f93fb03c 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -9,7 +9,7 @@ use clap::{CommandFactory, Parser, ValueEnum}; use crate::core::build_steps::setup::Profile; use crate::core::builder::{Builder, Kind}; -use crate::core::config::{target_selection_list, Config, TargetSelectionList}; +use crate::core::config::{Config, TargetSelectionList, target_selection_list}; use crate::{Build, DocTests}; #[derive(Copy, Clone, Default, Debug, ValueEnum)] @@ -143,9 +143,6 @@ pub struct Flags { /// Unless you know exactly what you are doing, you probably don't need this. pub bypass_bootstrap_lock: bool, - /// whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml - #[arg(global = true, long, value_name = "VALUE")] - pub llvm_skip_rebuild: Option, /// generate PGO profile with rustc build #[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] pub rust_profile_generate: Option, diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 219c5a6ec914e..e38d4eac051d8 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -1,5 +1,5 @@ use std::env; -use std::fs::{remove_file, File}; +use std::fs::{File, remove_file}; use std::io::Write; use std::path::Path; @@ -32,7 +32,7 @@ fn download_ci_llvm() { assert!(!parse_llvm("llvm.download-ci-llvm = false")); assert_eq!(parse_llvm(""), if_unchanged); assert_eq!(parse_llvm("rust.channel = \"dev\""), if_unchanged); - assert!(!parse_llvm("rust.channel = \"stable\"")); + assert!(parse_llvm("rust.channel = \"stable\"")); assert_eq!(parse_llvm("build.build = \"x86_64-unknown-linux-gnu\""), if_unchanged); assert_eq!( parse_llvm( @@ -317,3 +317,12 @@ fn order_of_clippy_rules() { assert_eq!(expected, actual); } + +#[test] +fn verbose_tests_default_value() { + let config = Config::parse(Flags::parse(&["build".into(), "compiler".into()])); + assert_eq!(config.verbose_tests, false); + + let config = Config::parse(Flags::parse(&["build".into(), "compiler".into(), "-v".into()])); + assert_eq!(config.verbose_tests, true); +} diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 1e3f8da525823..444b75876f248 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -10,9 +10,9 @@ use build_helper::ci::CiEnv; use xz2::bufread::XzDecoder; use crate::core::config::BUILDER_CONFIG_FILENAME; -use crate::utils::exec::{command, BootstrapCommand}; +use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{check_run, exe, hex_encode, move_file, program_out_of_date}; -use crate::{t, Config}; +use crate::{Config, t}; static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock = OnceLock::new(); @@ -228,25 +228,42 @@ impl Config { fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) { println!("downloading {url}"); // Try curl. If that fails and we are on windows, fallback to PowerShell. + // options should be kept in sync with + // src/bootstrap/src/core/download.rs + // for consistency let mut curl = command("curl"); curl.args([ - "-y", + // follow redirect + "--location", + // timeout if speed is < 10 bytes/sec for > 30 seconds + "--speed-time", "30", - "-Y", - "10", // timeout if speed is < 10 bytes/sec for > 30 seconds + "--speed-limit", + "10", + // timeout if cannot connect within 30 seconds "--connect-timeout", - "30", // timeout if cannot connect within 30 seconds - "-o", + "30", + // output file + "--output", tempfile.to_str().unwrap(), + // if there is an error, don't restart the download, + // instead continue where it left off. "--continue-at", "-", + // retry up to 3 times. note that this means a maximum of 4 + // attempts will be made, since the first attempt isn't a *re*try. "--retry", "3", - "-SRf", + // show errors, even if --silent is specified + "--show-error", + // set timestamp of downloaded file to that of the server + "--remote-time", + // fail on non-ok http status + "--fail", ]); // Don't print progress in CI; the \r wrapping looks bad and downloads don't take long enough for progress to be useful. if CiEnv::is_ci() { - curl.arg("-s"); + curl.arg("--silent"); } else { curl.arg("--progress-bar"); } @@ -299,6 +316,7 @@ impl Config { let mut tar = tar::Archive::new(decompressor); let is_ci_rustc = dst.ends_with("ci-rustc"); + let is_ci_llvm = dst.ends_with("ci-llvm"); // `compile::Sysroot` needs to know the contents of the `rustc-dev` tarball to avoid adding // it to the sysroot unless it was explicitly requested. But parsing the 100 MB tarball is slow. @@ -315,7 +333,9 @@ impl Config { let mut short_path = t!(original_path.strip_prefix(directory_prefix)); let is_builder_config = short_path.to_str() == Some(BUILDER_CONFIG_FILENAME); - if !(short_path.starts_with(pattern) || (is_ci_rustc && is_builder_config)) { + if !(short_path.starts_with(pattern) + || ((is_ci_rustc || is_ci_llvm) && is_builder_config)) + { continue; } short_path = short_path.strip_prefix(pattern).unwrap_or(short_path); @@ -700,17 +720,22 @@ download-rustc = false #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn maybe_download_ci_llvm(&self) { + use build_helper::exit; + use crate::core::build_steps::llvm::detect_llvm_sha; + use crate::core::config::check_incompatible_options_for_ci_llvm; if !self.llvm_from_ci { return; } + let llvm_root = self.ci_llvm_root(); let llvm_stamp = llvm_root.join(".llvm-stamp"); let llvm_sha = detect_llvm_sha(self, self.rust_info.is_managed_git_subrepository()); let key = format!("{}{}", llvm_sha, self.llvm_assertions); if program_out_of_date(&llvm_stamp, &key) && !self.dry_run() { self.download_ci_llvm(&llvm_sha); + if self.should_fix_bins_and_dylibs() { for entry in t!(fs::read_dir(llvm_root.join("bin"))) { self.fix_bin_or_dylib(&t!(entry).path()); @@ -743,6 +768,26 @@ download-rustc = false t!(fs::write(llvm_stamp, key)); } + + if let Some(config_path) = &self.config { + let current_config_toml = Self::get_toml(config_path).unwrap(); + + match self.get_builder_toml("ci-llvm") { + Ok(ci_config_toml) => { + t!(check_incompatible_options_for_ci_llvm(current_config_toml, ci_config_toml)); + } + Err(e) if e.to_string().contains("unknown field") => { + println!( + "WARNING: CI LLVM has some fields that are no longer supported in bootstrap; download-ci-llvm will be disabled." + ); + println!("HELP: Consider rebasing to a newer commit if available."); + } + Err(e) => { + eprintln!("ERROR: Failed to parse CI LLVM config.toml: {e}"); + exit!(2); + } + }; + }; } #[cfg(not(feature = "bootstrap-self-test"))] diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 1016607fc8318..983674d2c6835 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -1,9 +1,10 @@ +use std::collections::BTreeMap; use std::path::PathBuf; use serde_derive::Deserialize; use crate::utils::exec::command; -use crate::{t, Build, Crate}; +use crate::{Build, Crate, t}; /// For more information, see the output of /// @@ -21,6 +22,7 @@ struct Package { manifest_path: String, dependencies: Vec, targets: Vec, + features: BTreeMap>, } /// For more information, see the output of @@ -51,7 +53,13 @@ pub fn build(build: &mut Build) { .map(|dep| dep.name) .collect(); let has_lib = package.targets.iter().any(|t| t.kind.iter().any(|k| k == "lib")); - let krate = Crate { name: name.clone(), deps, path, has_lib }; + let krate = Crate { + name: name.clone(), + deps, + path, + has_lib, + features: package.features.keys().cloned().collect(), + }; let relative_path = krate.local_path(build); build.crates.insert(name.clone(), krate); let existing_path = build.crate_paths.insert(relative_path, name); diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 60ec57d0d443a..888ba8e2a3f75 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -13,6 +13,9 @@ use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use std::{env, fs}; +use build_helper::git::warn_old_master_branch; + +use crate::Build; #[cfg(not(feature = "bootstrap-self-test"))] use crate::builder::Builder; use crate::builder::Kind; @@ -20,7 +23,6 @@ use crate::builder::Kind; use crate::core::build_steps::tool; use crate::core::config::Target; use crate::utils::exec::command; -use crate::Build; pub struct Finder { cache: HashMap>, @@ -34,6 +36,7 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined + "armv7-rtems-eabihf", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM @@ -230,7 +233,8 @@ than building it. } // Ignore fake targets that are only used for unit tests in bootstrap. - if cfg!(not(feature = "bootstrap-self-test")) && !skip_target_sanity { + if cfg!(not(feature = "bootstrap-self-test")) && !skip_target_sanity && !build.local_rebuild + { let mut has_target = false; let target_str = target.to_string(); @@ -290,19 +294,19 @@ than building it. } } - for host in &build.hosts { - if !build.config.dry_run() { + if !build.config.dry_run() { + for host in &build.hosts { cmd_finder.must_have(build.cxx(*host).unwrap()); - } - if build.config.llvm_enabled(*host) { - // Externally configured LLVM requires FileCheck to exist - let filecheck = build.llvm_filecheck(build.build); - if !filecheck.starts_with(&build.out) - && !filecheck.exists() - && build.config.codegen_tests - { - panic!("FileCheck executable {filecheck:?} does not exist"); + if build.config.llvm_enabled(*host) { + // Externally configured LLVM requires FileCheck to exist + let filecheck = build.llvm_filecheck(build.build); + if !filecheck.starts_with(&build.out) + && !filecheck.exists() + && build.config.codegen_tests + { + panic!("FileCheck executable {filecheck:?} does not exist"); + } } } } @@ -351,7 +355,8 @@ than building it. // There are three builds of cmake on windows: MSVC, MinGW, and // Cygwin. The Cygwin build does not have generators for Visual // Studio, so detect that here and error. - let out = command("cmake").arg("--help").run_capture_stdout(build).stdout(); + let out = + command("cmake").arg("--help").run_always().run_capture_stdout(build).stdout(); if !out.contains("Visual Studio") { panic!( " @@ -374,4 +379,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake if let Some(ref s) = build.config.ccache { cmd_finder.must_have(s); } + + warn_old_master_branch(&build.config.git_config(), &build.config.src); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 268392c5fb118..7bf5b4e23d29b 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -35,8 +35,8 @@ use utils::helpers::hex_encode; use crate::core::builder; use crate::core::builder::{Builder, Kind}; -use crate::core::config::{flags, DryRun, LldMode, LlvmLibunwind, Target, TargetSelection}; -use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode}; +use crate::core::config::{DryRun, LldMode, LlvmLibunwind, Target, TargetSelection, flags}; +use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command}; use crate::utils::helpers::{ self, dir_is_empty, exe, libdir, mtime, output, set_file_times, symlink_dir, }; @@ -45,11 +45,11 @@ mod core; mod utils; pub use core::builder::PathSet; -pub use core::config::flags::{Flags, Subcommand}; pub use core::config::Config; +pub use core::config::flags::{Flags, Subcommand}; pub use utils::change_tracker::{ - find_recent_config_change_ids, human_readable_changes, CONFIG_CHANGE_HISTORY, + CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes, }; const LLVM_TOOLS: &[&str] = &[ @@ -77,6 +77,9 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; #[allow(clippy::type_complexity)] // It's fine for hard-coded list and type is explained above. const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ (None, "bootstrap", None), + (Some(Mode::Rustc), "llvm_enzyme", None), + (Some(Mode::Codegen), "llvm_enzyme", None), + (Some(Mode::ToolRustc), "llvm_enzyme", None), (Some(Mode::Rustc), "parallel_compiler", None), (Some(Mode::ToolRustc), "parallel_compiler", None), (Some(Mode::ToolRustc), "rust_analyzer", None), @@ -140,7 +143,9 @@ pub struct Build { clippy_info: GitInfo, miri_info: GitInfo, rustfmt_info: GitInfo, + enzyme_info: GitInfo, in_tree_llvm_info: GitInfo, + in_tree_gcc_info: GitInfo, local_rebuild: bool, fail_fast: bool, doc_tests: DocTests, @@ -183,6 +188,7 @@ struct Crate { deps: HashSet, path: PathBuf, has_lib: bool, + features: Vec, } impl Crate { @@ -306,9 +312,11 @@ impl Build { let clippy_info = GitInfo::new(omit_git_hash, &src.join("src/tools/clippy")); let miri_info = GitInfo::new(omit_git_hash, &src.join("src/tools/miri")); let rustfmt_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt")); + let enzyme_info = GitInfo::new(omit_git_hash, &src.join("src/tools/enzyme")); // we always try to use git for LLVM builds let in_tree_llvm_info = GitInfo::new(false, &src.join("src/llvm-project")); + let in_tree_gcc_info = GitInfo::new(false, &src.join("src/gcc")); let initial_target_libdir_str = if config.dry_run() { "/dummy/lib/path/to/lib/".to_string() @@ -332,14 +340,24 @@ impl Build { .trim() .to_string(); - let initial_libdir = initial_target_dir - .parent() - .unwrap() - .parent() - .unwrap() - .strip_prefix(&initial_sysroot) - .unwrap() - .to_path_buf(); + // FIXME(Zalathar): Determining this path occasionally fails locally for + // unknown reasons, so we print some extra context to help track down why. + let find_initial_libdir = || { + let initial_libdir = + initial_target_dir.parent()?.parent()?.strip_prefix(&initial_sysroot).ok()?; + Some(initial_libdir.to_path_buf()) + }; + let Some(initial_libdir) = find_initial_libdir() else { + panic!( + "couldn't determine `initial_libdir`: +- config.initial_rustc: {rustc:?} +- initial_target_libdir_str: {initial_target_libdir_str:?} +- initial_target_dir: {initial_target_dir:?} +- initial_sysroot: {initial_sysroot:?} +", + rustc = config.initial_rustc, + ); + }; let version = std::fs::read_to_string(src.join("src").join("version")) .expect("failed to read src/version"); @@ -393,7 +411,9 @@ impl Build { clippy_info, miri_info, rustfmt_info, + enzyme_info, in_tree_llvm_info, + in_tree_gcc_info, cc: RefCell::new(HashMap::new()), cxx: RefCell::new(HashMap::new()), ar: RefCell::new(HashMap::new()), @@ -532,11 +552,7 @@ impl Build { // Look for `submodule.$name.path = $path` // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer` let submodule = line.split_once(' ').unwrap().1; - let path = Path::new(submodule); - // Don't update the submodule unless it's already been cloned. - if GitInfo::new(false, path).is_managed_git_subrepository() { - self.config.update_submodule(submodule); - } + self.update_existing_submodule(submodule); } } @@ -580,15 +596,6 @@ impl Build { _ => (), } - { - let builder = builder::Builder::new(self); - if let Some(path) = builder.paths.first() { - if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") { - return; - } - } - } - if !self.config.dry_run() { { // We first do a dry-run. This is a sanity-check to ensure that @@ -666,25 +673,36 @@ impl Build { } /// Gets the space-separated set of activated features for the compiler. - fn rustc_features(&self, kind: Kind, target: TargetSelection) -> String { + fn rustc_features(&self, kind: Kind, target: TargetSelection, crates: &[String]) -> String { + let possible_features_by_crates: HashSet<_> = crates + .iter() + .flat_map(|krate| &self.crates[krate].features) + .map(std::ops::Deref::deref) + .collect(); + let check = |feature: &str| -> bool { + crates.is_empty() || possible_features_by_crates.contains(feature) + }; let mut features = vec![]; - if self.config.jemalloc { + if self.config.jemalloc && check("jemalloc") { features.push("jemalloc"); } - if self.config.llvm_enabled(target) || kind == Kind::Check { + if (self.config.llvm_enabled(target) || kind == Kind::Check) && check("llvm") { features.push("llvm"); } // keep in sync with `bootstrap/compile.rs:rustc_cargo_env` - if self.config.rustc_parallel { + if self.config.rustc_parallel && check("rustc_use_parallel_compiler") { features.push("rustc_use_parallel_compiler"); } + if self.config.rust_randomize_layout { + features.push("rustc_randomized_layouts"); + } // If debug logging is on, then we want the default for tracing: // https://github.com/tokio-rs/tracing/blob/3dd5c03d907afdf2c39444a29931833335171554/tracing/src/level_filters.rs#L26 // which is everything (including debug/trace/etc.) // if its unset, if debug_assertions is on, then debug_logging will also be on // as well as tracing *ignoring* this feature when debug_assertions is on - if !self.config.rust_debug_logging { + if !self.config.rust_debug_logging && check("max_level_info") { features.push("max_level_info"); } @@ -737,6 +755,14 @@ impl Build { } } + fn enzyme_out(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("enzyme") + } + + fn gcc_out(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("gcc") + } + fn lld_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("lld") } @@ -1379,16 +1405,17 @@ Executed at: {executed_at}"#, None } - /// Returns whether it's requested that `wasm-component-ld` is built as part - /// of the sysroot. This is done either with the `extended` key in - /// `config.toml` or with the `tools` set. - fn build_wasm_component_ld(&self) -> bool { - if self.config.extended { - return true; + /// Returns whether the specified tool is configured as part of this build. + /// + /// This requires that both the `extended` key is set and the `tools` key is + /// either unset or specifically contains the specified tool. + fn tool_enabled(&self, tool: &str) -> bool { + if !self.config.extended { + return false; } match &self.config.tools { - Some(set) => set.contains("wasm-component-ld"), - None => false, + Some(set) => set.contains(tool), + None => true, } } @@ -1501,6 +1528,7 @@ Executed at: {executed_at}"#, "refs/remotes/origin/{}..HEAD", self.config.stage0_metadata.config.nightly_branch )) + .run_always() .run_capture(self) .stdout() }); diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 29e6b74aaceb8..0df0046945220 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -26,7 +26,7 @@ use std::path::{Path, PathBuf}; use std::{env, iter}; use crate::core::config::TargetSelection; -use crate::utils::exec::{command, BootstrapCommand}; +use crate::utils::exec::{BootstrapCommand, command}; use crate::{Build, CLang, GitRepo}; // The `cc` crate doesn't provide a way to obtain a path to the detected archiver, @@ -87,15 +87,28 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { } pub fn find(build: &Build) { - // For all targets we're going to need a C compiler for building some shims - // and such as well as for being a linker for Rust code. - let targets = build - .targets - .iter() - .chain(&build.hosts) - .cloned() - .chain(iter::once(build.build)) - .collect::>(); + let targets: HashSet<_> = match build.config.cmd { + // We don't need to check cross targets for these commands. + crate::Subcommand::Clean { .. } + | crate::Subcommand::Suggest { .. } + | crate::Subcommand::Format { .. } + | crate::Subcommand::Setup { .. } => { + build.hosts.iter().cloned().chain(iter::once(build.build)).collect() + } + + _ => { + // For all targets we're going to need a C compiler for building some shims + // and such as well as for being a linker for Rust code. + build + .targets + .iter() + .chain(&build.hosts) + .cloned() + .chain(iter::once(build.build)) + .collect() + } + }; + for target in targets.into_iter() { find_target(build, target); } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 51a25104e4cfb..e6f7f105fa27a 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -235,4 +235,39 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "The `build.profiler` option now tries to use source code from `download-ci-llvm` if possible, instead of checking out the `src/llvm-project` submodule.", }, + ChangeInfo { + change_id: 129152, + severity: ChangeSeverity::Info, + summary: "New option `build.cargo-clippy` added for supporting the use of custom/external clippy.", + }, + ChangeInfo { + change_id: 129925, + severity: ChangeSeverity::Warning, + summary: "Removed `rust.split-debuginfo` as it was deprecated long time ago.", + }, + ChangeInfo { + change_id: 129176, + severity: ChangeSeverity::Info, + summary: "New option `llvm.enzyme` to control whether the llvm based autodiff tool (Enzyme) is built.", + }, + ChangeInfo { + change_id: 129473, + severity: ChangeSeverity::Warning, + summary: "`download-ci-llvm = true` now checks if CI llvm is available and has become the default for the compiler profile", + }, + ChangeInfo { + change_id: 130202, + severity: ChangeSeverity::Info, + summary: "'tools' and 'library' profiles switched `download-ci-llvm` option from `if-unchanged` to `true`.", + }, + ChangeInfo { + change_id: 130110, + severity: ChangeSeverity::Info, + summary: "New option `dist.vendor` added to control whether bootstrap should vendor dependencies for dist tarball.", + }, + ChangeInfo { + change_id: 130529, + severity: ChangeSeverity::Info, + summary: "If `llvm.download-ci-llvm` is not defined, it defaults to `true`.", + }, ]; diff --git a/src/bootstrap/src/utils/change_tracker/tests.rs b/src/bootstrap/src/utils/change_tracker/tests.rs index d2bfc07d1727b..730b65b4879c9 100644 --- a/src/bootstrap/src/utils/change_tracker/tests.rs +++ b/src/bootstrap/src/utils/change_tracker/tests.rs @@ -1,4 +1,4 @@ -use crate::{find_recent_config_change_ids, CONFIG_CHANGE_HISTORY}; +use crate::{CONFIG_CHANGE_HISTORY, find_recent_config_change_ids}; #[test] fn test_find_recent_config_change_ids() { diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index 3ae512ef7f1c2..c361abb9c9e13 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -9,8 +9,8 @@ use std::fs; use std::path::Path; use super::helpers; -use crate::utils::helpers::{output, t}; use crate::Build; +use crate::utils::helpers::{output, t}; #[derive(Clone, Default)] pub enum GitInfo { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index a856c99ff55a5..2519ace92b9e0 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -10,13 +10,12 @@ use std::sync::OnceLock; use std::time::{Instant, SystemTime, UNIX_EPOCH}; use std::{env, fs, io, str}; -use build_helper::git::{get_git_merge_base, output_result, GitConfig}; use build_helper::util::fail; +use crate::LldMode; use crate::core::builder::Builder; use crate::core::config::{Config, TargetSelection}; pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var}; -use crate::LldMode; #[cfg(test)] mod tests; @@ -47,7 +46,7 @@ macro_rules! t { } pub use t; -use crate::utils::exec::{command, BootstrapCommand}; +use crate::utils::exec::{BootstrapCommand, command}; pub fn exe(name: &str, target: TargetSelection) -> String { crate::utils::shared_helpers::exe(name, &target.triple) @@ -523,28 +522,6 @@ pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { git } -/// Returns the closest commit available from upstream for the given `author` and `target_paths`. -/// -/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD. -pub fn get_closest_merge_base_commit( - source_dir: Option<&Path>, - config: &GitConfig<'_>, - author: &str, - target_paths: &[PathBuf], -) -> Result { - let mut git = git(source_dir); - - let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into()); - - git.args(["rev-list", &format!("--author={author}"), "-n1", "--first-parent", &merge_base]); - - if !target_paths.is_empty() { - git.arg("--").args(target_paths); - } - - Ok(output_result(git.as_command_mut())?.trim().to_owned()) -} - /// Sets the file times for a given file at `path`. pub fn set_file_times>(path: P, times: fs::FileTimes) -> io::Result<()> { // Windows requires file to be writable to modify file times. But on Linux CI the file does not @@ -556,3 +533,41 @@ pub fn set_file_times>(path: P, times: fs::FileTimes) -> io::Resu }; f.set_times(times) } + +pub struct HashStamp { + pub path: PathBuf, + pub hash: Option>, +} + +impl HashStamp { + pub fn new(path: PathBuf, hash: Option<&str>) -> Self { + HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) } + } + + pub fn is_done(&self) -> bool { + match fs::read(&self.path) { + Ok(h) => self.hash.as_deref().unwrap_or(b"") == h.as_slice(), + Err(e) if e.kind() == io::ErrorKind::NotFound => false, + Err(e) => { + panic!("failed to read stamp file `{}`: {}", self.path.display(), e); + } + } + } + + pub fn remove(&self) -> io::Result<()> { + match fs::remove_file(&self.path) { + Ok(()) => Ok(()), + Err(e) => { + if e.kind() == io::ErrorKind::NotFound { + Ok(()) + } else { + Err(e) + } + } + } + } + + pub fn write(&self) -> io::Result<()> { + fs::write(&self.path, self.hash.as_deref().unwrap_or(b"")) + } +} diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs index 86016a91e49b1..f6fe6f47aa4fa 100644 --- a/src/bootstrap/src/utils/helpers/tests.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -1,4 +1,4 @@ -use std::fs::{self, remove_file, File}; +use std::fs::{self, File, remove_file}; use std::io::Write; use std::path::PathBuf; diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index 4012f5167ff73..c5e892450c4c5 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -43,19 +43,19 @@ mod for_windows { use std::ffi::c_void; use std::{env, io, mem}; - use windows::core::PCWSTR; - use windows::Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE}; + use windows::Win32::Foundation::{CloseHandle, DUPLICATE_SAME_ACCESS, DuplicateHandle, HANDLE}; use windows::Win32::System::Diagnostics::Debug::{ - SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE, + SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE, }; use windows::Win32::System::JobObjects::{ - AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation, - SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, - JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, + AssignProcessToJobObject, CreateJobObjectW, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, + JOB_OBJECT_LIMIT_PRIORITY_CLASS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, + JobObjectExtendedLimitInformation, SetInformationJobObject, }; use windows::Win32::System::Threading::{ - GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE, + BELOW_NORMAL_PRIORITY_CLASS, GetCurrentProcess, OpenProcess, PROCESS_DUP_HANDLE, }; + use windows::core::PCWSTR; use crate::Build; diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index e9acb93363e76..3b31fa36e889e 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -15,9 +15,9 @@ use build_helper::metrics::{ }; use sysinfo::{CpuRefreshKind, RefreshKind, System}; +use crate::Build; use crate::core::builder::{Builder, Step}; use crate::utils::helpers::t; -use crate::Build; // Update this number whenever a breaking change is made to the build metrics. // diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index b8aebc2854906..eb2c8254dc0f4 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -88,6 +88,9 @@ struct Renderer<'a> { builder: &'a Builder<'a>, tests_count: Option, executed_tests: usize, + /// Number of tests that were skipped due to already being up-to-date + /// (i.e. no relevant changes occurred since they last ran). + up_to_date_tests: usize, terse_tests_in_line: usize, } @@ -100,6 +103,7 @@ impl<'a> Renderer<'a> { builder, tests_count: None, executed_tests: 0, + up_to_date_tests: 0, terse_tests_in_line: 0, } } @@ -127,6 +131,12 @@ impl<'a> Renderer<'a> { } } } + + if self.up_to_date_tests > 0 { + let n = self.up_to_date_tests; + let s = if n > 1 { "s" } else { "" }; + println!("help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n"); + } } /// Renders the stdout characters one by one @@ -149,6 +159,11 @@ impl<'a> Renderer<'a> { fn render_test_outcome(&mut self, outcome: Outcome<'_>, test: &TestOutcome) { self.executed_tests += 1; + // Keep this in sync with the "up-to-date" ignore message inserted by compiletest. + if let Outcome::Ignored { reason: Some("up-to-date") } = outcome { + self.up_to_date_tests += 1; + } + #[cfg(feature = "build-metrics")] self.builder.metrics.record_test( &test.name, diff --git a/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile index 855465aa38e24..475542b335683 100644 --- a/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile @@ -25,5 +25,5 @@ ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ ENV HOSTS=arm-unknown-linux-gnueabihf -ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-full-tools --enable-profiler --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh index f3591a69beee6..2e08c87f278c0 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh @@ -5,7 +5,7 @@ set -ex source shared.sh # Try to keep the LLVM version here in sync with src/ci/scripts/install-clang.sh -LLVM=llvmorg-18.1.0 +LLVM=llvmorg-19.1.0-rc3 mkdir llvm-project cd llvm-project @@ -33,6 +33,7 @@ hide_output \ -DCOMPILER_RT_BUILD_SANITIZERS=OFF \ -DCOMPILER_RT_BUILD_XRAY=OFF \ -DCOMPILER_RT_BUILD_MEMPROF=OFF \ + -DCOMPILER_RT_BUILD_CTX_PROFILE=OFF \ -DLLVM_TARGETS_TO_BUILD=X86 \ -DLLVM_INCLUDE_BENCHMARKS=OFF \ -DLLVM_INCLUDE_TESTS=OFF \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile index c9a6a2dd069e2..32b5058bce703 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile @@ -19,6 +19,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ patch \ libssl-dev \ pkg-config \ + zlib1g-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /build/ diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs index d75ee147799a7..89e4393cb5c7b 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs @@ -6,7 +6,7 @@ use core::{panic, ptr}; -use r_efi::efi::{Char16, Handle, Status, SystemTable, RESET_SHUTDOWN}; +use r_efi::efi::{Char16, Handle, RESET_SHUTDOWN, Status, SystemTable}; #[panic_handler] fn panic_handler(_info: &panic::PanicInfo) -> ! { diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile index 3476b10a3addc..487da58015222 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile @@ -51,6 +51,7 @@ ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --llvm-root=/usr/lib/llvm-18 \ --enable-llvm-link-shared \ + --set rust.randomize-layout=true \ --set rust.thin-lto-import-instr-limit=10 COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile similarity index 82% rename from src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile rename to src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile index 275acb47c33a7..4991908fe7734 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:23.10 +FROM ubuntu:24.10 ARG DEBIAN_FRONTEND=noninteractive @@ -15,8 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ sudo \ gdb \ - llvm-17-tools \ - llvm-17-dev \ + llvm-19-tools \ + llvm-19-dev \ libedit-dev \ libssl-dev \ pkg-config \ @@ -33,8 +33,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* # Install powershell (universal package) so we can test x.ps1 on Linux +# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep. RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ - dpkg -i powershell.deb && \ + dpkg --ignore-depends=libicu72 -i powershell.deb && \ rm -f powershell.deb COPY scripts/sccache.sh /scripts/ @@ -48,8 +49,9 @@ ENV EXTERNAL_LLVM 1 # Using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-17 \ + --llvm-root=/usr/lib/llvm-19 \ --enable-llvm-link-shared \ + --set rust.randomize-layout=true \ --set rust.thin-lto-import-instr-limit=10 COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index a5a5acc333be9..303a2f26c0f82 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -58,8 +58,9 @@ case $HOST_TARGET in # Strangely, Linux targets do not work here. cargo always says # "error: cannot produce cdylib for ... as the target ... does not support these crate types". # Only run "pass" tests, which is quite a bit faster. - python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass - python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-gnu --test-args pass + #FIXME: Re-enable this once CI issues are fixed + #python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass + #python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-gnu --test-args pass ;; *) echo "FATAL: unexpected host $HOST_TARGET" @@ -68,6 +69,10 @@ case $HOST_TARGET in esac # Also smoke-test `x.py miri`. This doesn't run any actual tests (that would take too long), # but it ensures that the crates build properly when tested with Miri. -python3 "$X_PY" miri --stage 2 library/core --test-args notest -python3 "$X_PY" miri --stage 2 library/alloc --test-args notest -python3 "$X_PY" miri --stage 2 library/std --test-args notest + +#FIXME: Re-enable this for msvc once CI issues are fixed +if [ "$HOST_TARGET" != "x86_64-pc-windows-msvc" ]; then + python3 "$X_PY" miri --stage 2 library/core --test-args notest + python3 "$X_PY" miri --stage 2 library/alloc --test-args notest + python3 "$X_PY" miri --stage 2 library/std --test-args notest +fi diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 389abb2fdd38c..8011e07e92e60 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -4,8 +4,8 @@ set -euo pipefail LINUX_VERSION=4c7864e81d8bbd51036dacf92fb0a400e13aaeee -# Build rustc, rustdoc and cargo -../x.py build --stage 1 library rustdoc +# Build rustc, rustdoc, cargo, clippy-driver and rustfmt +../x.py build --stage 2 library rustdoc clippy rustfmt ../x.py build --stage 0 cargo # Install rustup so that we can use the built toolchain easily, and also @@ -16,7 +16,7 @@ sh rustup.sh -y --default-toolchain none source /cargo/env BUILD_DIR=$(realpath ./build) -rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage1 +rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage2 rustup default local mkdir -p rfl @@ -62,11 +62,47 @@ make -C linux LLVM=1 -j$(($(nproc) + 1)) \ defconfig \ rfl-for-rust-ci.config -make -C linux LLVM=1 -j$(($(nproc) + 1)) \ - samples/rust/rust_minimal.o \ - samples/rust/rust_print.o \ - drivers/net/phy/ax88796b_rust.o \ +BUILD_TARGETS=" + samples/rust/rust_minimal.o + samples/rust/rust_print.o + drivers/net/phy/ax88796b_rust.o rust/doctests_kernel_generated.o +" + +# Build a few Rust targets +# +# This does not include building the C side of the kernel nor linking, +# which can find other issues, but it is much faster. +# +# This includes transforming `rustdoc` tests into KUnit ones thanks to +# `CONFIG_RUST_KERNEL_DOCTESTS=y` above (which, for the moment, uses the +# unstable `--test-builder` and `--no-run`). +make -C linux LLVM=1 -j$(($(nproc) + 1)) \ + $BUILD_TARGETS +# Generate documentation make -C linux LLVM=1 -j$(($(nproc) + 1)) \ rustdoc + +# Build macro expanded source (`-Zunpretty=expanded`) +# +# This target also formats the macro expanded code, thus it is also +# intended to catch ICEs with formatting `-Zunpretty=expanded` output +# like https://github.com/rust-lang/rustfmt/issues/6105. +make -C linux LLVM=1 -j$(($(nproc) + 1)) \ + samples/rust/rust_minimal.rsi + +# Re-build with Clippy enabled +# +# This should not introduce Clippy errors, since `CONFIG_WERROR` is not +# set (thus no `-Dwarnings`) and the kernel uses `-W` for all Clippy +# lints, including `clippy::all`. However, it could catch ICEs. +make -C linux LLVM=1 -j$(($(nproc) + 1)) CLIPPY=1 \ + $BUILD_TARGETS + +# Format the code +# +# This returns successfully even if there were changes, i.e. it is not +# a check. +make -C linux LLVM=1 -j$(($(nproc) + 1)) \ + rustfmt diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 4de44c6dd39d7..6379f1ade1ce8 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -24,6 +24,10 @@ runners: os: macos-14 <<: *base-job + - &job-windows + os: windows-2022 + <<: *base-job + - &job-windows-8c os: windows-2022-8core-32gb <<: *base-job @@ -85,7 +89,7 @@ pr: - image: mingw-check-tidy continue_on_error: true <<: *job-linux-4c - - image: x86_64-gnu-llvm-17 + - image: x86_64-gnu-llvm-18 env: ENABLE_GCC_CODEGEN: "1" <<: *job-linux-16c @@ -247,12 +251,12 @@ auto: - image: x86_64-gnu-distcheck <<: *job-linux-8c - - image: x86_64-gnu-llvm-18 + - image: x86_64-gnu-llvm-19 env: RUST_BACKTRACE: 1 <<: *job-linux-8c - - image: x86_64-gnu-llvm-17 + - image: x86_64-gnu-llvm-18 env: RUST_BACKTRACE: 1 <<: *job-linux-8c @@ -373,6 +377,18 @@ auto: DEPLOY_TOOLSTATES_JSON: toolstates-windows.json <<: *job-windows-8c + # Temporary builder to workaround CI issues + - image: x86_64-msvc-ext2 + env: + SCRIPT: > + python x.py test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass && + python x.py test --stage 2 src/tools/miri --target i686-pc-windows-gnu --test-args pass && + python x.py miri --stage 2 library/core --test-args notest && + python x.py miri --stage 2 library/alloc --test-args notest && + python x.py miri --stage 2 library/std --test-args notest + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld + <<: *job-windows + # 32/64-bit MinGW builds. # # We are using MinGW with POSIX threads since LLVM requires @@ -418,6 +434,7 @@ auto: --set rust.codegen-units=1 SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows-8c - image: dist-i686-msvc @@ -430,6 +447,7 @@ auto: --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows-8c - image: dist-aarch64-msvc @@ -454,6 +472,7 @@ auto: NO_DOWNLOAD_CI_LLVM: 1 SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows-8c - image: dist-x86_64-mingw @@ -466,6 +485,7 @@ auto: # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows-8c - image: dist-x86_64-msvc-alt diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 31aa3785bc369..91eab2e7a0816 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -6,8 +6,8 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -MINGW_ARCHIVE_32="i686-12.2.0-release-posix-dwarf-rt_v10-rev0.7z" -MINGW_ARCHIVE_64="x86_64-12.2.0-release-posix-seh-rt_v10-rev0.7z" +MINGW_ARCHIVE_32="i686-14.1.0-release-posix-dwarf-msvcrt-rt_v12-rev0.7z" +MINGW_ARCHIVE_64="x86_64-14.1.0-release-posix-seh-msvcrt-rt_v12-rev0.7z" if isWindows && isKnownToBeMingwBuild; then case "${CI_JOB_NAME}" in diff --git a/src/doc/book b/src/doc/book index e7d217be2a75e..99cf75a5414fa 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit e7d217be2a75ef1753f0988d6ccaba4d7e376259 +Subproject commit 99cf75a5414fa8adbe3974bd0836661ca901708f diff --git a/src/doc/edition-guide b/src/doc/edition-guide index eeba2cb9c37ab..c7ebae25cb480 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit eeba2cb9c37ab74118a4fb5e5233f7397e4a91f8 +Subproject commit c7ebae25cb4801a31b6f05353f6d85bfa6feedd1 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index ff5d61d56f11e..dbae36bf3f841 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit ff5d61d56f11e1986bfa9652c6aff7731576c37d +Subproject commit dbae36bf3f8410aa4313b3bad42e374735d48a9d diff --git a/src/doc/not_found.md b/src/doc/not_found.md index f0794fc0be378..9552759d2b8b3 100644 --- a/src/doc/not_found.md +++ b/src/doc/not_found.md @@ -2,7 +2,7 @@ -

+
- - - - - - - - + .github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + @keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } + } + @media (max-width: 500px) { + .github-corner:hover .octo-arm { + animation: none; + } + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + } + + diff --git a/src/tools/clippy/util/versions.py b/src/tools/clippy/util/versions.py index c041fc606a8f3..fee0d292df16f 100755 --- a/src/tools/clippy/util/versions.py +++ b/src/tools/clippy/util/versions.py @@ -1,22 +1,21 @@ #!/usr/bin/env python -import json -import logging as log +from string import Template +import argparse import os import sys -log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s") - - def key(v): if v == "master": - return float("inf") - if v == "stable": return sys.maxsize - if v == "beta": + if v == "stable": return sys.maxsize - 1 + if v == "beta": + return sys.maxsize - 2 if v == "pre-1.29.0": return -1 + if not v.startswith("rust-"): + return None v = v.replace("rust-", "") @@ -26,26 +25,27 @@ def key(v): return s - def main(): - if len(sys.argv) < 2: - log.error("specify output directory") - return + parser = argparse.ArgumentParser() + parser.add_argument("input", help="path to the versions.html template", type=argparse.FileType("r")) + parser.add_argument("outdir", help="path to write the output HTML") + args = parser.parse_args() - outdir = sys.argv[1] versions = [ dir - for dir in os.listdir(outdir) - if not dir.startswith(".") - and not dir.startswith("v") - and os.path.isdir(os.path.join(outdir, dir)) + for dir in os.listdir(args.outdir) + if key(dir) is not None ] - versions.sort(key=key) + versions.sort(key=key, reverse=True) + links = [f'{version}' for version in versions] - with open(os.path.join(outdir, "versions.json"), "w") as fp: - json.dump(versions, fp, indent=2) - log.info("wrote JSON for great justice") + template = Template(args.input.read()) + html = template.substitute(list="\n".join(links)) + path = os.path.join(args.outdir, "index.html") + with open(path, "w") as out: + out.write(html) + print(f"wrote HTML to {path}") if __name__ == "__main__": main() diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs index a559d6f81a240..865aa76ddb0c7 100644 --- a/src/tools/compiletest/src/command-list.rs +++ b/src/tools/compiletest/src/command-list.rs @@ -136,6 +136,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "min-llvm-version", "min-system-llvm-version", "needs-asm-support", + "needs-deterministic-layouts", "needs-dlltool", "needs-dynamic-linking", "needs-force-clang-based-tests", diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5831f7c3cf283..2d8c0c3fa5eb6 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -11,7 +11,7 @@ use serde::de::{Deserialize, Deserializer, Error as _}; use test::{ColorConfig, OutputFormat}; pub use self::Mode::*; -use crate::util::{add_dylib_path, PathBufExt}; +use crate::util::{PathBufExt, add_dylib_path}; macro_rules! string_enum { ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => { @@ -183,6 +183,9 @@ pub struct Config { /// The rustc executable. pub rustc_path: PathBuf, + /// The cargo executable. + pub cargo_path: Option, + /// The rustdoc executable. pub rustdoc_path: Option, @@ -274,6 +277,9 @@ pub struct Config { /// Flags to pass to the compiler when building for the target pub target_rustcflags: Vec, + /// Whether the compiler and stdlib has been built with randomized struct layouts + pub rust_randomized_layout: bool, + /// Whether tests should be optimized by default. Individual test-suites and test files may /// override this setting. pub optimize_tests: bool, @@ -381,6 +387,7 @@ pub struct Config { // Needed both to construct build_helper::git::GitConfig pub git_repository: String, pub nightly_branch: String, + pub git_merge_commit_email: String, /// True if the profiler runtime is enabled for this target. /// Used by the "needs-profiler-support" header in test files. @@ -458,7 +465,11 @@ impl Config { } pub fn git_config(&self) -> GitConfig<'_> { - GitConfig { git_repository: &self.git_repository, nightly_branch: &self.nightly_branch } + GitConfig { + git_repository: &self.git_repository, + nightly_branch: &self.nightly_branch, + git_merge_commit_email: &self.git_merge_commit_email, + } } } diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 4ca9f02ddc7c7..efe758e65cf66 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -1,7 +1,7 @@ use std::fmt; use std::fs::File; -use std::io::prelude::*; use std::io::BufReader; +use std::io::prelude::*; use std::path::Path; use std::str::FromStr; use std::sync::OnceLock; diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 933913eb47c34..a291ff3711239 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1,8 +1,8 @@ use std::collections::HashSet; use std::env; use std::fs::File; -use std::io::prelude::*; use std::io::BufReader; +use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::OnceLock; @@ -11,7 +11,7 @@ use regex::Regex; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; -use crate::header::cfg::{parse_cfg_name_directive, MatchOutcome}; +use crate::header::cfg::{MatchOutcome, parse_cfg_name_directive}; use crate::header::needs::CachedNeedsConditions; use crate::util::static_regex; use crate::{extract_cdb_version, extract_gdb_version}; @@ -125,7 +125,7 @@ pub struct TestProps { // Build documentation for all specified aux-builds as well pub build_aux_docs: bool, /// Build the documentation for each crate in a unique output directory. - /// Uses /docs//doc + /// Uses `/docs//doc`. pub unique_doc_out_dir: bool, // Flag to force a crate to be built with the host architecture pub force_host: bool, @@ -1304,12 +1304,12 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { false } -/// Takes a directive of the form " [- ]", -/// returns the numeric representation of and as -/// tuple: ( as u32, as u32) +/// Takes a directive of the form `" [- ]"`, +/// returns the numeric representation of `` and `` as +/// tuple: `( as u32, as u32)`. /// -/// If the part is omitted, the second component of the tuple -/// is the same as . +/// If the `` part is omitted, the second component of the tuple +/// is the same as ``. fn extract_version_range(line: &str, parse: F) -> Option<(u32, u32)> where F: Fn(&str) -> Option, diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 72b1b9c6d480a..99c0e850f1a24 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -1,5 +1,5 @@ use crate::common::{Config, Sanitizer}; -use crate::header::{llvm_has_libzstd, IgnoreDecision}; +use crate::header::{IgnoreDecision, llvm_has_libzstd}; pub(super) fn handle_needs( cache: &CachedNeedsConditions, @@ -134,6 +134,11 @@ pub(super) fn handle_needs( condition: config.target_cfg().relocation_model == "pic", ignore_reason: "ignored on targets without PIC relocation model", }, + Need { + name: "needs-deterministic-layouts", + condition: !config.rust_randomized_layout, + ignore_reason: "ignored when randomizing layouts", + }, Need { name: "needs-wasmtime", condition: config.runner.as_ref().is_some_and(|r| r.contains("wasmtime")), diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 29e11e77f1ce1..ae661200c6cfa 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use super::iter_header; use crate::common::{Config, Debugger, Mode}; -use crate::header::{parse_normalize_rule, EarlyProps, HeadersCache}; +use crate::header::{EarlyProps, HeadersCache, parse_normalize_rule}; fn make_test_description( config: &Config, @@ -148,6 +148,7 @@ impl ConfigBuilder { self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"), "--git-repository=", "--nightly-branch=", + "--git-merge-commit-email=", ]; let mut args: Vec = args.iter().map(ToString::to_string).collect(); @@ -225,10 +226,9 @@ fn revisions() { let config: Config = cfg().build(); assert_eq!(parse_rs(&config, "//@ revisions: a b c").revisions, vec!["a", "b", "c"],); - assert_eq!( - parse_makefile(&config, "# revisions: hello there").revisions, - vec!["hello", "there"], - ); + assert_eq!(parse_makefile(&config, "# revisions: hello there").revisions, vec![ + "hello", "there" + ],); } #[test] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 7018362af5410..cfc619f934208 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -34,10 +34,10 @@ use test::ColorConfig; use tracing::*; use walkdir::WalkDir; -use self::header::{make_test_description, EarlyProps}; +use self::header::{EarlyProps, make_test_description}; use crate::common::{ - expected_output_path, output_base_dir, output_relative_path, Config, Debugger, Mode, PassMode, - TestPaths, UI_EXTENSIONS, + Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path, + output_base_dir, output_relative_path, }; use crate::header::HeadersCache; use crate::util::logv; @@ -47,6 +47,7 @@ pub fn parse_config(args: Vec) -> Config { opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") + .optopt("", "cargo-path", "path to cargo to use for compiling", "PATH") .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") .optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH") .reqopt("", "python", "path to python to use for doc tests", "PATH") @@ -99,6 +100,11 @@ pub fn parse_config(args: Vec) -> Config { ) .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") + .optflag( + "", + "rust-randomized-layout", + "set this when rustc/stdlib were compiled with randomized layouts", + ) .optflag("", "optimize-tests", "run tests with optimizations enabled") .optflag("", "verbose", "run tests verbosely, showing all output") .optflag( @@ -158,7 +164,13 @@ pub fn parse_config(args: Vec) -> Config { ) .optopt("", "edition", "default Rust edition", "EDITION") .reqopt("", "git-repository", "name of the git repository", "ORG/REPO") - .reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH"); + .reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH") + .reqopt( + "", + "git-merge-commit-email", + "email address used for finding merge commits", + "EMAIL", + ); let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { @@ -249,6 +261,7 @@ pub fn parse_config(args: Vec) -> Config { compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), + cargo_path: matches.opt_str("cargo-path").map(PathBuf::from), rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), python: matches.opt_str("python").unwrap(), @@ -286,6 +299,7 @@ pub fn parse_config(args: Vec) -> Config { host_rustcflags: matches.opt_strs("host-rustcflags"), target_rustcflags: matches.opt_strs("target-rustcflags"), optimize_tests: matches.opt_present("optimize-tests"), + rust_randomized_layout: matches.opt_present("rust-randomized-layout"), target, host: opt_str2(matches.opt_str("host")), cdb, @@ -340,6 +354,7 @@ pub fn parse_config(args: Vec) -> Config { git_repository: matches.opt_str("git-repository").unwrap(), nightly_branch: matches.opt_str("nightly-branch").unwrap(), + git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(), profiler_support: matches.opt_present("profiler-support"), } @@ -351,6 +366,7 @@ pub fn log_config(config: &Config) { logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); + logv(c, format!("cargo_path: {:?}", config.cargo_path)); logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); logv(c, format!("src_base: {:?}", config.src_base.display())); logv(c, format!("build_base: {:?}", config.build_base.display())); @@ -634,6 +650,12 @@ fn common_inputs_stamp(config: &Config) -> Stamp { stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); } + // Re-run coverage tests if the `coverage-dump` tool was modified, + // because its output format might have changed. + if let Some(coverage_dump_path) = &config.coverage_dump_path { + stamp.add_path(coverage_dump_path) + } + stamp.add_dir(&rust_src_dir.join("src/tools/run-make-support")); // Compiletest itself. @@ -802,8 +824,12 @@ fn make_test( &config, cache, test_name, &test_path, src_file, revision, poisoned, ); // Ignore tests that already run and are up to date with respect to inputs. - if !config.force_rerun { - desc.ignore |= is_up_to_date(&config, testpaths, &early_props, revision, inputs); + if !config.force_rerun + && is_up_to_date(&config, testpaths, &early_props, revision, inputs) + { + desc.ignore = true; + // Keep this in sync with the "up-to-date" message detected by bootstrap. + desc.ignore_message = Some("up-to-date"); } test::TestDescAndFn { desc, diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index b2d068e78b48f..2375f391d03d0 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -232,9 +232,9 @@ mod imp { use std::process::{ChildStderr, ChildStdout}; use std::{io, slice}; + use miow::Overlapped; use miow::iocp::{CompletionPort, CompletionStatus}; use miow::pipe::NamedPipe; - use miow::Overlapped; use windows::Win32::Foundation::ERROR_BROKEN_PIPE; struct Pipe<'a> { diff --git a/src/tools/compiletest/src/read2/tests.rs b/src/tools/compiletest/src/read2/tests.rs index 9e052ff069b99..10572725431cc 100644 --- a/src/tools/compiletest/src/read2/tests.rs +++ b/src/tools/compiletest/src/read2/tests.rs @@ -1,6 +1,6 @@ use std::io::Write; -use crate::read2::{ProcOutput, FILTERED_PATHS_PLACEHOLDER_LEN, MAX_OUT_LEN}; +use crate::read2::{FILTERED_PATHS_PLACEHOLDER_LEN, MAX_OUT_LEN, ProcOutput}; #[test] fn test_abbreviate_short_string() { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index c18f569e52867..25a135aa32027 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2,8 +2,8 @@ use std::borrow::Cow; use std::collections::{HashMap, HashSet}; -use std::ffi::{OsStr, OsString}; -use std::fs::{self, create_dir_all, File, OpenOptions}; +use std::ffi::OsString; +use std::fs::{self, File, create_dir_all}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::io::prelude::*; use std::io::{self, BufReader}; @@ -14,29 +14,43 @@ use std::{env, iter, str}; use anyhow::Context; use colored::Colorize; -use glob::glob; -use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile}; use regex::{Captures, Regex}; -use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; use tracing::*; use crate::common::{ - expected_output_path, incremental_dir, output_base_dir, output_base_name, - output_testname_unique, Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, - CoverageRun, Crashes, DebugInfo, Debugger, FailMode, Incremental, JsDocTest, MirOpt, PassMode, - Pretty, RunMake, RunPassValgrind, Rustdoc, RustdocJson, TestPaths, Ui, UI_EXTENSIONS, UI_FIXED, - UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, + Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes, + DebugInfo, Debugger, FailMode, Incremental, JsDocTest, MirOpt, PassMode, Pretty, RunMake, + RunPassValgrind, Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, + UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, + incremental_dir, output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; -use crate::read2::{read2_abbreviated, Truncated}; -use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, static_regex, PathBufExt}; -use crate::{extract_gdb_version, is_android_gdb_target, json, ColorConfig}; +use crate::read2::{Truncated, read2_abbreviated}; +use crate::util::{PathBufExt, add_dylib_path, logv, static_regex}; +use crate::{ColorConfig, json}; -mod coverage; mod debugger; -use debugger::DebuggerCommands; + +// Helper modules that implement test running logic for each test suite. +// tidy-alphabet-start +mod assembly; +mod codegen; +mod codegen_units; +mod coverage; +mod crash; +mod debuginfo; +mod incremental; +mod js_doc; +mod mir_opt; +mod pretty; +mod run_make; +mod rustdoc; +mod rustdoc_json; +mod ui; +mod valgrind; +// tidy-alphabet-end #[cfg(test)] mod tests; @@ -48,7 +62,7 @@ fn disable_error_reporting R, R>(f: F) -> R { use std::sync::Mutex; use windows::Win32::System::Diagnostics::Debug::{ - SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE, + SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE, }; static LOCK: Mutex<()> = Mutex::new(()); @@ -325,81 +339,6 @@ impl<'test> TestCx<'test> { } } - fn run_cfail_test(&self) { - let pm = self.pass_mode(); - let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); - self.check_if_test_should_compile(&proc_res, pm); - self.check_no_compiler_crash(&proc_res, self.props.should_ice); - - let output_to_check = self.get_output(&proc_res); - let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - if !expected_errors.is_empty() { - if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() - { - self.fatal("both error pattern and expected errors specified"); - } - self.check_expected_errors(expected_errors, &proc_res); - } else { - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } - if self.props.should_ice { - match proc_res.status.code() { - Some(101) => (), - _ => self.fatal("expected ICE"), - } - } - - self.check_forbid_output(&output_to_check, &proc_res); - } - - fn run_crash_test(&self) { - let pm = self.pass_mode(); - let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); - - if std::env::var("COMPILETEST_VERBOSE_CRASHES").is_ok() { - eprintln!("{}", proc_res.status); - eprintln!("{}", proc_res.stdout); - eprintln!("{}", proc_res.stderr); - eprintln!("{}", proc_res.cmdline); - } - - // if a test does not crash, consider it an error - if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { - self.fatal(&format!( - "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful name, \ - add a doc-comment to the start of the test explaining why it exists and \ - move it to tests/ui or wherever you see fit. Adding 'Fixes #' to your PR description \ - ensures that the corresponding ticket is auto-closed upon merge." - )); - } - } - - fn run_rfail_test(&self) { - let pm = self.pass_mode(); - let should_run = self.run_if_enabled(); - let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm)); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - if let WillExecute::Disabled = should_run { - return; - } - - let proc_res = self.exec_compiled_test(); - - // The value our Makefile configures valgrind to return on failure - const VALGRIND_ERR: i32 = 100; - if proc_res.status.code() == Some(VALGRIND_ERR) { - self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res); - } - - let output_to_check = self.get_output(&proc_res); - self.check_correct_failure_status(&proc_res); - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } - fn get_output(&self, proc_res: &ProcRes) -> String { if self.props.check_stdout { format!("{}{}", proc_res.stdout, proc_res.stderr) @@ -423,73 +362,6 @@ impl<'test> TestCx<'test> { } } - fn run_cpass_test(&self) { - let emit_metadata = self.should_emit_metadata(self.pass_mode()); - let proc_res = self.compile_test(WillExecute::No, emit_metadata); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - // FIXME(#41968): Move this check to tidy? - if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { - self.fatal("compile-pass tests with expected warnings should be moved to ui/"); - } - } - - fn run_rpass_test(&self) { - let emit_metadata = self.should_emit_metadata(self.pass_mode()); - let should_run = self.run_if_enabled(); - let proc_res = self.compile_test(should_run, emit_metadata); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - // FIXME(#41968): Move this check to tidy? - if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { - self.fatal("run-pass tests with expected warnings should be moved to ui/"); - } - - if let WillExecute::Disabled = should_run { - return; - } - - let proc_res = self.exec_compiled_test(); - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } - - fn run_valgrind_test(&self) { - assert!(self.revision.is_none(), "revisions not relevant here"); - - if self.config.valgrind_path.is_none() { - assert!(!self.config.force_valgrind); - return self.run_rpass_test(); - } - - let should_run = self.run_if_enabled(); - let mut proc_res = self.compile_test(should_run, Emit::None); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - if let WillExecute::Disabled = should_run { - return; - } - - let mut new_config = self.config.clone(); - new_config.runner = new_config.valgrind_path.clone(); - let new_cx = TestCx { config: &new_config, ..*self }; - proc_res = new_cx.exec_compiled_test(); - - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } - /// Runs a [`Command`] and waits for it to finish, then converts its exit /// status and output streams into a [`ProcRes`]. /// @@ -517,104 +389,6 @@ impl<'test> TestCx<'test> { proc_res } - fn run_pretty_test(&self) { - if self.props.pp_exact.is_some() { - logv(self.config, "testing for exact pretty-printing".to_owned()); - } else { - logv(self.config, "testing for converging pretty-printing".to_owned()); - } - - let rounds = match self.props.pp_exact { - Some(_) => 1, - None => 2, - }; - - let src = fs::read_to_string(&self.testpaths.file).unwrap(); - let mut srcs = vec![src]; - - let mut round = 0; - while round < rounds { - logv( - self.config, - format!("pretty-printing round {} revision {:?}", round, self.revision), - ); - let read_from = - if round == 0 { ReadFrom::Path } else { ReadFrom::Stdin(srcs[round].to_owned()) }; - - let proc_res = self.print_source(read_from, &self.props.pretty_mode); - if !proc_res.status.success() { - self.fatal_proc_rec( - &format!( - "pretty-printing failed in round {} revision {:?}", - round, self.revision - ), - &proc_res, - ); - } - - let ProcRes { stdout, .. } = proc_res; - srcs.push(stdout); - round += 1; - } - - let mut expected = match self.props.pp_exact { - Some(ref file) => { - let filepath = self.testpaths.file.parent().unwrap().join(file); - fs::read_to_string(&filepath).unwrap() - } - None => srcs[srcs.len() - 2].clone(), - }; - let mut actual = srcs[srcs.len() - 1].clone(); - - if self.props.pp_exact.is_some() { - // Now we have to care about line endings - let cr = "\r".to_owned(); - actual = actual.replace(&cr, ""); - expected = expected.replace(&cr, ""); - } - - if !self.config.bless { - self.compare_source(&expected, &actual); - } else if expected != actual { - let filepath_buf; - let filepath = match &self.props.pp_exact { - Some(file) => { - filepath_buf = self.testpaths.file.parent().unwrap().join(file); - &filepath_buf - } - None => &self.testpaths.file, - }; - fs::write(filepath, &actual).unwrap(); - } - - // If we're only making sure that the output matches then just stop here - if self.props.pretty_compare_only { - return; - } - - // Finally, let's make sure it actually appears to remain valid code - let proc_res = self.typecheck_source(actual); - if !proc_res.status.success() { - self.fatal_proc_rec("pretty-printed source does not typecheck", &proc_res); - } - - if !self.props.pretty_expanded { - return; - } - - // additionally, run `-Zunpretty=expanded` and try to build it. - let proc_res = self.print_source(ReadFrom::Path, "expanded"); - if !proc_res.status.success() { - self.fatal_proc_rec("pretty-printing (expanded) failed", &proc_res); - } - - let ProcRes { stdout: expanded_src, .. } = proc_res; - let proc_res = self.typecheck_source(expanded_src); - if !proc_res.status.success() { - self.fatal_proc_rec("pretty-printed source (expanded) does not typecheck", &proc_res); - } - } - fn print_source(&self, read_from: ReadFrom, pretty_type: &str) -> ProcRes { let aux_dir = self.aux_output_dir_name(); let input: &str = match read_from { @@ -727,624 +501,130 @@ impl<'test> TestCx<'test> { self.compose_and_run_compiler(rustc, Some(src), self.testpaths) } - fn run_debuginfo_test(&self) { - match self.config.debugger.unwrap() { - Debugger::Cdb => self.run_debuginfo_cdb_test(), - Debugger::Gdb => self.run_debuginfo_gdb_test(), - Debugger::Lldb => self.run_debuginfo_lldb_test(), - } - } - - fn run_debuginfo_cdb_test(&self) { - let config = Config { - target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), - host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), - ..self.config.clone() - }; + fn maybe_add_external_args(&self, cmd: &mut Command, args: &Vec) { + // Filter out the arguments that should not be added by runtest here. + // + // Notable use-cases are: do not add our optimisation flag if + // `compile-flags: -Copt-level=x` and similar for debug-info level as well. + const OPT_FLAGS: &[&str] = &["-O", "-Copt-level=", /*-C*/ "opt-level="]; + const DEBUG_FLAGS: &[&str] = &["-g", "-Cdebuginfo=", /*-C*/ "debuginfo="]; - let test_cx = TestCx { config: &config, ..*self }; + // FIXME: ideally we would "just" check the `cmd` itself, but it does not allow inspecting + // its arguments. They need to be collected separately. For now I cannot be bothered to + // implement this the "right" way. + let have_opt_flag = + self.props.compile_flags.iter().any(|arg| OPT_FLAGS.iter().any(|f| arg.starts_with(f))); + let have_debug_flag = self + .props + .compile_flags + .iter() + .any(|arg| DEBUG_FLAGS.iter().any(|f| arg.starts_with(f))); - test_cx.run_debuginfo_cdb_test_no_opt(); + for arg in args { + if OPT_FLAGS.iter().any(|f| arg.starts_with(f)) && have_opt_flag { + continue; + } + if DEBUG_FLAGS.iter().any(|f| arg.starts_with(f)) && have_debug_flag { + continue; + } + cmd.arg(arg); + } } - fn run_debuginfo_cdb_test_no_opt(&self) { - let exe_file = self.make_exe_name(); - - // Existing PDB files are update in-place. When changing the debuginfo - // the compiler generates for something, this can lead to the situation - // where both the old and the new version of the debuginfo for the same - // type is present in the PDB, which is very confusing. - // Therefore we delete any existing PDB file before compiling the test - // case. - // FIXME: If can reliably detect that MSVC's link.exe is used, then - // passing `/INCREMENTAL:NO` might be a cleaner way to do this. - let pdb_file = exe_file.with_extension(".pdb"); - if pdb_file.exists() { - std::fs::remove_file(pdb_file).unwrap(); + fn check_all_error_patterns( + &self, + output_to_check: &str, + proc_res: &ProcRes, + pm: Option, + ) { + if self.props.error_patterns.is_empty() && self.props.regex_error_patterns.is_empty() { + if pm.is_some() { + // FIXME(#65865) + return; + } else { + self.fatal(&format!( + "no error pattern specified in {:?}", + self.testpaths.file.display() + )); + } } - // 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, Emit::None); - if !compile_result.status.success() { - self.fatal_proc_rec("compilation failed!", &compile_result); - } - if let WillExecute::Disabled = should_run { - return; - } + let mut missing_patterns: Vec = Vec::new(); - let prefixes = { - static PREFIXES: &[&str] = &["cdb", "cdbg"]; - // No "native rust support" variation for CDB yet. - PREFIXES - }; + self.check_error_patterns(output_to_check, &mut missing_patterns); + self.check_regex_error_patterns(output_to_check, proc_res, &mut missing_patterns); - // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); - - // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands - let mut script_str = String::with_capacity(2048); - script_str.push_str("version\n"); // List CDB (and more) version info in test output - script_str.push_str(".nvlist\n"); // List loaded `*.natvis` files, bulk of custom MSVC debug - - // If a .js file exists next to the source file being tested, then this is a JavaScript - // debugging extension that needs to be loaded. - let mut js_extension = self.testpaths.file.clone(); - js_extension.set_extension("cdb.js"); - if js_extension.exists() { - script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension.to_string_lossy())); + if missing_patterns.is_empty() { + return; } - // Set breakpoints on every line that contains the string "#break" - let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); - for line in &dbg_cmds.breakpoint_lines { - script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line)); + if missing_patterns.len() == 1 { + self.fatal_proc_rec( + &format!("error pattern '{}' not found!", missing_patterns[0]), + proc_res, + ); + } else { + for pattern in missing_patterns { + self.error(&format!("error pattern '{}' not found!", pattern)); + } + self.fatal_proc_rec("multiple error patterns not found", proc_res); } + } - // Append the other `cdb-command:`s - for line in &dbg_cmds.commands { - script_str.push_str(line); - script_str.push('\n'); + fn check_error_patterns(&self, output_to_check: &str, missing_patterns: &mut Vec) { + debug!("check_error_patterns"); + for pattern in &self.props.error_patterns { + if output_to_check.contains(pattern.trim()) { + debug!("found error pattern {}", pattern); + } else { + missing_patterns.push(pattern.to_string()); + } } + } - script_str.push_str("qq\n"); // Quit the debugger (including remote debugger, if any) - - // Write the script into a file - debug!("script_str = {}", script_str); - self.dump_output_file(&script_str, "debugger.script"); - let debugger_script = self.make_out_name("debugger.script"); - - let cdb_path = &self.config.cdb.as_ref().unwrap(); - let mut cdb = Command::new(cdb_path); - cdb.arg("-lines") // Enable source line debugging. - .arg("-cf") - .arg(&debugger_script) - .arg(&exe_file); - - let debugger_run_result = self.compose_and_run( - cdb, - self.config.run_lib_path.to_str().unwrap(), - None, // aux_path - None, // input - ); + fn check_regex_error_patterns( + &self, + output_to_check: &str, + proc_res: &ProcRes, + missing_patterns: &mut Vec, + ) { + debug!("check_regex_error_patterns"); - if !debugger_run_result.status.success() { - self.fatal_proc_rec("Error while running CDB", &debugger_run_result); + for pattern in &self.props.regex_error_patterns { + let pattern = pattern.trim(); + let re = match Regex::new(pattern) { + Ok(re) => re, + Err(err) => { + self.fatal_proc_rec( + &format!("invalid regex error pattern '{}': {:?}", pattern, err), + proc_res, + ); + } + }; + if re.is_match(output_to_check) { + debug!("found regex error pattern {}", pattern); + } else { + missing_patterns.push(pattern.to_string()); + } } + } - if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { - self.fatal_proc_rec(&e, &debugger_run_result); + fn check_no_compiler_crash(&self, proc_res: &ProcRes, should_ice: bool) { + match proc_res.status.code() { + Some(101) if !should_ice => { + self.fatal_proc_rec("compiler encountered internal error", proc_res) + } + None => self.fatal_proc_rec("compiler terminated by signal", proc_res), + _ => (), } } - fn run_debuginfo_gdb_test(&self) { - let config = Config { - target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), - host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), - ..self.config.clone() - }; - - let test_cx = TestCx { config: &config, ..*self }; - - test_cx.run_debuginfo_gdb_test_no_opt(); - } - - fn run_debuginfo_gdb_test_no_opt(&self) { - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - &["gdb"], - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); - let mut cmds = dbg_cmds.commands.join("\n"); - - // 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, Emit::None); - if !compiler_run_result.status.success() { - self.fatal_proc_rec("compilation failed!", &compiler_run_result); - } - if let WillExecute::Disabled = should_run { - return; - } - - let exe_file = self.make_exe_name(); - - let debugger_run_result; - if is_android_gdb_target(&self.config.target) { - cmds = cmds.replace("run", "continue"); - - let tool_path = match self.config.android_cross_path.to_str() { - Some(x) => x.to_owned(), - None => self.fatal("cannot find android cross path"), - }; - - // write debugger script - let mut script_str = String::with_capacity(2048); - script_str.push_str(&format!("set charset {}\n", Self::charset())); - script_str.push_str(&format!("set sysroot {}\n", tool_path)); - script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap())); - script_str.push_str("target remote :5039\n"); - script_str.push_str(&format!( - "set solib-search-path \ - ./{}/stage2/lib/rustlib/{}/lib/\n", - self.config.host, self.config.target - )); - for line in &dbg_cmds.breakpoint_lines { - script_str.push_str( - format!( - "break {:?}:{}\n", - self.testpaths.file.file_name().unwrap().to_string_lossy(), - *line - ) - .as_str(), - ); - } - script_str.push_str(&cmds); - script_str.push_str("\nquit\n"); - - debug!("script_str = {}", script_str); - self.dump_output_file(&script_str, "debugger.script"); - - let adb_path = &self.config.adb_path; - - Command::new(adb_path) - .arg("push") - .arg(&exe_file) - .arg(&self.config.adb_test_dir) - .status() - .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}")); - - Command::new(adb_path) - .args(&["forward", "tcp:5039", "tcp:5039"]) - .status() - .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}")); - - let adb_arg = format!( - "export LD_LIBRARY_PATH={}; \ - gdbserver{} :5039 {}/{}", - self.config.adb_test_dir.clone(), - if self.config.target.contains("aarch64") { "64" } else { "" }, - self.config.adb_test_dir.clone(), - exe_file.file_name().unwrap().to_str().unwrap() - ); - - debug!("adb arg: {}", adb_arg); - let mut adb = Command::new(adb_path) - .args(&["shell", &adb_arg]) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .spawn() - .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}")); - - // Wait for the gdbserver to print out "Listening on port ..." - // at which point we know that it's started and then we can - // execute the debugger below. - let mut stdout = BufReader::new(adb.stdout.take().unwrap()); - let mut line = String::new(); - loop { - line.truncate(0); - stdout.read_line(&mut line).unwrap(); - if line.starts_with("Listening on port 5039") { - break; - } - } - drop(stdout); - - let mut debugger_script = OsString::from("-command="); - debugger_script.push(self.make_out_name("debugger.script")); - let debugger_opts: &[&OsStr] = - &["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script]; - - let gdb_path = self.config.gdb.as_ref().unwrap(); - let Output { status, stdout, stderr } = Command::new(&gdb_path) - .args(debugger_opts) - .output() - .unwrap_or_else(|e| panic!("failed to exec `{gdb_path:?}`: {e:?}")); - let cmdline = { - let mut gdb = Command::new(&format!("{}-gdb", self.config.target)); - gdb.args(debugger_opts); - let cmdline = self.make_cmdline(&gdb, ""); - logv(self.config, format!("executing {}", cmdline)); - cmdline - }; - - debugger_run_result = ProcRes { - status, - stdout: String::from_utf8(stdout).unwrap(), - stderr: String::from_utf8(stderr).unwrap(), - truncated: Truncated::No, - cmdline, - }; - if adb.kill().is_err() { - println!("Adb process is already finished."); - } - } else { - let rust_src_root = - self.config.find_rust_src_root().expect("Could not find Rust source root"); - let rust_pp_module_rel_path = Path::new("./src/etc"); - let rust_pp_module_abs_path = - rust_src_root.join(rust_pp_module_rel_path).to_str().unwrap().to_owned(); - // write debugger script - let mut script_str = String::with_capacity(2048); - script_str.push_str(&format!("set charset {}\n", Self::charset())); - script_str.push_str("show version\n"); - - match self.config.gdb_version { - Some(version) => { - println!("NOTE: compiletest thinks it is using GDB version {}", version); - - if version > extract_gdb_version("7.4").unwrap() { - // Add the directory containing the pretty printers to - // GDB's script auto loading safe path - script_str.push_str(&format!( - "add-auto-load-safe-path {}\n", - rust_pp_module_abs_path.replace(r"\", r"\\") - )); - - let output_base_dir = self.output_base_dir().to_str().unwrap().to_owned(); - - // Add the directory containing the output binary to - // include embedded pretty printers to GDB's script - // auto loading safe path - script_str.push_str(&format!( - "add-auto-load-safe-path {}\n", - output_base_dir.replace(r"\", r"\\") - )); - } - } - _ => { - println!( - "NOTE: compiletest does not know which version of \ - GDB it is using" - ); - } - } - - // The following line actually doesn't have to do anything with - // pretty printing, it just tells GDB to print values on one line: - script_str.push_str("set print pretty off\n"); - - // Add the pretty printer directory to GDB's source-file search path - script_str - .push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\"))); - - // Load the target executable - script_str - .push_str(&format!("file {}\n", exe_file.to_str().unwrap().replace(r"\", r"\\"))); - - // Force GDB to print values in the Rust format. - script_str.push_str("set language rust\n"); - - // Add line breakpoints - for line in &dbg_cmds.breakpoint_lines { - script_str.push_str(&format!( - "break '{}':{}\n", - self.testpaths.file.file_name().unwrap().to_string_lossy(), - *line - )); - } - - script_str.push_str(&cmds); - script_str.push_str("\nquit\n"); - - debug!("script_str = {}", script_str); - self.dump_output_file(&script_str, "debugger.script"); - - let mut debugger_script = OsString::from("-command="); - debugger_script.push(self.make_out_name("debugger.script")); - - let debugger_opts: &[&OsStr] = - &["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script]; - - let mut gdb = Command::new(self.config.gdb.as_ref().unwrap()); - let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { - format!("{pp}:{rust_pp_module_abs_path}") - } else { - rust_pp_module_abs_path - }; - gdb.args(debugger_opts).env("PYTHONPATH", pythonpath); - - debugger_run_result = - self.compose_and_run(gdb, self.config.run_lib_path.to_str().unwrap(), None, None); - } - - if !debugger_run_result.status.success() { - self.fatal_proc_rec("gdb failed to execute", &debugger_run_result); - } - - if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { - self.fatal_proc_rec(&e, &debugger_run_result); - } - } - - fn run_debuginfo_lldb_test(&self) { - if self.config.lldb_python_dir.is_none() { - self.fatal("Can't run LLDB test because LLDB's python path is not set."); - } - - let config = Config { - target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), - host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), - ..self.config.clone() - }; - - let test_cx = TestCx { config: &config, ..*self }; - - test_cx.run_debuginfo_lldb_test_no_opt(); - } - - 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, Emit::None); - if !compile_result.status.success() { - self.fatal_proc_rec("compilation failed!", &compile_result); - } - if let WillExecute::Disabled = should_run { - return; - } - - let exe_file = self.make_exe_name(); - - match self.config.lldb_version { - Some(ref version) => { - println!("NOTE: compiletest thinks it is using LLDB version {}", version); - } - _ => { - println!( - "NOTE: compiletest does not know which version of \ - LLDB it is using" - ); - } - } - - // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - &["lldb"], - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); - - // Write debugger script: - // We don't want to hang when calling `quit` while the process is still running - let mut script_str = String::from("settings set auto-confirm true\n"); - - // Make LLDB emit its version, so we have it documented in the test output - script_str.push_str("version\n"); - - // Switch LLDB into "Rust mode" - let rust_src_root = - self.config.find_rust_src_root().expect("Could not find Rust source root"); - let rust_pp_module_rel_path = Path::new("./src/etc"); - let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path); - - script_str.push_str(&format!( - "command script import {}/lldb_lookup.py\n", - rust_pp_module_abs_path.to_str().unwrap() - )); - File::open(rust_pp_module_abs_path.join("lldb_commands")) - .and_then(|mut file| file.read_to_string(&mut script_str)) - .expect("Failed to read lldb_commands"); - - // Set breakpoints on every line that contains the string "#break" - let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); - for line in &dbg_cmds.breakpoint_lines { - script_str.push_str(&format!( - "breakpoint set --file '{}' --line {}\n", - source_file_name, line - )); - } - - // Append the other commands - for line in &dbg_cmds.commands { - script_str.push_str(line); - script_str.push('\n'); - } - - // Finally, quit the debugger - script_str.push_str("\nquit\n"); - - // Write the script into a file - debug!("script_str = {}", script_str); - self.dump_output_file(&script_str, "debugger.script"); - let debugger_script = self.make_out_name("debugger.script"); - - // Let LLDB execute the script via lldb_batchmode.py - let debugger_run_result = self.run_lldb(&exe_file, &debugger_script, &rust_src_root); - - if !debugger_run_result.status.success() { - self.fatal_proc_rec("Error while running LLDB", &debugger_run_result); - } - - if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { - self.fatal_proc_rec(&e, &debugger_run_result); - } - } - - fn run_lldb( - &self, - test_executable: &Path, - debugger_script: &Path, - rust_src_root: &Path, - ) -> ProcRes { - // Prepare the lldb_batchmode which executes the debugger script - let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py"); - let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { - format!("{pp}:{}", self.config.lldb_python_dir.as_ref().unwrap()) - } else { - self.config.lldb_python_dir.as_ref().unwrap().to_string() - }; - self.run_command_to_procres( - Command::new(&self.config.python) - .arg(&lldb_script_path) - .arg(test_executable) - .arg(debugger_script) - .env("PYTHONUNBUFFERED", "1") // Help debugging #78665 - .env("PYTHONPATH", pythonpath), - ) - } - - fn cleanup_debug_info_options(&self, options: &Vec) -> Vec { - // 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()]; - - options.iter().filter(|x| !options_to_remove.contains(x)).cloned().collect() - } - - fn maybe_add_external_args(&self, cmd: &mut Command, args: &Vec) { - // Filter out the arguments that should not be added by runtest here. - // - // Notable use-cases are: do not add our optimisation flag if - // `compile-flags: -Copt-level=x` and similar for debug-info level as well. - const OPT_FLAGS: &[&str] = &["-O", "-Copt-level=", /*-C*/ "opt-level="]; - const DEBUG_FLAGS: &[&str] = &["-g", "-Cdebuginfo=", /*-C*/ "debuginfo="]; - - // FIXME: ideally we would "just" check the `cmd` itself, but it does not allow inspecting - // its arguments. They need to be collected separately. For now I cannot be bothered to - // implement this the "right" way. - let have_opt_flag = - self.props.compile_flags.iter().any(|arg| OPT_FLAGS.iter().any(|f| arg.starts_with(f))); - let have_debug_flag = self - .props - .compile_flags - .iter() - .any(|arg| DEBUG_FLAGS.iter().any(|f| arg.starts_with(f))); - - for arg in args { - if OPT_FLAGS.iter().any(|f| arg.starts_with(f)) && have_opt_flag { - continue; - } - if DEBUG_FLAGS.iter().any(|f| arg.starts_with(f)) && have_debug_flag { - continue; - } - cmd.arg(arg); - } - } - - fn check_all_error_patterns( - &self, - output_to_check: &str, - proc_res: &ProcRes, - pm: Option, - ) { - if self.props.error_patterns.is_empty() && self.props.regex_error_patterns.is_empty() { - if pm.is_some() { - // FIXME(#65865) - return; - } else { - self.fatal(&format!( - "no error pattern specified in {:?}", - self.testpaths.file.display() - )); - } - } - - let mut missing_patterns: Vec = Vec::new(); - - self.check_error_patterns(output_to_check, &mut missing_patterns); - self.check_regex_error_patterns(output_to_check, proc_res, &mut missing_patterns); - - if missing_patterns.is_empty() { - return; - } - - if missing_patterns.len() == 1 { - self.fatal_proc_rec( - &format!("error pattern '{}' not found!", missing_patterns[0]), - proc_res, - ); - } else { - for pattern in missing_patterns { - self.error(&format!("error pattern '{}' not found!", pattern)); - } - self.fatal_proc_rec("multiple error patterns not found", proc_res); - } - } - - fn check_error_patterns(&self, output_to_check: &str, missing_patterns: &mut Vec) { - debug!("check_error_patterns"); - for pattern in &self.props.error_patterns { - if output_to_check.contains(pattern.trim()) { - debug!("found error pattern {}", pattern); - } else { - missing_patterns.push(pattern.to_string()); - } - } - } - - fn check_regex_error_patterns( - &self, - output_to_check: &str, - proc_res: &ProcRes, - missing_patterns: &mut Vec, - ) { - debug!("check_regex_error_patterns"); - - for pattern in &self.props.regex_error_patterns { - let pattern = pattern.trim(); - let re = match Regex::new(pattern) { - Ok(re) => re, - Err(err) => { - self.fatal_proc_rec( - &format!("invalid regex error pattern '{}': {:?}", pattern, err), - proc_res, - ); - } - }; - if re.is_match(output_to_check) { - debug!("found regex error pattern {}", pattern); - } else { - missing_patterns.push(pattern.to_string()); - } - } - } - - fn check_no_compiler_crash(&self, proc_res: &ProcRes, should_ice: bool) { - match proc_res.status.code() { - Some(101) if !should_ice => { - self.fatal_proc_rec("compiler encountered internal error", proc_res) - } - None => self.fatal_proc_rec("compiler terminated by signal", proc_res), - _ => (), - } - } - - fn check_forbid_output(&self, output_to_check: &str, proc_res: &ProcRes) { - for pat in &self.props.forbid_output { - if output_to_check.contains(pat) { - self.fatal_proc_rec("forbidden pattern found in compiler output", proc_res); - } - } + fn check_forbid_output(&self, output_to_check: &str, proc_res: &ProcRes) { + for pat in &self.props.forbid_output { + if output_to_check.contains(pat) { + self.fatal_proc_rec("forbidden pattern found in compiler output", proc_res); + } + } } fn check_expected_errors(&self, expected_errors: Vec, proc_res: &ProcRes) { @@ -2016,6 +1296,14 @@ impl<'test> TestCx<'test> { || self.config.src_base.ends_with("rustdoc-json") } + fn get_mir_dump_dir(&self) -> PathBuf { + let mut mir_dump_dir = PathBuf::from(self.config.build_base.as_path()); + debug!("input_file: {:?}", self.testpaths.file); + mir_dump_dir.push(&self.testpaths.relative_dir); + mir_dump_dir.push(self.testpaths.file.file_stem().unwrap()); + mir_dump_dir + } + fn make_compile_args( &self, input_file: &Path, @@ -2626,77 +1914,13 @@ impl<'test> TestCx<'test> { self.compose_and_run(filecheck, "", None, None) } - fn run_codegen_test(&self) { - if self.config.llvm_filecheck.is_none() { - self.fatal("missing --llvm-filecheck"); - } - - let (proc_res, output_path) = self.compile_test_and_save_ir(); - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } + fn charset() -> &'static str { + // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset + if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" } + } - if let Some(PassMode::Build) = self.pass_mode() { - return; - } - let proc_res = self.verify_with_filecheck(&output_path); - if !proc_res.status.success() { - self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); - } - } - - fn run_assembly_test(&self) { - if self.config.llvm_filecheck.is_none() { - self.fatal("missing --llvm-filecheck"); - } - - let (proc_res, output_path) = self.compile_test_and_save_assembly(); - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - let proc_res = self.verify_with_filecheck(&output_path); - if !proc_res.status.success() { - self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); - } - } - - fn charset() -> &'static str { - // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset - if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" } - } - - fn run_rustdoc_test(&self) { - assert!(self.revision.is_none(), "revisions not relevant here"); - - let out_dir = self.output_base_dir(); - remove_and_create_dir_all(&out_dir); - - let proc_res = self.document(&out_dir, &self.testpaths); - if !proc_res.status.success() { - self.fatal_proc_rec("rustdoc failed!", &proc_res); - } - - if self.props.check_test_line_numbers_match { - self.check_rustdoc_test_option(proc_res); - } else { - let root = self.config.find_rust_src_root().unwrap(); - let mut cmd = Command::new(&self.config.python); - cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file); - if self.config.bless { - cmd.arg("--bless"); - } - let res = self.run_command_to_procres(&mut cmd); - if !res.status.success() { - self.fatal_proc_rec_with_ctx("htmldocck failed!", &res, |mut this| { - this.compare_to_default_rustdoc(&out_dir) - }); - } - } - } - - fn compare_to_default_rustdoc(&mut self, out_dir: &Path) { - if !self.config.has_tidy { + fn compare_to_default_rustdoc(&mut self, out_dir: &Path) { + if !self.config.has_tidy { return; } println!("info: generating a diff against nightly rustdoc"); @@ -2739,7 +1963,7 @@ impl<'test> TestCx<'test> { #[rustfmt::skip] let tidy_args = [ - "--new-blocklevel-tags", "rustdoc-search", + "--new-blocklevel-tags", "rustdoc-search,rustdoc-toolbar", "--indent", "yes", "--indent-spaces", "2", "--wrap", "0", @@ -2847,49 +2071,6 @@ impl<'test> TestCx<'test> { }; } - fn run_rustdoc_json_test(&self) { - //FIXME: Add bless option. - - assert!(self.revision.is_none(), "revisions not relevant here"); - - let out_dir = self.output_base_dir(); - remove_and_create_dir_all(&out_dir); - - let proc_res = self.document(&out_dir, &self.testpaths); - if !proc_res.status.success() { - self.fatal_proc_rec("rustdoc failed!", &proc_res); - } - - let root = self.config.find_rust_src_root().unwrap(); - let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); - json_out.set_extension("json"); - let res = self.run_command_to_procres( - Command::new(self.config.jsondocck_path.as_ref().unwrap()) - .arg("--doc-dir") - .arg(root.join(&out_dir)) - .arg("--template") - .arg(&self.testpaths.file), - ); - - if !res.status.success() { - self.fatal_proc_rec_with_ctx("jsondocck failed!", &res, |_| { - println!("Rustdoc Output:"); - proc_res.print_info(); - }) - } - - let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); - json_out.set_extension("json"); - - let res = self.run_command_to_procres( - Command::new(self.config.jsondoclint_path.as_ref().unwrap()).arg(&json_out), - ); - - if !res.status.success() { - self.fatal_proc_rec("jsondoclint failed!", &res); - } - } - fn get_lines>( &self, path: &P, @@ -2990,824 +2171,6 @@ impl<'test> TestCx<'test> { } } - fn run_codegen_units_test(&self) { - assert!(self.revision.is_none(), "revisions not relevant here"); - - let proc_res = self.compile_test(WillExecute::No, Emit::None); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - self.check_no_compiler_crash(&proc_res, self.props.should_ice); - - const PREFIX: &str = "MONO_ITEM "; - const CGU_MARKER: &str = "@@"; - - // Some MonoItems can contain {closure@/path/to/checkout/tests/codgen-units/test.rs} - // To prevent the current dir from leaking, we just replace the entire path to the test - // file with TEST_PATH. - let actual: Vec = proc_res - .stdout - .lines() - .filter(|line| line.starts_with(PREFIX)) - .map(|line| { - line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string() - }) - .map(|line| str_to_mono_item(&line, true)) - .collect(); - - let expected: Vec = errors::load_errors(&self.testpaths.file, None) - .iter() - .map(|e| str_to_mono_item(&e.msg[..], false)) - .collect(); - - let mut missing = Vec::new(); - let mut wrong_cgus = Vec::new(); - - for expected_item in &expected { - let actual_item_with_same_name = actual.iter().find(|ti| ti.name == expected_item.name); - - if let Some(actual_item) = actual_item_with_same_name { - if !expected_item.codegen_units.is_empty() && - // Also check for codegen units - expected_item.codegen_units != actual_item.codegen_units - { - wrong_cgus.push((expected_item.clone(), actual_item.clone())); - } - } else { - missing.push(expected_item.string.clone()); - } - } - - let unexpected: Vec<_> = actual - .iter() - .filter(|acgu| !expected.iter().any(|ecgu| acgu.name == ecgu.name)) - .map(|acgu| acgu.string.clone()) - .collect(); - - if !missing.is_empty() { - missing.sort(); - - println!("\nThese items should have been contained but were not:\n"); - - for item in &missing { - println!("{}", item); - } - - println!("\n"); - } - - if !unexpected.is_empty() { - let sorted = { - let mut sorted = unexpected.clone(); - sorted.sort(); - sorted - }; - - println!("\nThese items were contained but should not have been:\n"); - - for item in sorted { - println!("{}", item); - } - - println!("\n"); - } - - if !wrong_cgus.is_empty() { - wrong_cgus.sort_by_key(|pair| pair.0.name.clone()); - println!("\nThe following items were assigned to wrong codegen units:\n"); - - for &(ref expected_item, ref actual_item) in &wrong_cgus { - println!("{}", expected_item.name); - println!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units)); - println!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units)); - println!(); - } - } - - if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty()) { - panic!(); - } - - #[derive(Clone, Eq, PartialEq)] - struct MonoItem { - name: String, - codegen_units: HashSet, - string: String, - } - - // [MONO_ITEM] name [@@ (cgu)+] - fn str_to_mono_item(s: &str, cgu_has_crate_disambiguator: bool) -> MonoItem { - let s = if s.starts_with(PREFIX) { (&s[PREFIX.len()..]).trim() } else { s.trim() }; - - let full_string = format!("{}{}", PREFIX, s); - - let parts: Vec<&str> = - s.split(CGU_MARKER).map(str::trim).filter(|s| !s.is_empty()).collect(); - - let name = parts[0].trim(); - - let cgus = if parts.len() > 1 { - let cgus_str = parts[1]; - - cgus_str - .split(' ') - .map(str::trim) - .filter(|s| !s.is_empty()) - .map(|s| { - if cgu_has_crate_disambiguator { - remove_crate_disambiguators_from_set_of_cgu_names(s) - } else { - s.to_string() - } - }) - .collect() - } else { - HashSet::new() - }; - - MonoItem { name: name.to_owned(), codegen_units: cgus, string: full_string } - } - - fn codegen_units_to_str(cgus: &HashSet) -> String { - let mut cgus: Vec<_> = cgus.iter().collect(); - cgus.sort(); - - let mut string = String::new(); - for cgu in cgus { - string.push_str(&cgu[..]); - string.push(' '); - } - - string - } - - // Given a cgu-name-prefix of the form . or - // the form .-in-., - // remove all crate-disambiguators. - fn remove_crate_disambiguator_from_cgu(cgu: &str) -> String { - let Some(captures) = - static_regex!(r"^[^\.]+(?P\.[[:alnum:]]+)(-in-[^\.]+(?P\.[[:alnum:]]+))?") - .captures(cgu) - else { - panic!("invalid cgu name encountered: {cgu}"); - }; - - let mut new_name = cgu.to_owned(); - - if let Some(d2) = captures.name("d2") { - new_name.replace_range(d2.start()..d2.end(), ""); - } - - let d1 = captures.name("d1").unwrap(); - new_name.replace_range(d1.start()..d1.end(), ""); - - new_name - } - - // The name of merged CGUs is constructed as the names of the original - // CGUs joined with "--". This function splits such composite CGU names - // and handles each component individually. - fn remove_crate_disambiguators_from_set_of_cgu_names(cgus: &str) -> String { - cgus.split("--").map(remove_crate_disambiguator_from_cgu).collect::>().join("--") - } - } - - fn init_incremental_test(&self) { - // (See `run_incremental_test` for an overview of how incremental tests work.) - - // Before any of the revisions have executed, create the - // incremental workproduct directory. Delete any old - // incremental work products that may be there from prior - // runs. - let incremental_dir = self.props.incremental_dir.as_ref().unwrap(); - if incremental_dir.exists() { - // Canonicalizing the path will convert it to the //?/ format - // on Windows, which enables paths longer than 260 character - let canonicalized = incremental_dir.canonicalize().unwrap(); - fs::remove_dir_all(canonicalized).unwrap(); - } - fs::create_dir_all(&incremental_dir).unwrap(); - - if self.config.verbose { - println!("init_incremental_test: incremental_dir={}", incremental_dir.display()); - } - } - - fn run_incremental_test(&self) { - // Basic plan for a test incremental/foo/bar.rs: - // - load list of revisions rpass1, cfail2, rpass3 - // - each should begin with `cpass`, `rpass`, `cfail`, or `rfail` - // - if `cpass`, expect compilation to succeed, don't execute - // - if `rpass`, expect compilation and execution to succeed - // - if `cfail`, expect compilation to fail - // - if `rfail`, expect compilation to succeed and execution to fail - // - create a directory build/foo/bar.incremental - // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1 - // - because name of revision starts with "rpass", expect success - // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C cfail2 - // - because name of revision starts with "cfail", expect an error - // - load expected errors as usual, but filter for those that end in `[rfail2]` - // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass3 - // - because name of revision starts with "rpass", expect success - // - execute build/foo/bar.exe and save output - // - // FIXME -- use non-incremental mode as an oracle? That doesn't apply - // to #[rustc_dirty] and clean tests I guess - - let revision = self.revision.expect("incremental tests require a list of revisions"); - - // Incremental workproduct directory should have already been created. - let incremental_dir = self.props.incremental_dir.as_ref().unwrap(); - assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir"); - - if self.config.verbose { - print!("revision={:?} props={:#?}", revision, self.props); - } - - if revision.starts_with("cpass") { - if self.props.should_ice { - self.fatal("can only use should-ice in cfail tests"); - } - self.run_cpass_test(); - } else if revision.starts_with("rpass") { - if self.props.should_ice { - self.fatal("can only use should-ice in cfail tests"); - } - self.run_rpass_test(); - } else if revision.starts_with("rfail") { - if self.props.should_ice { - self.fatal("can only use should-ice in cfail tests"); - } - self.run_rfail_test(); - } else if revision.starts_with("cfail") { - self.run_cfail_test(); - } else { - self.fatal("revision name must begin with cpass, rpass, rfail, or cfail"); - } - } - - fn run_rmake_test(&self) { - let test_dir = &self.testpaths.file; - if test_dir.join("rmake.rs").exists() { - self.run_rmake_v2_test(); - } else if test_dir.join("Makefile").exists() { - self.run_rmake_legacy_test(); - } else { - self.fatal("failed to find either `rmake.rs` or `Makefile`") - } - } - - fn run_rmake_legacy_test(&self) { - let cwd = env::current_dir().unwrap(); - let src_root = self.config.src_base.parent().unwrap().parent().unwrap(); - let src_root = cwd.join(&src_root); - - let tmpdir = cwd.join(self.output_base_name()); - if tmpdir.exists() { - self.aggressive_rm_rf(&tmpdir).unwrap(); - } - create_dir_all(&tmpdir).unwrap(); - - let host = &self.config.host; - let make = if host.contains("dragonfly") - || host.contains("freebsd") - || host.contains("netbsd") - || host.contains("openbsd") - || host.contains("aix") - { - "gmake" - } else { - "make" - }; - - let mut cmd = Command::new(make); - cmd.current_dir(&self.testpaths.file) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .env("TARGET", &self.config.target) - .env("PYTHON", &self.config.python) - .env("S", src_root) - .env("RUST_BUILD_STAGE", &self.config.stage_id) - .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("TMPDIR", &tmpdir) - .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) - .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) - .env("LLVM_COMPONENTS", &self.config.llvm_components) - // We for sure don't want these tests to run in parallel, so make - // sure they don't have access to these vars if we run via `make` - // at the top level - .env_remove("MAKEFLAGS") - .env_remove("MFLAGS") - .env_remove("CARGO_MAKEFLAGS"); - - if let Some(ref rustdoc) = self.config.rustdoc_path { - cmd.env("RUSTDOC", cwd.join(rustdoc)); - } - - if let Some(ref node) = self.config.nodejs { - cmd.env("NODE", node); - } - - if let Some(ref linker) = self.config.target_linker { - cmd.env("RUSTC_LINKER", linker); - } - - if let Some(ref clang) = self.config.run_clang_based_tests_with { - cmd.env("CLANG", clang); - } - - if let Some(ref filecheck) = self.config.llvm_filecheck { - cmd.env("LLVM_FILECHECK", filecheck); - } - - if let Some(ref llvm_bin_dir) = self.config.llvm_bin_dir { - cmd.env("LLVM_BIN_DIR", llvm_bin_dir); - } - - if let Some(ref remote_test_client) = self.config.remote_test_client { - cmd.env("REMOTE_TEST_CLIENT", remote_test_client); - } - - // We don't want RUSTFLAGS set from the outside to interfere with - // compiler flags set in the test cases: - cmd.env_remove("RUSTFLAGS"); - - // Use dynamic musl for tests because static doesn't allow creating dylibs - if self.config.host.contains("musl") { - cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1"); - } - - if self.config.bless { - cmd.env("RUSTC_BLESS_TEST", "--bless"); - // Assume this option is active if the environment variable is "defined", with _any_ value. - // As an example, a `Makefile` can use this option by: - // - // ifdef RUSTC_BLESS_TEST - // cp "$(TMPDIR)"/actual_something.ext expected_something.ext - // else - // $(DIFF) expected_something.ext "$(TMPDIR)"/actual_something.ext - // endif - } - - if self.config.target.contains("msvc") && !self.config.cc.is_empty() { - // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` - // and that `lib.exe` lives next to it. - let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); - - // MSYS doesn't like passing flags of the form `/foo` as it thinks it's - // a path and instead passes `C:\msys64\foo`, so convert all - // `/`-arguments to MSVC here to `-` arguments. - let cflags = self - .config - .cflags - .split(' ') - .map(|s| s.replace("/", "-")) - .collect::>() - .join(" "); - let cxxflags = self - .config - .cxxflags - .split(' ') - .map(|s| s.replace("/", "-")) - .collect::>() - .join(" "); - - cmd.env("IS_MSVC", "1") - .env("IS_WINDOWS", "1") - .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) - .env("MSVC_LIB_PATH", format!("{}", lib.display())) - .env("CC", format!("'{}' {}", self.config.cc, cflags)) - .env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags)); - } else { - cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) - .env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags)) - .env("AR", &self.config.ar); - - if self.config.target.contains("windows") { - cmd.env("IS_WINDOWS", "1"); - } - } - - let (output, truncated) = - self.read2_abbreviated(cmd.spawn().expect("failed to spawn `make`")); - if !output.status.success() { - let res = ProcRes { - status: output.status, - stdout: String::from_utf8_lossy(&output.stdout).into_owned(), - stderr: String::from_utf8_lossy(&output.stderr).into_owned(), - truncated, - cmdline: format!("{:?}", cmd), - }; - self.fatal_proc_rec("make failed", &res); - } - } - - fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> { - for e in path.read_dir()? { - let entry = e?; - let path = entry.path(); - if entry.file_type()?.is_dir() { - self.aggressive_rm_rf(&path)?; - } else { - // Remove readonly files as well on windows (by default we can't) - fs::remove_file(&path).or_else(|e| { - if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied { - let mut meta = entry.metadata()?.permissions(); - meta.set_readonly(false); - fs::set_permissions(&path, meta)?; - fs::remove_file(&path) - } else { - Err(e) - } - })?; - } - } - fs::remove_dir(path) - } - - fn run_rmake_v2_test(&self) { - // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe - // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust - // library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`. - // - // 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support` - // library. - // 2. We need to run the recipe binary. - - // So we assume the rust-lang/rust project setup looks like the following (our `.` is the - // top-level directory, irrelevant entries to our purposes omitted): - // - // ``` - // . // <- `source_root` - // ├── build/ // <- `build_root` - // ├── compiler/ - // ├── library/ - // ├── src/ - // │ └── tools/ - // │ └── run_make_support/ - // └── tests - // └── run-make/ - // ``` - - // `source_root` is the top-level directory containing the rust-lang/rust checkout. - let source_root = - self.config.find_rust_src_root().expect("could not determine rust source root"); - // `self.config.build_base` is actually the build base folder + "test" + test suite name, it - // looks like `build//test/run-make`. But we want `build//`. Note - // that the `build` directory does not need to be called `build`, nor does it need to be - // under `source_root`, so we must compute it based off of `self.config.build_base`. - let build_root = - self.config.build_base.parent().and_then(Path::parent).unwrap().to_path_buf(); - - // We construct the following directory tree for each rmake.rs test: - // ``` - // / - // rmake.exe - // rmake_out/ - // ``` - // having the recipe executable separate from the output artifacts directory allows the - // recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove - // a currently running executable because the recipe executable is not under the - // `rmake_out/` directory. - // - // This setup intentionally diverges from legacy Makefile run-make tests. - let base_dir = self.output_base_name(); - if base_dir.exists() { - self.aggressive_rm_rf(&base_dir).unwrap(); - } - let rmake_out_dir = base_dir.join("rmake_out"); - create_dir_all(&rmake_out_dir).unwrap(); - - // Copy all input files (apart from rmake.rs) to the temporary directory, - // so that the input directory structure from `tests/run-make/` is mirrored - // to the `rmake_out` directory. - for path in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) { - let path = path.unwrap().path().to_path_buf(); - if path.file_name().is_some_and(|s| s != "rmake.rs") { - let target = rmake_out_dir.join(path.strip_prefix(&self.testpaths.file).unwrap()); - if path.is_dir() { - copy_dir_all(&path, target).unwrap(); - } else { - fs::copy(&path, target).unwrap(); - } - } - } - - // `self.config.stage_id` looks like `stage1-`, but we only want - // the `stage1` part as that is what the output directories of bootstrap are prefixed with. - // Note that this *assumes* build layout from bootstrap is produced as: - // - // ``` - // build// // <- this is `build_root` - // ├── stage0 - // ├── stage0-bootstrap-tools - // ├── stage0-codegen - // ├── stage0-rustc - // ├── stage0-std - // ├── stage0-sysroot - // ├── stage0-tools - // ├── stage0-tools-bin - // ├── stage1 - // ├── stage1-std - // ├── stage1-tools - // ├── stage1-tools-bin - // └── test - // ``` - // FIXME(jieyouxu): improve the communication between bootstrap and compiletest here so - // we don't have to hack out a `stageN`. - let stage = self.config.stage_id.split('-').next().unwrap(); - - // In order to link in the support library as a rlib when compiling recipes, we need three - // paths: - // 1. Path of the built support library rlib itself. - // 2. Path of the built support library's dependencies directory. - // 3. Path of the built support library's dependencies' dependencies directory. - // - // The paths look like - // - // ``` - // build// - // ├── stageN-tools-bin/ - // │ └── librun_make_support.rlib // <- support rlib itself - // ├── stageN-tools/ - // │ ├── release/deps/ // <- deps of deps - // │ └── /release/deps/ // <- deps - // ``` - // - // FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the - // support lib and its deps are organized, can't we copy them to the tools-bin dir as - // well?), but this seems to work for now. - - let stage_tools_bin = build_root.join(format!("{stage}-tools-bin")); - let support_lib_path = stage_tools_bin.join("librun_make_support.rlib"); - - let stage_tools = build_root.join(format!("{stage}-tools")); - let support_lib_deps = stage_tools.join(&self.config.host).join("release").join("deps"); - let support_lib_deps_deps = stage_tools.join("release").join("deps"); - - // To compile the recipe with rustc, we need to provide suitable dynamic library search - // paths to rustc. This includes both: - // 1. The "base" dylib search paths that was provided to compiletest, e.g. `LD_LIBRARY_PATH` - // on some linux distros. - // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc. - - let base_dylib_search_paths = - Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); - - let host_dylib_search_paths = { - let mut paths = vec![self.config.compile_lib_path.clone()]; - paths.extend(base_dylib_search_paths.iter().cloned()); - paths - }; - - // Calculate the paths of the recipe binary. As previously discussed, this is placed at - // `/` with `bin_name` being `rmake` or `rmake.exe` depending on - // platform. - let recipe_bin = { - let mut p = base_dir.join("rmake"); - p.set_extension(env::consts::EXE_EXTENSION); - p - }; - - let mut rustc = Command::new(&self.config.rustc_path); - rustc - .arg("-o") - .arg(&recipe_bin) - // Specify library search paths for `run_make_support`. - .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy())) - .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy())) - .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) - // Provide `run_make_support` as extern prelude, so test writers don't need to write - // `extern run_make_support;`. - .arg("--extern") - .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) - .arg("--edition=2021") - .arg(&self.testpaths.file.join("rmake.rs")) - // Provide necessary library search paths for rustc. - .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); - - // In test code we want to be very pedantic about values being silently discarded that are - // annotated with `#[must_use]`. - rustc.arg("-Dunused_must_use"); - - // > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc - // > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is - // > compiled using the bootstrap rustc wrapper which sets `--sysroot - // > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile - // > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the - // > `libstd.rlib` against which `librun_make_support.rlib` is compiled. - // - // The gist here is that we have to pass the proper stage0 sysroot if we want - // - // ``` - // $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0 - // ``` - // - // to work correctly. - // - // See for more background. - if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { - let stage0_sysroot = build_root.join("stage0-sysroot"); - rustc.arg("--sysroot").arg(&stage0_sysroot); - } - - // Now run rustc to build the recipe. - let res = self.run_command_to_procres(&mut rustc); - if !res.status.success() { - self.fatal_proc_rec("run-make test failed: could not build `rmake.rs` recipe", &res); - } - - // To actually run the recipe, we have to provide the recipe with a bunch of information - // provided through env vars. - - // Compute stage-specific standard library paths. - let stage_std_path = build_root.join(&stage).join("lib"); - - // Compute dynamic library search paths for recipes. - let recipe_dylib_search_paths = { - let mut paths = base_dylib_search_paths.clone(); - paths.push(support_lib_path.parent().unwrap().to_path_buf()); - paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); - paths - }; - - // Compute runtime library search paths for recipes. This is target-specific. - let target_runtime_dylib_search_paths = { - let mut paths = vec![rmake_out_dir.clone()]; - paths.extend(base_dylib_search_paths.iter().cloned()); - paths - }; - - // FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and - // `TARGET_RPATH_DIR`, it is **extremely** confusing! - let mut cmd = Command::new(&recipe_bin); - cmd.current_dir(&rmake_out_dir) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - // Provide the target-specific env var that is used to record dylib search paths. For - // example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows. - .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - // Provide the dylib search paths. - .env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap()) - // Provide runtime dylib search paths. - .env("TARGET_RPATH_ENV", &env::join_paths(target_runtime_dylib_search_paths).unwrap()) - // Provide the target. - .env("TARGET", &self.config.target) - // Some tests unfortunately still need Python, so provide path to a Python interpreter. - .env("PYTHON", &self.config.python) - // Provide path to checkout root. This is the top-level directory containing - // rust-lang/rust checkout. - .env("SOURCE_ROOT", &source_root) - // Provide path to stage-corresponding rustc. - .env("RUSTC", &self.config.rustc_path) - // Provide the directory to libraries that are needed to run the *compiler*. This is not - // to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the - // recipe wants to invoke rustc. - .env("HOST_RPATH_DIR", &self.config.compile_lib_path) - // Provide the directory to libraries that might be needed to run compiled binaries - // (further compiled by the recipe!). - .env("TARGET_RPATH_DIR", &self.config.run_lib_path) - // Provide which LLVM components are available (e.g. which LLVM components are provided - // through a specific CI runner). - .env("LLVM_COMPONENTS", &self.config.llvm_components); - - if let Some(ref rustdoc) = self.config.rustdoc_path { - cmd.env("RUSTDOC", source_root.join(rustdoc)); - } - - if let Some(ref node) = self.config.nodejs { - cmd.env("NODE", node); - } - - if let Some(ref linker) = self.config.target_linker { - cmd.env("RUSTC_LINKER", linker); - } - - if let Some(ref clang) = self.config.run_clang_based_tests_with { - cmd.env("CLANG", clang); - } - - if let Some(ref filecheck) = self.config.llvm_filecheck { - cmd.env("LLVM_FILECHECK", filecheck); - } - - if let Some(ref llvm_bin_dir) = self.config.llvm_bin_dir { - cmd.env("LLVM_BIN_DIR", llvm_bin_dir); - } - - if let Some(ref remote_test_client) = self.config.remote_test_client { - cmd.env("REMOTE_TEST_CLIENT", remote_test_client); - } - - // We don't want RUSTFLAGS set from the outside to interfere with - // compiler flags set in the test cases: - cmd.env_remove("RUSTFLAGS"); - - // Use dynamic musl for tests because static doesn't allow creating dylibs - if self.config.host.contains("musl") { - cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1"); - } - - if self.config.bless { - // If we're running in `--bless` mode, set an environment variable to tell - // `run_make_support` to bless snapshot files instead of checking them. - // - // The value is this test's source directory, because the support code - // will need that path in order to bless the _original_ snapshot files, - // not the copies in `rmake_out`. - // (See .) - cmd.env("RUSTC_BLESS_TEST", &self.testpaths.file); - } - - if self.config.target.contains("msvc") && !self.config.cc.is_empty() { - // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` - // and that `lib.exe` lives next to it. - let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); - - // MSYS doesn't like passing flags of the form `/foo` as it thinks it's - // a path and instead passes `C:\msys64\foo`, so convert all - // `/`-arguments to MSVC here to `-` arguments. - let cflags = self - .config - .cflags - .split(' ') - .map(|s| s.replace("/", "-")) - .collect::>() - .join(" "); - let cxxflags = self - .config - .cxxflags - .split(' ') - .map(|s| s.replace("/", "-")) - .collect::>() - .join(" "); - - cmd.env("IS_MSVC", "1") - .env("IS_WINDOWS", "1") - .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) - .env("MSVC_LIB_PATH", format!("{}", lib.display())) - // Note: we diverge from legacy run_make and don't lump `CC` the compiler and - // default flags together. - .env("CC_DEFAULT_FLAGS", &cflags) - .env("CC", &self.config.cc) - .env("CXX_DEFAULT_FLAGS", &cxxflags) - .env("CXX", &self.config.cxx); - } else { - cmd.env("CC_DEFAULT_FLAGS", &self.config.cflags) - .env("CC", &self.config.cc) - .env("CXX_DEFAULT_FLAGS", &self.config.cxxflags) - .env("CXX", &self.config.cxx) - .env("AR", &self.config.ar); - - if self.config.target.contains("windows") { - cmd.env("IS_WINDOWS", "1"); - } - } - - let (Output { stdout, stderr, status }, truncated) = - self.read2_abbreviated(cmd.spawn().expect("failed to spawn `rmake`")); - if !status.success() { - let res = ProcRes { - status, - stdout: String::from_utf8_lossy(&stdout).into_owned(), - stderr: String::from_utf8_lossy(&stderr).into_owned(), - truncated, - cmdline: format!("{:?}", cmd), - }; - self.fatal_proc_rec("rmake recipe failed to complete", &res); - } - } - - fn run_js_doc_test(&self) { - if let Some(nodejs) = &self.config.nodejs { - let out_dir = self.output_base_dir(); - - self.document(&out_dir, &self.testpaths); - - let root = self.config.find_rust_src_root().unwrap(); - let file_stem = - self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem"); - let res = self.run_command_to_procres( - Command::new(&nodejs) - .arg(root.join("src/tools/rustdoc-js/tester.js")) - .arg("--doc-folder") - .arg(out_dir) - .arg("--crate-name") - .arg(file_stem.replace("-", "_")) - .arg("--test-file") - .arg(self.testpaths.file.with_extension("js")), - ); - if !res.status.success() { - self.fatal_proc_rec("rustdoc-js test failed!", &res); - } - } else { - self.fatal("no nodeJS"); - } - } - fn force_color_svg(&self) -> bool { self.props.compile_flags.iter().any(|s| s.contains("--color=always")) } @@ -3895,377 +2258,6 @@ impl<'test> TestCx<'test> { errors } - fn run_ui_test(&self) { - 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, Emit::Metadata, pm, Vec::new()); - self.check_if_test_should_compile(&proc_res, pm); - } - - let pm = self.pass_mode(); - let should_run = self.should_run(pm); - let emit_metadata = self.should_emit_metadata(pm); - let proc_res = self.compile_test(should_run, emit_metadata); - self.check_if_test_should_compile(&proc_res, pm); - if matches!(proc_res.truncated, Truncated::Yes) - && !self.props.dont_check_compiler_stdout - && !self.props.dont_check_compiler_stderr - { - self.fatal_proc_rec( - "compiler output got truncated, cannot compare with reference file", - &proc_res, - ); - } - - // if the user specified a format in the ui test - // print the output to the stderr file, otherwise extract - // the rendered error messages from json and print them - let explicit = self.props.compile_flags.iter().any(|s| s.contains("--error-format")); - - let expected_fixed = self.load_expected_output(UI_FIXED); - - self.check_and_prune_duplicate_outputs(&proc_res, &[], &[]); - - let mut errors = self.load_compare_outputs(&proc_res, TestOutput::Compile, explicit); - let rustfix_input = json::rustfix_diagnostics_only(&proc_res.stderr); - - if self.config.compare_mode.is_some() { - // don't test rustfix with nll right now - } else if self.config.rustfix_coverage { - // Find out which tests have `MachineApplicable` suggestions but are missing - // `run-rustfix` or `run-rustfix-only-machine-applicable` headers. - // - // This will return an empty `Vec` in case the executed test file has a - // `compile-flags: --error-format=xxxx` header with a value other than `json`. - let suggestions = get_suggestions_from_json( - &rustfix_input, - &HashSet::new(), - Filter::MachineApplicableOnly, - ) - .unwrap_or_default(); - if !suggestions.is_empty() - && !self.props.run_rustfix - && !self.props.rustfix_only_machine_applicable - { - let mut coverage_file_path = self.config.build_base.clone(); - coverage_file_path.push("rustfix_missing_coverage.txt"); - debug!("coverage_file_path: {}", coverage_file_path.display()); - - let mut file = OpenOptions::new() - .create(true) - .append(true) - .open(coverage_file_path.as_path()) - .expect("could not create or open file"); - - if let Err(e) = writeln!(file, "{}", self.testpaths.file.display()) { - panic!("couldn't write to {}: {e:?}", coverage_file_path.display()); - } - } - } else if self.props.run_rustfix { - // Apply suggestions from rustc to the code itself - let unfixed_code = self.load_expected_output_from_path(&self.testpaths.file).unwrap(); - let suggestions = get_suggestions_from_json( - &rustfix_input, - &HashSet::new(), - if self.props.rustfix_only_machine_applicable { - Filter::MachineApplicableOnly - } else { - Filter::Everything - }, - ) - .unwrap(); - let fixed_code = apply_suggestions(&unfixed_code, &suggestions).unwrap_or_else(|e| { - panic!( - "failed to apply suggestions for {:?} with rustfix: {}", - self.testpaths.file, e - ) - }); - - errors += self.compare_output("fixed", &fixed_code, &expected_fixed); - } else if !expected_fixed.is_empty() { - panic!( - "the `//@ run-rustfix` directive wasn't found but a `*.fixed` \ - file was found" - ); - } - - if errors > 0 { - println!("To update references, rerun the tests and pass the `--bless` flag"); - let relative_path_to_file = - self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap()); - println!( - "To only update this specific test, also pass `--test-args {}`", - relative_path_to_file.display(), - ); - self.fatal_proc_rec( - &format!("{} errors occurred comparing output.", errors), - &proc_res, - ); - } - - let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - - if let WillExecute::Yes = should_run { - let proc_res = self.exec_compiled_test(); - let run_output_errors = if self.props.check_run_results { - self.load_compare_outputs(&proc_res, TestOutput::Run, explicit) - } else { - 0 - }; - if run_output_errors > 0 { - self.fatal_proc_rec( - &format!("{} errors occurred comparing run output.", run_output_errors), - &proc_res, - ); - } - if self.should_run_successfully(pm) { - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } else if proc_res.status.success() { - self.fatal_proc_rec("test run succeeded!", &proc_res); - } - - if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() - { - // "// error-pattern" comments - let output_to_check = self.get_output(&proc_res); - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } - } - - debug!( - "run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \ - proc_res.status={:?} props.error_patterns={:?}", - explicit, - self.config.compare_mode, - expected_errors, - proc_res.status, - self.props.error_patterns - ); - - let check_patterns = should_run == WillExecute::No - && (!self.props.error_patterns.is_empty() - || !self.props.regex_error_patterns.is_empty()); - if !explicit && self.config.compare_mode.is_none() { - let check_annotations = !check_patterns || !expected_errors.is_empty(); - - if check_annotations { - // "//~ERROR comments" - self.check_expected_errors(expected_errors, &proc_res); - } - } else if explicit && !expected_errors.is_empty() { - let msg = format!( - "line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead", - expected_errors[0].line_num, - expected_errors[0].kind.unwrap_or(ErrorKind::Error), - ); - self.fatal(&msg); - } - if check_patterns { - // "// error-pattern" comments - let output_to_check = self.get_output(&proc_res); - self.check_all_error_patterns(&output_to_check, &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( - &self.expected_output_path(UI_FIXED), - TargetLocation::ThisFile(self.make_exe_name()), - emit_metadata, - AllowUnused::No, - LinkToAux::Yes, - Vec::new(), - ); - - // If a test is revisioned, it's fixed source file can be named "a.foo.fixed", which, - // well, "a.foo" isn't a valid crate name. So we explicitly mangle the test name - // (including the revision) here to avoid the test writer having to manually specify a - // `#![crate_name = "..."]` as a workaround. This is okay since we're only checking if - // the fixed code is compilable. - if self.revision.is_some() { - let crate_name = - self.testpaths.file.file_stem().expect("test must have a file stem"); - // crate name must be alphanumeric or `_`. - let crate_name = - crate_name.to_str().expect("crate name implies file name must be valid UTF-8"); - // replace `a.foo` -> `a__foo` for crate name purposes. - // replace `revision-name-with-dashes` -> `revision_name_with_underscore` - let crate_name = crate_name.replace('.', "__"); - let crate_name = crate_name.replace('-', "_"); - rustc.arg("--crate-name"); - rustc.arg(crate_name); - } - - let res = self.compose_and_run_compiler(rustc, None, self.testpaths); - if !res.status.success() { - self.fatal_proc_rec("failed to compile fixed code", &res); - } - if !res.stderr.is_empty() - && !self.props.rustfix_only_machine_applicable - && !json::rustfix_diagnostics_only(&res.stderr).is_empty() - { - self.fatal_proc_rec("fixed code is still producing diagnostics", &res); - } - } - } - - fn run_mir_opt_test(&self) { - let pm = self.pass_mode(); - let should_run = self.should_run(pm); - - let mut test_info = files_for_miropt_test( - &self.testpaths.file, - self.config.get_pointer_width(), - self.config.target_cfg().panic.for_miropt_test_tools(), - ); - - let passes = std::mem::take(&mut test_info.passes); - - let proc_res = self.compile_test_with_passes(should_run, Emit::Mir, passes); - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - self.check_mir_dump(test_info); - - if let WillExecute::Yes = should_run { - let proc_res = self.exec_compiled_test(); - - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } - } - - fn check_mir_dump(&self, test_info: MiroptTest) { - let test_dir = self.testpaths.file.parent().unwrap(); - let test_crate = - self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_"); - - let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info; - - if self.config.bless { - for e in - glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, suffix)).unwrap() - { - std::fs::remove_file(e.unwrap()).unwrap(); - } - for e in - glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, suffix)).unwrap() - { - std::fs::remove_file(e.unwrap()).unwrap(); - } - } - - for MiroptTestFile { 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() - ); - } - 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() - ); - } - } - } - - if run_filecheck { - let output_path = self.output_base_name().with_extension("mir"); - let proc_res = self.verify_with_filecheck(&output_path); - if !proc_res.status.success() { - self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); - } - } - } - - fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String { - let to_full_path = |path: PathBuf| { - let full = self.get_mir_dump_dir().join(&path); - if !full.exists() { - panic!( - "the mir dump file for {} does not exist (requested in {})", - path.display(), - self.testpaths.file.display(), - ); - } - full - }; - let before = to_full_path(before); - let after = to_full_path(after); - debug!("comparing the contents of: {} with {}", before.display(), after.display()); - let before = fs::read_to_string(before).unwrap(); - let after = fs::read_to_string(after).unwrap(); - let before = self.normalize_output(&before, &[]); - let after = self.normalize_output(&after, &[]); - let mut dumped_string = String::new(); - for result in diff::lines(&before, &after) { - use std::fmt::Write; - match result { - diff::Result::Left(s) => writeln!(dumped_string, "- {}", s).unwrap(), - diff::Result::Right(s) => writeln!(dumped_string, "+ {}", s).unwrap(), - diff::Result::Both(s, _) => writeln!(dumped_string, " {}", s).unwrap(), - } - } - dumped_string - } - - fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) { - let t = |file| fs::metadata(file).unwrap().modified().unwrap(); - let source_file = &self.testpaths.file; - let output_time = t(output_file); - let source_time = t(source_file); - if source_time > output_time { - debug!("source file time: {:?} output file time: {:?}", source_time, output_time); - panic!( - "test source file `{}` is newer than potentially stale output file `{}`.", - source_file.display(), - test_name - ); - } - } - - fn get_mir_dump_dir(&self) -> PathBuf { - let mut mir_dump_dir = PathBuf::from(self.config.build_base.as_path()); - debug!("input_file: {:?}", self.testpaths.file); - mir_dump_dir.push(&self.testpaths.relative_dir); - mir_dump_dir.push(self.testpaths.file.file_stem().unwrap()); - mir_dump_dir - } - fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String { // Crude heuristic to detect when the output should have JSON-specific // normalization steps applied. @@ -4634,6 +2626,77 @@ impl<'test> TestCx<'test> { let stamp = crate::stamp(&self.config, self.testpaths, self.revision); fs::write(&stamp, compute_stamp_hash(&self.config)).unwrap(); } + + fn init_incremental_test(&self) { + // (See `run_incremental_test` for an overview of how incremental tests work.) + + // Before any of the revisions have executed, create the + // incremental workproduct directory. Delete any old + // incremental work products that may be there from prior + // runs. + let incremental_dir = self.props.incremental_dir.as_ref().unwrap(); + if incremental_dir.exists() { + // Canonicalizing the path will convert it to the //?/ format + // on Windows, which enables paths longer than 260 character + let canonicalized = incremental_dir.canonicalize().unwrap(); + fs::remove_dir_all(canonicalized).unwrap(); + } + fs::create_dir_all(&incremental_dir).unwrap(); + + if self.config.verbose { + println!("init_incremental_test: incremental_dir={}", incremental_dir.display()); + } + } + + // FIXME(jieyouxu): `run_rpass_test` is hoisted out here and not in incremental because + // apparently valgrind test falls back to `run_rpass_test` if valgrind isn't available, which + // seems highly questionable to me. + fn run_rpass_test(&self) { + let emit_metadata = self.should_emit_metadata(self.pass_mode()); + let should_run = self.run_if_enabled(); + let proc_res = self.compile_test(should_run, emit_metadata); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + // FIXME(#41968): Move this check to tidy? + if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { + self.fatal("run-pass tests with expected warnings should be moved to ui/"); + } + + if let WillExecute::Disabled = should_run { + return; + } + + let proc_res = self.exec_compiled_test(); + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + } + + fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> { + for e in path.read_dir()? { + let entry = e?; + let path = entry.path(); + if entry.file_type()?.is_dir() { + self.aggressive_rm_rf(&path)?; + } else { + // Remove readonly files as well on windows (by default we can't) + fs::remove_file(&path).or_else(|e| { + if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied { + let mut meta = entry.metadata()?.permissions(); + meta.set_readonly(false); + fs::set_permissions(&path, meta)?; + fs::remove_file(&path) + } else { + Err(e) + } + })?; + } + } + fs::remove_dir(path) + } } struct ProcArgs { diff --git a/src/tools/compiletest/src/runtest/assembly.rs b/src/tools/compiletest/src/runtest/assembly.rs new file mode 100644 index 0000000000000..430a5534da1fd --- /dev/null +++ b/src/tools/compiletest/src/runtest/assembly.rs @@ -0,0 +1,19 @@ +use super::TestCx; + +impl TestCx<'_> { + pub(super) fn run_assembly_test(&self) { + if self.config.llvm_filecheck.is_none() { + self.fatal("missing --llvm-filecheck"); + } + + let (proc_res, output_path) = self.compile_test_and_save_assembly(); + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + let proc_res = self.verify_with_filecheck(&output_path); + if !proc_res.status.success() { + self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); + } + } +} diff --git a/src/tools/compiletest/src/runtest/codegen.rs b/src/tools/compiletest/src/runtest/codegen.rs new file mode 100644 index 0000000000000..6e61ab5e46d66 --- /dev/null +++ b/src/tools/compiletest/src/runtest/codegen.rs @@ -0,0 +1,22 @@ +use super::{PassMode, TestCx}; + +impl TestCx<'_> { + pub(super) fn run_codegen_test(&self) { + if self.config.llvm_filecheck.is_none() { + self.fatal("missing --llvm-filecheck"); + } + + let (proc_res, output_path) = self.compile_test_and_save_ir(); + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + if let Some(PassMode::Build) = self.pass_mode() { + return; + } + let proc_res = self.verify_with_filecheck(&output_path); + if !proc_res.status.success() { + self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); + } + } +} diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs new file mode 100644 index 0000000000000..6c866cbef21ab --- /dev/null +++ b/src/tools/compiletest/src/runtest/codegen_units.rs @@ -0,0 +1,191 @@ +use std::collections::HashSet; + +use super::{Emit, TestCx, WillExecute}; +use crate::errors; +use crate::util::static_regex; + +impl TestCx<'_> { + pub(super) fn run_codegen_units_test(&self) { + assert!(self.revision.is_none(), "revisions not relevant here"); + + let proc_res = self.compile_test(WillExecute::No, Emit::None); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + self.check_no_compiler_crash(&proc_res, self.props.should_ice); + + const PREFIX: &str = "MONO_ITEM "; + const CGU_MARKER: &str = "@@"; + + // Some MonoItems can contain {closure@/path/to/checkout/tests/codgen-units/test.rs} + // To prevent the current dir from leaking, we just replace the entire path to the test + // file with TEST_PATH. + let actual: Vec = proc_res + .stdout + .lines() + .filter(|line| line.starts_with(PREFIX)) + .map(|line| { + line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string() + }) + .map(|line| str_to_mono_item(&line, true)) + .collect(); + + let expected: Vec = errors::load_errors(&self.testpaths.file, None) + .iter() + .map(|e| str_to_mono_item(&e.msg[..], false)) + .collect(); + + let mut missing = Vec::new(); + let mut wrong_cgus = Vec::new(); + + for expected_item in &expected { + let actual_item_with_same_name = actual.iter().find(|ti| ti.name == expected_item.name); + + if let Some(actual_item) = actual_item_with_same_name { + if !expected_item.codegen_units.is_empty() && + // Also check for codegen units + expected_item.codegen_units != actual_item.codegen_units + { + wrong_cgus.push((expected_item.clone(), actual_item.clone())); + } + } else { + missing.push(expected_item.string.clone()); + } + } + + let unexpected: Vec<_> = actual + .iter() + .filter(|acgu| !expected.iter().any(|ecgu| acgu.name == ecgu.name)) + .map(|acgu| acgu.string.clone()) + .collect(); + + if !missing.is_empty() { + missing.sort(); + + println!("\nThese items should have been contained but were not:\n"); + + for item in &missing { + println!("{}", item); + } + + println!("\n"); + } + + if !unexpected.is_empty() { + let sorted = { + let mut sorted = unexpected.clone(); + sorted.sort(); + sorted + }; + + println!("\nThese items were contained but should not have been:\n"); + + for item in sorted { + println!("{}", item); + } + + println!("\n"); + } + + if !wrong_cgus.is_empty() { + wrong_cgus.sort_by_key(|pair| pair.0.name.clone()); + println!("\nThe following items were assigned to wrong codegen units:\n"); + + for &(ref expected_item, ref actual_item) in &wrong_cgus { + println!("{}", expected_item.name); + println!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units)); + println!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units)); + println!(); + } + } + + if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty()) { + panic!(); + } + + #[derive(Clone, Eq, PartialEq)] + struct MonoItem { + name: String, + codegen_units: HashSet, + string: String, + } + + // [MONO_ITEM] name [@@ (cgu)+] + fn str_to_mono_item(s: &str, cgu_has_crate_disambiguator: bool) -> MonoItem { + let s = if s.starts_with(PREFIX) { (&s[PREFIX.len()..]).trim() } else { s.trim() }; + + let full_string = format!("{}{}", PREFIX, s); + + let parts: Vec<&str> = + s.split(CGU_MARKER).map(str::trim).filter(|s| !s.is_empty()).collect(); + + let name = parts[0].trim(); + + let cgus = if parts.len() > 1 { + let cgus_str = parts[1]; + + cgus_str + .split(' ') + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(|s| { + if cgu_has_crate_disambiguator { + remove_crate_disambiguators_from_set_of_cgu_names(s) + } else { + s.to_string() + } + }) + .collect() + } else { + HashSet::new() + }; + + MonoItem { name: name.to_owned(), codegen_units: cgus, string: full_string } + } + + fn codegen_units_to_str(cgus: &HashSet) -> String { + let mut cgus: Vec<_> = cgus.iter().collect(); + cgus.sort(); + + let mut string = String::new(); + for cgu in cgus { + string.push_str(&cgu[..]); + string.push(' '); + } + + string + } + + // Given a cgu-name-prefix of the form . or + // the form .-in-., + // remove all crate-disambiguators. + fn remove_crate_disambiguator_from_cgu(cgu: &str) -> String { + let Some(captures) = + static_regex!(r"^[^\.]+(?P\.[[:alnum:]]+)(-in-[^\.]+(?P\.[[:alnum:]]+))?") + .captures(cgu) + else { + panic!("invalid cgu name encountered: {cgu}"); + }; + + let mut new_name = cgu.to_owned(); + + if let Some(d2) = captures.name("d2") { + new_name.replace_range(d2.start()..d2.end(), ""); + } + + let d1 = captures.name("d1").unwrap(); + new_name.replace_range(d1.start()..d1.end(), ""); + + new_name + } + + // The name of merged CGUs is constructed as the names of the original + // CGUs joined with "--". This function splits such composite CGU names + // and handles each component individually. + fn remove_crate_disambiguators_from_set_of_cgu_names(cgus: &str) -> String { + cgus.split("--").map(remove_crate_disambiguator_from_cgu).collect::>().join("--") + } + } +} diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs index 05191a159801c..961a160298631 100644 --- a/src/tools/compiletest/src/runtest/coverage.rs +++ b/src/tools/compiletest/src/runtest/coverage.rs @@ -18,7 +18,7 @@ impl<'test> TestCx<'test> { .unwrap_or_else(|| self.fatal("missing --coverage-dump")) } - pub(crate) fn run_coverage_map_test(&self) { + pub(super) fn run_coverage_map_test(&self) { let coverage_dump_path = self.coverage_dump_path(); let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir(); @@ -50,7 +50,7 @@ impl<'test> TestCx<'test> { } } - pub(crate) fn run_coverage_run_test(&self) { + pub(super) fn run_coverage_run_test(&self) { let should_run = self.run_if_enabled(); let proc_res = self.compile_test(should_run, Emit::None); diff --git a/src/tools/compiletest/src/runtest/crash.rs b/src/tools/compiletest/src/runtest/crash.rs new file mode 100644 index 0000000000000..885ed3b08faca --- /dev/null +++ b/src/tools/compiletest/src/runtest/crash.rs @@ -0,0 +1,26 @@ +use super::{TestCx, WillExecute}; + +impl TestCx<'_> { + pub(super) fn run_crash_test(&self) { + let pm = self.pass_mode(); + let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); + + if std::env::var("COMPILETEST_VERBOSE_CRASHES").is_ok() { + eprintln!("{}", proc_res.status); + eprintln!("{}", proc_res.stdout); + eprintln!("{}", proc_res.stderr); + eprintln!("{}", proc_res.cmdline); + } + + // if a test does not crash, consider it an error + if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { + self.fatal(&format!( + "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful \ + name, add a doc-comment to the start of the test explaining why it exists and \ + move it to tests/ui or wherever you see fit. Adding 'Fixes #' to your PR \ + description ensures that the corresponding ticket is auto-closed upon merge. \ + If you want to see verbose output, set `COMPILETEST_VERBOSE_CRASHES=1`." + )); + } + } +} diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs new file mode 100644 index 0000000000000..36127414ab147 --- /dev/null +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -0,0 +1,509 @@ +use std::ffi::{OsStr, OsString}; +use std::fs::File; +use std::io::{BufRead, BufReader, Read}; +use std::path::Path; +use std::process::{Command, Output, Stdio}; + +use tracing::debug; + +use super::debugger::DebuggerCommands; +use super::{Debugger, Emit, ProcRes, TestCx, Truncated, WillExecute}; +use crate::common::Config; +use crate::util::logv; +use crate::{extract_gdb_version, is_android_gdb_target}; + +impl TestCx<'_> { + pub(super) fn run_debuginfo_test(&self) { + match self.config.debugger.unwrap() { + Debugger::Cdb => self.run_debuginfo_cdb_test(), + Debugger::Gdb => self.run_debuginfo_gdb_test(), + Debugger::Lldb => self.run_debuginfo_lldb_test(), + } + } + + fn run_debuginfo_cdb_test(&self) { + let config = Config { + target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), + host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), + ..self.config.clone() + }; + + let test_cx = TestCx { config: &config, ..*self }; + + test_cx.run_debuginfo_cdb_test_no_opt(); + } + + fn run_debuginfo_cdb_test_no_opt(&self) { + let exe_file = self.make_exe_name(); + + // Existing PDB files are update in-place. When changing the debuginfo + // the compiler generates for something, this can lead to the situation + // where both the old and the new version of the debuginfo for the same + // type is present in the PDB, which is very confusing. + // Therefore we delete any existing PDB file before compiling the test + // case. + // FIXME: If can reliably detect that MSVC's link.exe is used, then + // passing `/INCREMENTAL:NO` might be a cleaner way to do this. + let pdb_file = exe_file.with_extension(".pdb"); + if pdb_file.exists() { + std::fs::remove_file(pdb_file).unwrap(); + } + + // 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, Emit::None); + if !compile_result.status.success() { + self.fatal_proc_rec("compilation failed!", &compile_result); + } + if let WillExecute::Disabled = should_run { + return; + } + + let prefixes = { + static PREFIXES: &[&str] = &["cdb", "cdbg"]; + // No "native rust support" variation for CDB yet. + PREFIXES + }; + + // Parse debugger commands etc from test files + let dbg_cmds = DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + prefixes, + self.revision, + ) + .unwrap_or_else(|e| self.fatal(&e)); + + // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands + let mut script_str = String::with_capacity(2048); + script_str.push_str("version\n"); // List CDB (and more) version info in test output + script_str.push_str(".nvlist\n"); // List loaded `*.natvis` files, bulk of custom MSVC debug + + // If a .js file exists next to the source file being tested, then this is a JavaScript + // debugging extension that needs to be loaded. + let mut js_extension = self.testpaths.file.clone(); + js_extension.set_extension("cdb.js"); + if js_extension.exists() { + script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension.to_string_lossy())); + } + + // Set breakpoints on every line that contains the string "#break" + let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); + for line in &dbg_cmds.breakpoint_lines { + script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line)); + } + + // Append the other `cdb-command:`s + for line in &dbg_cmds.commands { + script_str.push_str(line); + script_str.push('\n'); + } + + script_str.push_str("qq\n"); // Quit the debugger (including remote debugger, if any) + + // Write the script into a file + debug!("script_str = {}", script_str); + self.dump_output_file(&script_str, "debugger.script"); + let debugger_script = self.make_out_name("debugger.script"); + + let cdb_path = &self.config.cdb.as_ref().unwrap(); + let mut cdb = Command::new(cdb_path); + cdb.arg("-lines") // Enable source line debugging. + .arg("-cf") + .arg(&debugger_script) + .arg(&exe_file); + + let debugger_run_result = self.compose_and_run( + cdb, + self.config.run_lib_path.to_str().unwrap(), + None, // aux_path + None, // input + ); + + if !debugger_run_result.status.success() { + self.fatal_proc_rec("Error while running CDB", &debugger_run_result); + } + + if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { + self.fatal_proc_rec(&e, &debugger_run_result); + } + } + + fn run_debuginfo_gdb_test(&self) { + let config = Config { + target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), + host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), + ..self.config.clone() + }; + + let test_cx = TestCx { config: &config, ..*self }; + + test_cx.run_debuginfo_gdb_test_no_opt(); + } + + fn run_debuginfo_gdb_test_no_opt(&self) { + let dbg_cmds = DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + &["gdb"], + self.revision, + ) + .unwrap_or_else(|e| self.fatal(&e)); + let mut cmds = dbg_cmds.commands.join("\n"); + + // 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, Emit::None); + if !compiler_run_result.status.success() { + self.fatal_proc_rec("compilation failed!", &compiler_run_result); + } + if let WillExecute::Disabled = should_run { + return; + } + + let exe_file = self.make_exe_name(); + + let debugger_run_result; + if is_android_gdb_target(&self.config.target) { + cmds = cmds.replace("run", "continue"); + + let tool_path = match self.config.android_cross_path.to_str() { + Some(x) => x.to_owned(), + None => self.fatal("cannot find android cross path"), + }; + + // write debugger script + let mut script_str = String::with_capacity(2048); + script_str.push_str(&format!("set charset {}\n", Self::charset())); + script_str.push_str(&format!("set sysroot {}\n", tool_path)); + script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap())); + script_str.push_str("target remote :5039\n"); + script_str.push_str(&format!( + "set solib-search-path \ + ./{}/stage2/lib/rustlib/{}/lib/\n", + self.config.host, self.config.target + )); + for line in &dbg_cmds.breakpoint_lines { + script_str.push_str( + format!( + "break {:?}:{}\n", + self.testpaths.file.file_name().unwrap().to_string_lossy(), + *line + ) + .as_str(), + ); + } + script_str.push_str(&cmds); + script_str.push_str("\nquit\n"); + + debug!("script_str = {}", script_str); + self.dump_output_file(&script_str, "debugger.script"); + + let adb_path = &self.config.adb_path; + + Command::new(adb_path) + .arg("push") + .arg(&exe_file) + .arg(&self.config.adb_test_dir) + .status() + .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}")); + + Command::new(adb_path) + .args(&["forward", "tcp:5039", "tcp:5039"]) + .status() + .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}")); + + let adb_arg = format!( + "export LD_LIBRARY_PATH={}; \ + gdbserver{} :5039 {}/{}", + self.config.adb_test_dir.clone(), + if self.config.target.contains("aarch64") { "64" } else { "" }, + self.config.adb_test_dir.clone(), + exe_file.file_name().unwrap().to_str().unwrap() + ); + + debug!("adb arg: {}", adb_arg); + let mut adb = Command::new(adb_path) + .args(&["shell", &adb_arg]) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}")); + + // Wait for the gdbserver to print out "Listening on port ..." + // at which point we know that it's started and then we can + // execute the debugger below. + let mut stdout = BufReader::new(adb.stdout.take().unwrap()); + let mut line = String::new(); + loop { + line.truncate(0); + stdout.read_line(&mut line).unwrap(); + if line.starts_with("Listening on port 5039") { + break; + } + } + drop(stdout); + + let mut debugger_script = OsString::from("-command="); + debugger_script.push(self.make_out_name("debugger.script")); + let debugger_opts: &[&OsStr] = + &["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script]; + + let gdb_path = self.config.gdb.as_ref().unwrap(); + let Output { status, stdout, stderr } = Command::new(&gdb_path) + .args(debugger_opts) + .output() + .unwrap_or_else(|e| panic!("failed to exec `{gdb_path:?}`: {e:?}")); + let cmdline = { + let mut gdb = Command::new(&format!("{}-gdb", self.config.target)); + gdb.args(debugger_opts); + let cmdline = self.make_cmdline(&gdb, ""); + logv(self.config, format!("executing {}", cmdline)); + cmdline + }; + + debugger_run_result = ProcRes { + status, + stdout: String::from_utf8(stdout).unwrap(), + stderr: String::from_utf8(stderr).unwrap(), + truncated: Truncated::No, + cmdline, + }; + if adb.kill().is_err() { + println!("Adb process is already finished."); + } + } else { + let rust_src_root = + self.config.find_rust_src_root().expect("Could not find Rust source root"); + let rust_pp_module_rel_path = Path::new("./src/etc"); + let rust_pp_module_abs_path = + rust_src_root.join(rust_pp_module_rel_path).to_str().unwrap().to_owned(); + // write debugger script + let mut script_str = String::with_capacity(2048); + script_str.push_str(&format!("set charset {}\n", Self::charset())); + script_str.push_str("show version\n"); + + match self.config.gdb_version { + Some(version) => { + println!("NOTE: compiletest thinks it is using GDB version {}", version); + + if version > extract_gdb_version("7.4").unwrap() { + // Add the directory containing the pretty printers to + // GDB's script auto loading safe path + script_str.push_str(&format!( + "add-auto-load-safe-path {}\n", + rust_pp_module_abs_path.replace(r"\", r"\\") + )); + + let output_base_dir = self.output_base_dir().to_str().unwrap().to_owned(); + + // Add the directory containing the output binary to + // include embedded pretty printers to GDB's script + // auto loading safe path + script_str.push_str(&format!( + "add-auto-load-safe-path {}\n", + output_base_dir.replace(r"\", r"\\") + )); + } + } + _ => { + println!( + "NOTE: compiletest does not know which version of \ + GDB it is using" + ); + } + } + + // The following line actually doesn't have to do anything with + // pretty printing, it just tells GDB to print values on one line: + script_str.push_str("set print pretty off\n"); + + // Add the pretty printer directory to GDB's source-file search path + script_str + .push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\"))); + + // Load the target executable + script_str + .push_str(&format!("file {}\n", exe_file.to_str().unwrap().replace(r"\", r"\\"))); + + // Force GDB to print values in the Rust format. + script_str.push_str("set language rust\n"); + + // Add line breakpoints + for line in &dbg_cmds.breakpoint_lines { + script_str.push_str(&format!( + "break '{}':{}\n", + self.testpaths.file.file_name().unwrap().to_string_lossy(), + *line + )); + } + + script_str.push_str(&cmds); + script_str.push_str("\nquit\n"); + + debug!("script_str = {}", script_str); + self.dump_output_file(&script_str, "debugger.script"); + + let mut debugger_script = OsString::from("-command="); + debugger_script.push(self.make_out_name("debugger.script")); + + let debugger_opts: &[&OsStr] = + &["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script]; + + let mut gdb = Command::new(self.config.gdb.as_ref().unwrap()); + let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { + format!("{pp}:{rust_pp_module_abs_path}") + } else { + rust_pp_module_abs_path + }; + gdb.args(debugger_opts).env("PYTHONPATH", pythonpath); + + debugger_run_result = + self.compose_and_run(gdb, self.config.run_lib_path.to_str().unwrap(), None, None); + } + + if !debugger_run_result.status.success() { + self.fatal_proc_rec("gdb failed to execute", &debugger_run_result); + } + + if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { + self.fatal_proc_rec(&e, &debugger_run_result); + } + } + + fn run_debuginfo_lldb_test(&self) { + if self.config.lldb_python_dir.is_none() { + self.fatal("Can't run LLDB test because LLDB's python path is not set."); + } + + let config = Config { + target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), + host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), + ..self.config.clone() + }; + + let test_cx = TestCx { config: &config, ..*self }; + + test_cx.run_debuginfo_lldb_test_no_opt(); + } + + 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, Emit::None); + if !compile_result.status.success() { + self.fatal_proc_rec("compilation failed!", &compile_result); + } + if let WillExecute::Disabled = should_run { + return; + } + + let exe_file = self.make_exe_name(); + + match self.config.lldb_version { + Some(ref version) => { + println!("NOTE: compiletest thinks it is using LLDB version {}", version); + } + _ => { + println!( + "NOTE: compiletest does not know which version of \ + LLDB it is using" + ); + } + } + + // Parse debugger commands etc from test files + let dbg_cmds = DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + &["lldb"], + self.revision, + ) + .unwrap_or_else(|e| self.fatal(&e)); + + // Write debugger script: + // We don't want to hang when calling `quit` while the process is still running + let mut script_str = String::from("settings set auto-confirm true\n"); + + // Make LLDB emit its version, so we have it documented in the test output + script_str.push_str("version\n"); + + // Switch LLDB into "Rust mode" + let rust_src_root = + self.config.find_rust_src_root().expect("Could not find Rust source root"); + let rust_pp_module_rel_path = Path::new("./src/etc"); + let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path); + + script_str.push_str(&format!( + "command script import {}/lldb_lookup.py\n", + rust_pp_module_abs_path.to_str().unwrap() + )); + File::open(rust_pp_module_abs_path.join("lldb_commands")) + .and_then(|mut file| file.read_to_string(&mut script_str)) + .expect("Failed to read lldb_commands"); + + // Set breakpoints on every line that contains the string "#break" + let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); + for line in &dbg_cmds.breakpoint_lines { + script_str.push_str(&format!( + "breakpoint set --file '{}' --line {}\n", + source_file_name, line + )); + } + + // Append the other commands + for line in &dbg_cmds.commands { + script_str.push_str(line); + script_str.push('\n'); + } + + // Finally, quit the debugger + script_str.push_str("\nquit\n"); + + // Write the script into a file + debug!("script_str = {}", script_str); + self.dump_output_file(&script_str, "debugger.script"); + let debugger_script = self.make_out_name("debugger.script"); + + // Let LLDB execute the script via lldb_batchmode.py + let debugger_run_result = self.run_lldb(&exe_file, &debugger_script, &rust_src_root); + + if !debugger_run_result.status.success() { + self.fatal_proc_rec("Error while running LLDB", &debugger_run_result); + } + + if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { + self.fatal_proc_rec(&e, &debugger_run_result); + } + } + + fn run_lldb( + &self, + test_executable: &Path, + debugger_script: &Path, + rust_src_root: &Path, + ) -> ProcRes { + // Prepare the lldb_batchmode which executes the debugger script + let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py"); + let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { + format!("{pp}:{}", self.config.lldb_python_dir.as_ref().unwrap()) + } else { + self.config.lldb_python_dir.as_ref().unwrap().to_string() + }; + self.run_command_to_procres( + Command::new(&self.config.python) + .arg(&lldb_script_path) + .arg(test_executable) + .arg(debugger_script) + .env("PYTHONUNBUFFERED", "1") // Help debugging #78665 + .env("PYTHONPATH", pythonpath), + ) + } + + fn cleanup_debug_info_options(&self, options: &Vec) -> Vec { + // 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()]; + + options.iter().filter(|x| !options_to_remove.contains(x)).cloned().collect() + } +} diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs new file mode 100644 index 0000000000000..81b006292e492 --- /dev/null +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -0,0 +1,128 @@ +use super::{TestCx, WillExecute}; +use crate::errors; + +// FIXME(jieyouxu): `run_rpass_test` got hoisted out of this because apparently valgrind falls back +// to `run_rpass_test` if valgrind isn't available, which is questionable, but keeping it for +// refactoring changes to preserve current behavior. + +impl TestCx<'_> { + pub(super) fn run_incremental_test(&self) { + // Basic plan for a test incremental/foo/bar.rs: + // - load list of revisions rpass1, cfail2, rpass3 + // - each should begin with `cpass`, `rpass`, `cfail`, or `rfail` + // - if `cpass`, expect compilation to succeed, don't execute + // - if `rpass`, expect compilation and execution to succeed + // - if `cfail`, expect compilation to fail + // - if `rfail`, expect compilation to succeed and execution to fail + // - create a directory build/foo/bar.incremental + // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1 + // - because name of revision starts with "rpass", expect success + // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C cfail2 + // - because name of revision starts with "cfail", expect an error + // - load expected errors as usual, but filter for those that end in `[rfail2]` + // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass3 + // - because name of revision starts with "rpass", expect success + // - execute build/foo/bar.exe and save output + // + // FIXME -- use non-incremental mode as an oracle? That doesn't apply + // to #[rustc_dirty] and clean tests I guess + + let revision = self.revision.expect("incremental tests require a list of revisions"); + + // Incremental workproduct directory should have already been created. + let incremental_dir = self.props.incremental_dir.as_ref().unwrap(); + assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir"); + + if self.config.verbose { + print!("revision={:?} props={:#?}", revision, self.props); + } + + if revision.starts_with("cpass") { + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); + } + self.run_cpass_test(); + } else if revision.starts_with("rpass") { + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); + } + self.run_rpass_test(); + } else if revision.starts_with("rfail") { + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); + } + self.run_rfail_test(); + } else if revision.starts_with("cfail") { + self.run_cfail_test(); + } else { + self.fatal("revision name must begin with cpass, rpass, rfail, or cfail"); + } + } + + fn run_cpass_test(&self) { + let emit_metadata = self.should_emit_metadata(self.pass_mode()); + let proc_res = self.compile_test(WillExecute::No, emit_metadata); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + // FIXME(#41968): Move this check to tidy? + if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { + self.fatal("compile-pass tests with expected warnings should be moved to ui/"); + } + } + + fn run_cfail_test(&self) { + let pm = self.pass_mode(); + let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); + self.check_if_test_should_compile(&proc_res, pm); + self.check_no_compiler_crash(&proc_res, self.props.should_ice); + + let output_to_check = self.get_output(&proc_res); + let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); + if !expected_errors.is_empty() { + if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() + { + self.fatal("both error pattern and expected errors specified"); + } + self.check_expected_errors(expected_errors, &proc_res); + } else { + self.check_all_error_patterns(&output_to_check, &proc_res, pm); + } + if self.props.should_ice { + match proc_res.status.code() { + Some(101) => (), + _ => self.fatal("expected ICE"), + } + } + + self.check_forbid_output(&output_to_check, &proc_res); + } + + fn run_rfail_test(&self) { + let pm = self.pass_mode(); + let should_run = self.run_if_enabled(); + let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm)); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + if let WillExecute::Disabled = should_run { + return; + } + + let proc_res = self.exec_compiled_test(); + + // The value our Makefile configures valgrind to return on failure + const VALGRIND_ERR: i32 = 100; + if proc_res.status.code() == Some(VALGRIND_ERR) { + self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res); + } + + let output_to_check = self.get_output(&proc_res); + self.check_correct_failure_status(&proc_res); + self.check_all_error_patterns(&output_to_check, &proc_res, pm); + } +} diff --git a/src/tools/compiletest/src/runtest/js_doc.rs b/src/tools/compiletest/src/runtest/js_doc.rs new file mode 100644 index 0000000000000..68c74cd155c0e --- /dev/null +++ b/src/tools/compiletest/src/runtest/js_doc.rs @@ -0,0 +1,32 @@ +use std::process::Command; + +use super::TestCx; + +impl TestCx<'_> { + pub(super) fn run_js_doc_test(&self) { + if let Some(nodejs) = &self.config.nodejs { + let out_dir = self.output_base_dir(); + + self.document(&out_dir, &self.testpaths); + + let root = self.config.find_rust_src_root().unwrap(); + let file_stem = + self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem"); + let res = self.run_command_to_procres( + Command::new(&nodejs) + .arg(root.join("src/tools/rustdoc-js/tester.js")) + .arg("--doc-folder") + .arg(out_dir) + .arg("--crate-name") + .arg(file_stem.replace("-", "_")) + .arg("--test-file") + .arg(self.testpaths.file.with_extension("js")), + ); + if !res.status.success() { + self.fatal_proc_rec("rustdoc-js test failed!", &res); + } + } else { + self.fatal("no nodeJS"); + } + } +} diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs new file mode 100644 index 0000000000000..d1ec00357449d --- /dev/null +++ b/src/tools/compiletest/src/runtest/mir_opt.rs @@ -0,0 +1,155 @@ +use std::fs; +use std::path::{Path, PathBuf}; + +use glob::glob; +use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test}; +use tracing::debug; + +use super::{Emit, TestCx, WillExecute}; +use crate::compute_diff::write_diff; + +impl TestCx<'_> { + pub(super) fn run_mir_opt_test(&self) { + let pm = self.pass_mode(); + let should_run = self.should_run(pm); + + let mut test_info = files_for_miropt_test( + &self.testpaths.file, + self.config.get_pointer_width(), + self.config.target_cfg().panic.for_miropt_test_tools(), + ); + + let passes = std::mem::take(&mut test_info.passes); + + let proc_res = self.compile_test_with_passes(should_run, Emit::Mir, passes); + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + self.check_mir_dump(test_info); + + if let WillExecute::Yes = should_run { + let proc_res = self.exec_compiled_test(); + + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + } + } + + fn check_mir_dump(&self, test_info: MiroptTest) { + let test_dir = self.testpaths.file.parent().unwrap(); + let test_crate = + self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_"); + + let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info; + + if self.config.bless { + for e in + glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, suffix)).unwrap() + { + fs::remove_file(e.unwrap()).unwrap(); + } + for e in + glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, suffix)).unwrap() + { + fs::remove_file(e.unwrap()).unwrap(); + } + } + + for MiroptTestFile { 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() + ); + } + 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 _ = fs::remove_file(&expected_file); + 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 run_filecheck { + let output_path = self.output_base_name().with_extension("mir"); + let proc_res = self.verify_with_filecheck(&output_path); + if !proc_res.status.success() { + self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); + } + } + } + + fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String { + let to_full_path = |path: PathBuf| { + let full = self.get_mir_dump_dir().join(&path); + if !full.exists() { + panic!( + "the mir dump file for {} does not exist (requested in {})", + path.display(), + self.testpaths.file.display(), + ); + } + full + }; + let before = to_full_path(before); + let after = to_full_path(after); + debug!("comparing the contents of: {} with {}", before.display(), after.display()); + let before = fs::read_to_string(before).unwrap(); + let after = fs::read_to_string(after).unwrap(); + let before = self.normalize_output(&before, &[]); + let after = self.normalize_output(&after, &[]); + let mut dumped_string = String::new(); + for result in diff::lines(&before, &after) { + use std::fmt::Write; + match result { + diff::Result::Left(s) => writeln!(dumped_string, "- {}", s).unwrap(), + diff::Result::Right(s) => writeln!(dumped_string, "+ {}", s).unwrap(), + diff::Result::Both(s, _) => writeln!(dumped_string, " {}", s).unwrap(), + } + } + dumped_string + } + + fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) { + let t = |file| fs::metadata(file).unwrap().modified().unwrap(); + let source_file = &self.testpaths.file; + let output_time = t(output_file); + let source_time = t(source_file); + if source_time > output_time { + debug!("source file time: {:?} output file time: {:?}", source_time, output_time); + panic!( + "test source file `{}` is newer than potentially stale output file `{}`.", + source_file.display(), + test_name + ); + } + } +} diff --git a/src/tools/compiletest/src/runtest/pretty.rs b/src/tools/compiletest/src/runtest/pretty.rs new file mode 100644 index 0000000000000..40e767e84ef39 --- /dev/null +++ b/src/tools/compiletest/src/runtest/pretty.rs @@ -0,0 +1,104 @@ +use std::fs; + +use super::{ProcRes, ReadFrom, TestCx}; +use crate::util::logv; + +impl TestCx<'_> { + pub(super) fn run_pretty_test(&self) { + if self.props.pp_exact.is_some() { + logv(self.config, "testing for exact pretty-printing".to_owned()); + } else { + logv(self.config, "testing for converging pretty-printing".to_owned()); + } + + let rounds = match self.props.pp_exact { + Some(_) => 1, + None => 2, + }; + + let src = fs::read_to_string(&self.testpaths.file).unwrap(); + let mut srcs = vec![src]; + + let mut round = 0; + while round < rounds { + logv( + self.config, + format!("pretty-printing round {} revision {:?}", round, self.revision), + ); + let read_from = + if round == 0 { ReadFrom::Path } else { ReadFrom::Stdin(srcs[round].to_owned()) }; + + let proc_res = self.print_source(read_from, &self.props.pretty_mode); + if !proc_res.status.success() { + self.fatal_proc_rec( + &format!( + "pretty-printing failed in round {} revision {:?}", + round, self.revision + ), + &proc_res, + ); + } + + let ProcRes { stdout, .. } = proc_res; + srcs.push(stdout); + round += 1; + } + + let mut expected = match self.props.pp_exact { + Some(ref file) => { + let filepath = self.testpaths.file.parent().unwrap().join(file); + fs::read_to_string(&filepath).unwrap() + } + None => srcs[srcs.len() - 2].clone(), + }; + let mut actual = srcs[srcs.len() - 1].clone(); + + if self.props.pp_exact.is_some() { + // Now we have to care about line endings + let cr = "\r".to_owned(); + actual = actual.replace(&cr, ""); + expected = expected.replace(&cr, ""); + } + + if !self.config.bless { + self.compare_source(&expected, &actual); + } else if expected != actual { + let filepath_buf; + let filepath = match &self.props.pp_exact { + Some(file) => { + filepath_buf = self.testpaths.file.parent().unwrap().join(file); + &filepath_buf + } + None => &self.testpaths.file, + }; + fs::write(filepath, &actual).unwrap(); + } + + // If we're only making sure that the output matches then just stop here + if self.props.pretty_compare_only { + return; + } + + // Finally, let's make sure it actually appears to remain valid code + let proc_res = self.typecheck_source(actual); + if !proc_res.status.success() { + self.fatal_proc_rec("pretty-printed source does not typecheck", &proc_res); + } + + if !self.props.pretty_expanded { + return; + } + + // additionally, run `-Zunpretty=expanded` and try to build it. + let proc_res = self.print_source(ReadFrom::Path, "expanded"); + if !proc_res.status.success() { + self.fatal_proc_rec("pretty-printing (expanded) failed", &proc_res); + } + + let ProcRes { stdout: expanded_src, .. } = proc_res; + let proc_res = self.typecheck_source(expanded_src); + if !proc_res.status.success() { + self.fatal_proc_rec("pretty-printed source (expanded) does not typecheck", &proc_res); + } + } +} diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs new file mode 100644 index 0000000000000..75fe6a6baafa1 --- /dev/null +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -0,0 +1,526 @@ +use std::path::Path; +use std::process::{Command, Output, Stdio}; +use std::{env, fs}; + +use super::{ProcRes, TestCx}; +use crate::util::{copy_dir_all, dylib_env_var}; + +impl TestCx<'_> { + pub(super) fn run_rmake_test(&self) { + let test_dir = &self.testpaths.file; + if test_dir.join("rmake.rs").exists() { + self.run_rmake_v2_test(); + } else if test_dir.join("Makefile").exists() { + self.run_rmake_legacy_test(); + } else { + self.fatal("failed to find either `rmake.rs` or `Makefile`") + } + } + + fn run_rmake_legacy_test(&self) { + let cwd = env::current_dir().unwrap(); + let src_root = self.config.src_base.parent().unwrap().parent().unwrap(); + let src_root = cwd.join(&src_root); + + let tmpdir = cwd.join(self.output_base_name()); + if tmpdir.exists() { + self.aggressive_rm_rf(&tmpdir).unwrap(); + } + fs::create_dir_all(&tmpdir).unwrap(); + + let host = &self.config.host; + let make = if host.contains("dragonfly") + || host.contains("freebsd") + || host.contains("netbsd") + || host.contains("openbsd") + || host.contains("aix") + { + "gmake" + } else { + "make" + }; + + let mut cmd = Command::new(make); + cmd.current_dir(&self.testpaths.file) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .env("TARGET", &self.config.target) + .env("PYTHON", &self.config.python) + .env("S", src_root) + .env("RUST_BUILD_STAGE", &self.config.stage_id) + .env("RUSTC", cwd.join(&self.config.rustc_path)) + .env("TMPDIR", &tmpdir) + .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) + .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) + .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) + .env("LLVM_COMPONENTS", &self.config.llvm_components) + // We for sure don't want these tests to run in parallel, so make + // sure they don't have access to these vars if we run via `make` + // at the top level + .env_remove("MAKEFLAGS") + .env_remove("MFLAGS") + .env_remove("CARGO_MAKEFLAGS"); + + if let Some(ref cargo) = self.config.cargo_path { + cmd.env("CARGO", cwd.join(cargo)); + } + + if let Some(ref rustdoc) = self.config.rustdoc_path { + cmd.env("RUSTDOC", cwd.join(rustdoc)); + } + + if let Some(ref node) = self.config.nodejs { + cmd.env("NODE", node); + } + + if let Some(ref linker) = self.config.target_linker { + cmd.env("RUSTC_LINKER", linker); + } + + if let Some(ref clang) = self.config.run_clang_based_tests_with { + cmd.env("CLANG", clang); + } + + if let Some(ref filecheck) = self.config.llvm_filecheck { + cmd.env("LLVM_FILECHECK", filecheck); + } + + if let Some(ref llvm_bin_dir) = self.config.llvm_bin_dir { + cmd.env("LLVM_BIN_DIR", llvm_bin_dir); + } + + if let Some(ref remote_test_client) = self.config.remote_test_client { + cmd.env("REMOTE_TEST_CLIENT", remote_test_client); + } + + // We don't want RUSTFLAGS set from the outside to interfere with + // compiler flags set in the test cases: + cmd.env_remove("RUSTFLAGS"); + + // Use dynamic musl for tests because static doesn't allow creating dylibs + if self.config.host.contains("musl") { + cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1"); + } + + if self.config.bless { + cmd.env("RUSTC_BLESS_TEST", "--bless"); + // Assume this option is active if the environment variable is "defined", with _any_ value. + // As an example, a `Makefile` can use this option by: + // + // ifdef RUSTC_BLESS_TEST + // cp "$(TMPDIR)"/actual_something.ext expected_something.ext + // else + // $(DIFF) expected_something.ext "$(TMPDIR)"/actual_something.ext + // endif + } + + if self.config.target.contains("msvc") && !self.config.cc.is_empty() { + // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` + // and that `lib.exe` lives next to it. + let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); + + // MSYS doesn't like passing flags of the form `/foo` as it thinks it's + // a path and instead passes `C:\msys64\foo`, so convert all + // `/`-arguments to MSVC here to `-` arguments. + let cflags = self + .config + .cflags + .split(' ') + .map(|s| s.replace("/", "-")) + .collect::>() + .join(" "); + let cxxflags = self + .config + .cxxflags + .split(' ') + .map(|s| s.replace("/", "-")) + .collect::>() + .join(" "); + + cmd.env("IS_MSVC", "1") + .env("IS_WINDOWS", "1") + .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) + .env("MSVC_LIB_PATH", format!("{}", lib.display())) + .env("CC", format!("'{}' {}", self.config.cc, cflags)) + .env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags)); + } else { + cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) + .env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags)) + .env("AR", &self.config.ar); + + if self.config.target.contains("windows") { + cmd.env("IS_WINDOWS", "1"); + } + } + + let (output, truncated) = + self.read2_abbreviated(cmd.spawn().expect("failed to spawn `make`")); + if !output.status.success() { + let res = ProcRes { + status: output.status, + stdout: String::from_utf8_lossy(&output.stdout).into_owned(), + stderr: String::from_utf8_lossy(&output.stderr).into_owned(), + truncated, + cmdline: format!("{:?}", cmd), + }; + self.fatal_proc_rec("make failed", &res); + } + } + + fn run_rmake_v2_test(&self) { + // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe + // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust + // library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`. + // + // 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support` + // library. + // 2. We need to run the recipe binary. + + // So we assume the rust-lang/rust project setup looks like the following (our `.` is the + // top-level directory, irrelevant entries to our purposes omitted): + // + // ``` + // . // <- `source_root` + // ├── build/ // <- `build_root` + // ├── compiler/ + // ├── library/ + // ├── src/ + // │ └── tools/ + // │ └── run_make_support/ + // └── tests + // └── run-make/ + // ``` + + // `source_root` is the top-level directory containing the rust-lang/rust checkout. + let source_root = + self.config.find_rust_src_root().expect("could not determine rust source root"); + // `self.config.build_base` is actually the build base folder + "test" + test suite name, it + // looks like `build//test/run-make`. But we want `build//`. Note + // that the `build` directory does not need to be called `build`, nor does it need to be + // under `source_root`, so we must compute it based off of `self.config.build_base`. + let build_root = + self.config.build_base.parent().and_then(Path::parent).unwrap().to_path_buf(); + + // We construct the following directory tree for each rmake.rs test: + // ``` + // / + // rmake.exe + // rmake_out/ + // ``` + // having the recipe executable separate from the output artifacts directory allows the + // recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove + // a currently running executable because the recipe executable is not under the + // `rmake_out/` directory. + // + // This setup intentionally diverges from legacy Makefile run-make tests. + let base_dir = self.output_base_name(); + if base_dir.exists() { + self.aggressive_rm_rf(&base_dir).unwrap(); + } + let rmake_out_dir = base_dir.join("rmake_out"); + fs::create_dir_all(&rmake_out_dir).unwrap(); + + // Copy all input files (apart from rmake.rs) to the temporary directory, + // so that the input directory structure from `tests/run-make/` is mirrored + // to the `rmake_out` directory. + for path in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) { + let path = path.unwrap().path().to_path_buf(); + if path.file_name().is_some_and(|s| s != "rmake.rs") { + let target = rmake_out_dir.join(path.strip_prefix(&self.testpaths.file).unwrap()); + if path.is_dir() { + copy_dir_all(&path, target).unwrap(); + } else { + fs::copy(&path, target).unwrap(); + } + } + } + + // `self.config.stage_id` looks like `stage1-`, but we only want + // the `stage1` part as that is what the output directories of bootstrap are prefixed with. + // Note that this *assumes* build layout from bootstrap is produced as: + // + // ``` + // build// // <- this is `build_root` + // ├── stage0 + // ├── stage0-bootstrap-tools + // ├── stage0-codegen + // ├── stage0-rustc + // ├── stage0-std + // ├── stage0-sysroot + // ├── stage0-tools + // ├── stage0-tools-bin + // ├── stage1 + // ├── stage1-std + // ├── stage1-tools + // ├── stage1-tools-bin + // └── test + // ``` + // FIXME(jieyouxu): improve the communication between bootstrap and compiletest here so + // we don't have to hack out a `stageN`. + let stage = self.config.stage_id.split('-').next().unwrap(); + + // In order to link in the support library as a rlib when compiling recipes, we need three + // paths: + // 1. Path of the built support library rlib itself. + // 2. Path of the built support library's dependencies directory. + // 3. Path of the built support library's dependencies' dependencies directory. + // + // The paths look like + // + // ``` + // build// + // ├── stageN-tools-bin/ + // │ └── librun_make_support.rlib // <- support rlib itself + // ├── stageN-tools/ + // │ ├── release/deps/ // <- deps of deps + // │ └── /release/deps/ // <- deps + // ``` + // + // FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the + // support lib and its deps are organized, can't we copy them to the tools-bin dir as + // well?), but this seems to work for now. + + let stage_tools_bin = build_root.join(format!("{stage}-tools-bin")); + let support_lib_path = stage_tools_bin.join("librun_make_support.rlib"); + + let stage_tools = build_root.join(format!("{stage}-tools")); + let support_lib_deps = stage_tools.join(&self.config.host).join("release").join("deps"); + let support_lib_deps_deps = stage_tools.join("release").join("deps"); + + // To compile the recipe with rustc, we need to provide suitable dynamic library search + // paths to rustc. This includes both: + // 1. The "base" dylib search paths that was provided to compiletest, e.g. `LD_LIBRARY_PATH` + // on some linux distros. + // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc. + + let base_dylib_search_paths = + Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); + + let host_dylib_search_paths = { + let mut paths = vec![self.config.compile_lib_path.clone()]; + paths.extend(base_dylib_search_paths.iter().cloned()); + paths + }; + + // Calculate the paths of the recipe binary. As previously discussed, this is placed at + // `/` with `bin_name` being `rmake` or `rmake.exe` depending on + // platform. + let recipe_bin = { + let mut p = base_dir.join("rmake"); + p.set_extension(env::consts::EXE_EXTENSION); + p + }; + + let mut rustc = Command::new(&self.config.rustc_path); + rustc + .arg("-o") + .arg(&recipe_bin) + // Specify library search paths for `run_make_support`. + .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy())) + .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy())) + .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) + // Provide `run_make_support` as extern prelude, so test writers don't need to write + // `extern run_make_support;`. + .arg("--extern") + .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) + .arg("--edition=2021") + .arg(&self.testpaths.file.join("rmake.rs")) + // Provide necessary library search paths for rustc. + .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); + + // In test code we want to be very pedantic about values being silently discarded that are + // annotated with `#[must_use]`. + rustc.arg("-Dunused_must_use"); + + // > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc + // > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is + // > compiled using the bootstrap rustc wrapper which sets `--sysroot + // > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile + // > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the + // > `libstd.rlib` against which `librun_make_support.rlib` is compiled. + // + // The gist here is that we have to pass the proper stage0 sysroot if we want + // + // ``` + // $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0 + // ``` + // + // to work correctly. + // + // See for more background. + if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { + let stage0_sysroot = build_root.join("stage0-sysroot"); + rustc.arg("--sysroot").arg(&stage0_sysroot); + } + + // Now run rustc to build the recipe. + let res = self.run_command_to_procres(&mut rustc); + if !res.status.success() { + self.fatal_proc_rec("run-make test failed: could not build `rmake.rs` recipe", &res); + } + + // To actually run the recipe, we have to provide the recipe with a bunch of information + // provided through env vars. + + // Compute stage-specific standard library paths. + let stage_std_path = build_root.join(&stage).join("lib"); + + // Compute dynamic library search paths for recipes. + let recipe_dylib_search_paths = { + let mut paths = base_dylib_search_paths.clone(); + paths.push(support_lib_path.parent().unwrap().to_path_buf()); + paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); + paths + }; + + // Compute runtime library search paths for recipes. This is target-specific. + let target_runtime_dylib_search_paths = { + let mut paths = vec![rmake_out_dir.clone()]; + paths.extend(base_dylib_search_paths.iter().cloned()); + paths + }; + + // FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and + // `TARGET_RPATH_DIR`, it is **extremely** confusing! + let mut cmd = Command::new(&recipe_bin); + cmd.current_dir(&rmake_out_dir) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + // Provide the target-specific env var that is used to record dylib search paths. For + // example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows. + .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) + // Provide the dylib search paths. + .env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap()) + // Provide runtime dylib search paths. + .env("TARGET_RPATH_ENV", &env::join_paths(target_runtime_dylib_search_paths).unwrap()) + // Provide the target. + .env("TARGET", &self.config.target) + // Some tests unfortunately still need Python, so provide path to a Python interpreter. + .env("PYTHON", &self.config.python) + // Provide path to checkout root. This is the top-level directory containing + // rust-lang/rust checkout. + .env("SOURCE_ROOT", &source_root) + // Provide path to stage-corresponding rustc. + .env("RUSTC", &self.config.rustc_path) + // Provide the directory to libraries that are needed to run the *compiler*. This is not + // to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the + // recipe wants to invoke rustc. + .env("HOST_RPATH_DIR", &self.config.compile_lib_path) + // Provide the directory to libraries that might be needed to run compiled binaries + // (further compiled by the recipe!). + .env("TARGET_RPATH_DIR", &self.config.run_lib_path) + // Provide which LLVM components are available (e.g. which LLVM components are provided + // through a specific CI runner). + .env("LLVM_COMPONENTS", &self.config.llvm_components); + + if let Some(ref cargo) = self.config.cargo_path { + cmd.env("CARGO", source_root.join(cargo)); + } + + if let Some(ref rustdoc) = self.config.rustdoc_path { + cmd.env("RUSTDOC", source_root.join(rustdoc)); + } + + if let Some(ref node) = self.config.nodejs { + cmd.env("NODE", node); + } + + if let Some(ref linker) = self.config.target_linker { + cmd.env("RUSTC_LINKER", linker); + } + + if let Some(ref clang) = self.config.run_clang_based_tests_with { + cmd.env("CLANG", clang); + } + + if let Some(ref filecheck) = self.config.llvm_filecheck { + cmd.env("LLVM_FILECHECK", filecheck); + } + + if let Some(ref llvm_bin_dir) = self.config.llvm_bin_dir { + cmd.env("LLVM_BIN_DIR", llvm_bin_dir); + } + + if let Some(ref remote_test_client) = self.config.remote_test_client { + cmd.env("REMOTE_TEST_CLIENT", remote_test_client); + } + + // We don't want RUSTFLAGS set from the outside to interfere with + // compiler flags set in the test cases: + cmd.env_remove("RUSTFLAGS"); + + // Use dynamic musl for tests because static doesn't allow creating dylibs + if self.config.host.contains("musl") { + cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1"); + } + + if self.config.bless { + // If we're running in `--bless` mode, set an environment variable to tell + // `run_make_support` to bless snapshot files instead of checking them. + // + // The value is this test's source directory, because the support code + // will need that path in order to bless the _original_ snapshot files, + // not the copies in `rmake_out`. + // (See .) + cmd.env("RUSTC_BLESS_TEST", &self.testpaths.file); + } + + if self.config.target.contains("msvc") && !self.config.cc.is_empty() { + // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` + // and that `lib.exe` lives next to it. + let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); + + // MSYS doesn't like passing flags of the form `/foo` as it thinks it's + // a path and instead passes `C:\msys64\foo`, so convert all + // `/`-arguments to MSVC here to `-` arguments. + let cflags = self + .config + .cflags + .split(' ') + .map(|s| s.replace("/", "-")) + .collect::>() + .join(" "); + let cxxflags = self + .config + .cxxflags + .split(' ') + .map(|s| s.replace("/", "-")) + .collect::>() + .join(" "); + + cmd.env("IS_MSVC", "1") + .env("IS_WINDOWS", "1") + .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) + .env("MSVC_LIB_PATH", format!("{}", lib.display())) + // Note: we diverge from legacy run_make and don't lump `CC` the compiler and + // default flags together. + .env("CC_DEFAULT_FLAGS", &cflags) + .env("CC", &self.config.cc) + .env("CXX_DEFAULT_FLAGS", &cxxflags) + .env("CXX", &self.config.cxx); + } else { + cmd.env("CC_DEFAULT_FLAGS", &self.config.cflags) + .env("CC", &self.config.cc) + .env("CXX_DEFAULT_FLAGS", &self.config.cxxflags) + .env("CXX", &self.config.cxx) + .env("AR", &self.config.ar); + + if self.config.target.contains("windows") { + cmd.env("IS_WINDOWS", "1"); + } + } + + let (Output { stdout, stderr, status }, truncated) = + self.read2_abbreviated(cmd.spawn().expect("failed to spawn `rmake`")); + if !status.success() { + let res = ProcRes { + status, + stdout: String::from_utf8_lossy(&stdout).into_owned(), + stderr: String::from_utf8_lossy(&stderr).into_owned(), + truncated, + cmdline: format!("{:?}", cmd), + }; + self.fatal_proc_rec("rmake recipe failed to complete", &res); + } + } +} diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs new file mode 100644 index 0000000000000..3f33862d2cfe2 --- /dev/null +++ b/src/tools/compiletest/src/runtest/rustdoc.rs @@ -0,0 +1,34 @@ +use std::process::Command; + +use super::{TestCx, remove_and_create_dir_all}; + +impl TestCx<'_> { + pub(super) fn run_rustdoc_test(&self) { + assert!(self.revision.is_none(), "revisions not relevant here"); + + let out_dir = self.output_base_dir(); + remove_and_create_dir_all(&out_dir); + + let proc_res = self.document(&out_dir, &self.testpaths); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc failed!", &proc_res); + } + + if self.props.check_test_line_numbers_match { + self.check_rustdoc_test_option(proc_res); + } else { + let root = self.config.find_rust_src_root().unwrap(); + let mut cmd = Command::new(&self.config.python); + cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file); + if self.config.bless { + cmd.arg("--bless"); + } + let res = self.run_command_to_procres(&mut cmd); + if !res.status.success() { + self.fatal_proc_rec_with_ctx("htmldocck failed!", &res, |mut this| { + this.compare_to_default_rustdoc(&out_dir) + }); + } + } + } +} diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs new file mode 100644 index 0000000000000..31fdb0a5d13bd --- /dev/null +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -0,0 +1,48 @@ +use std::process::Command; + +use super::{TestCx, remove_and_create_dir_all}; + +impl TestCx<'_> { + pub(super) fn run_rustdoc_json_test(&self) { + //FIXME: Add bless option. + + assert!(self.revision.is_none(), "revisions not relevant here"); + + let out_dir = self.output_base_dir(); + remove_and_create_dir_all(&out_dir); + + let proc_res = self.document(&out_dir, &self.testpaths); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc failed!", &proc_res); + } + + let root = self.config.find_rust_src_root().unwrap(); + let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); + json_out.set_extension("json"); + let res = self.run_command_to_procres( + Command::new(self.config.jsondocck_path.as_ref().unwrap()) + .arg("--doc-dir") + .arg(root.join(&out_dir)) + .arg("--template") + .arg(&self.testpaths.file), + ); + + if !res.status.success() { + self.fatal_proc_rec_with_ctx("jsondocck failed!", &res, |_| { + println!("Rustdoc Output:"); + proc_res.print_info(); + }) + } + + let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); + json_out.set_extension("json"); + + let res = self.run_command_to_procres( + Command::new(self.config.jsondoclint_path.as_ref().unwrap()).arg(&json_out), + ); + + if !res.status.success() { + self.fatal_proc_rec("jsondoclint failed!", &res); + } + } +} diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs new file mode 100644 index 0000000000000..bd8ef952a863b --- /dev/null +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -0,0 +1,233 @@ +use std::collections::HashSet; +use std::fs::OpenOptions; +use std::io::Write; + +use rustfix::{Filter, apply_suggestions, get_suggestions_from_json}; +use tracing::debug; + +use super::{ + AllowUnused, Emit, ErrorKind, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, + TestOutput, Truncated, UI_FIXED, WillExecute, +}; +use crate::{errors, json}; + +impl TestCx<'_> { + pub(super) fn run_ui_test(&self) { + 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, Emit::Metadata, pm, Vec::new()); + self.check_if_test_should_compile(&proc_res, pm); + } + + let pm = self.pass_mode(); + let should_run = self.should_run(pm); + let emit_metadata = self.should_emit_metadata(pm); + let proc_res = self.compile_test(should_run, emit_metadata); + self.check_if_test_should_compile(&proc_res, pm); + if matches!(proc_res.truncated, Truncated::Yes) + && !self.props.dont_check_compiler_stdout + && !self.props.dont_check_compiler_stderr + { + self.fatal_proc_rec( + "compiler output got truncated, cannot compare with reference file", + &proc_res, + ); + } + + // if the user specified a format in the ui test + // print the output to the stderr file, otherwise extract + // the rendered error messages from json and print them + let explicit = self.props.compile_flags.iter().any(|s| s.contains("--error-format")); + + let expected_fixed = self.load_expected_output(UI_FIXED); + + self.check_and_prune_duplicate_outputs(&proc_res, &[], &[]); + + let mut errors = self.load_compare_outputs(&proc_res, TestOutput::Compile, explicit); + let rustfix_input = json::rustfix_diagnostics_only(&proc_res.stderr); + + if self.config.compare_mode.is_some() { + // don't test rustfix with nll right now + } else if self.config.rustfix_coverage { + // Find out which tests have `MachineApplicable` suggestions but are missing + // `run-rustfix` or `run-rustfix-only-machine-applicable` headers. + // + // This will return an empty `Vec` in case the executed test file has a + // `compile-flags: --error-format=xxxx` header with a value other than `json`. + let suggestions = get_suggestions_from_json( + &rustfix_input, + &HashSet::new(), + Filter::MachineApplicableOnly, + ) + .unwrap_or_default(); + if !suggestions.is_empty() + && !self.props.run_rustfix + && !self.props.rustfix_only_machine_applicable + { + let mut coverage_file_path = self.config.build_base.clone(); + coverage_file_path.push("rustfix_missing_coverage.txt"); + debug!("coverage_file_path: {}", coverage_file_path.display()); + + let mut file = OpenOptions::new() + .create(true) + .append(true) + .open(coverage_file_path.as_path()) + .expect("could not create or open file"); + + if let Err(e) = writeln!(file, "{}", self.testpaths.file.display()) { + panic!("couldn't write to {}: {e:?}", coverage_file_path.display()); + } + } + } else if self.props.run_rustfix { + // Apply suggestions from rustc to the code itself + let unfixed_code = self.load_expected_output_from_path(&self.testpaths.file).unwrap(); + let suggestions = get_suggestions_from_json( + &rustfix_input, + &HashSet::new(), + if self.props.rustfix_only_machine_applicable { + Filter::MachineApplicableOnly + } else { + Filter::Everything + }, + ) + .unwrap(); + let fixed_code = apply_suggestions(&unfixed_code, &suggestions).unwrap_or_else(|e| { + panic!( + "failed to apply suggestions for {:?} with rustfix: {}", + self.testpaths.file, e + ) + }); + + errors += self.compare_output("fixed", &fixed_code, &expected_fixed); + } else if !expected_fixed.is_empty() { + panic!( + "the `//@ run-rustfix` directive wasn't found but a `*.fixed` \ + file was found" + ); + } + + if errors > 0 { + println!("To update references, rerun the tests and pass the `--bless` flag"); + let relative_path_to_file = + self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap()); + println!( + "To only update this specific test, also pass `--test-args {}`", + relative_path_to_file.display(), + ); + self.fatal_proc_rec( + &format!("{} errors occurred comparing output.", errors), + &proc_res, + ); + } + + let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); + + if let WillExecute::Yes = should_run { + let proc_res = self.exec_compiled_test(); + let run_output_errors = if self.props.check_run_results { + self.load_compare_outputs(&proc_res, TestOutput::Run, explicit) + } else { + 0 + }; + if run_output_errors > 0 { + self.fatal_proc_rec( + &format!("{} errors occurred comparing run output.", run_output_errors), + &proc_res, + ); + } + if self.should_run_successfully(pm) { + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + } else if proc_res.status.success() { + self.fatal_proc_rec("test run succeeded!", &proc_res); + } + + if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() + { + // "// error-pattern" comments + let output_to_check = self.get_output(&proc_res); + self.check_all_error_patterns(&output_to_check, &proc_res, pm); + } + } + + debug!( + "run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \ + proc_res.status={:?} props.error_patterns={:?}", + explicit, + self.config.compare_mode, + expected_errors, + proc_res.status, + self.props.error_patterns + ); + + let check_patterns = should_run == WillExecute::No + && (!self.props.error_patterns.is_empty() + || !self.props.regex_error_patterns.is_empty()); + if !explicit && self.config.compare_mode.is_none() { + let check_annotations = !check_patterns || !expected_errors.is_empty(); + + if check_annotations { + // "//~ERROR comments" + self.check_expected_errors(expected_errors, &proc_res); + } + } else if explicit && !expected_errors.is_empty() { + let msg = format!( + "line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead", + expected_errors[0].line_num, + expected_errors[0].kind.unwrap_or(ErrorKind::Error), + ); + self.fatal(&msg); + } + if check_patterns { + // "// error-pattern" comments + let output_to_check = self.get_output(&proc_res); + self.check_all_error_patterns(&output_to_check, &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( + &self.expected_output_path(UI_FIXED), + TargetLocation::ThisFile(self.make_exe_name()), + emit_metadata, + AllowUnused::No, + LinkToAux::Yes, + Vec::new(), + ); + + // If a test is revisioned, it's fixed source file can be named "a.foo.fixed", which, + // well, "a.foo" isn't a valid crate name. So we explicitly mangle the test name + // (including the revision) here to avoid the test writer having to manually specify a + // `#![crate_name = "..."]` as a workaround. This is okay since we're only checking if + // the fixed code is compilable. + if self.revision.is_some() { + let crate_name = + self.testpaths.file.file_stem().expect("test must have a file stem"); + // crate name must be alphanumeric or `_`. + let crate_name = + crate_name.to_str().expect("crate name implies file name must be valid UTF-8"); + // replace `a.foo` -> `a__foo` for crate name purposes. + // replace `revision-name-with-dashes` -> `revision_name_with_underscore` + let crate_name = crate_name.replace('.', "__"); + let crate_name = crate_name.replace('-', "_"); + rustc.arg("--crate-name"); + rustc.arg(crate_name); + } + + let res = self.compose_and_run_compiler(rustc, None, self.testpaths); + if !res.status.success() { + self.fatal_proc_rec("failed to compile fixed code", &res); + } + if !res.stderr.is_empty() + && !self.props.rustfix_only_machine_applicable + && !json::rustfix_diagnostics_only(&res.stderr).is_empty() + { + self.fatal_proc_rec("fixed code is still producing diagnostics", &res); + } + } + } +} diff --git a/src/tools/compiletest/src/runtest/valgrind.rs b/src/tools/compiletest/src/runtest/valgrind.rs new file mode 100644 index 0000000000000..8d72c4be9ff29 --- /dev/null +++ b/src/tools/compiletest/src/runtest/valgrind.rs @@ -0,0 +1,34 @@ +use super::{Emit, TestCx, WillExecute}; + +impl TestCx<'_> { + pub(super) fn run_valgrind_test(&self) { + assert!(self.revision.is_none(), "revisions not relevant here"); + + // FIXME(jieyouxu): does this really make any sense? If a valgrind test isn't testing + // valgrind, what is it even testing? + if self.config.valgrind_path.is_none() { + assert!(!self.config.force_valgrind); + return self.run_rpass_test(); + } + + let should_run = self.run_if_enabled(); + let mut proc_res = self.compile_test(should_run, Emit::None); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + if let WillExecute::Disabled = should_run { + return; + } + + let mut new_config = self.config.clone(); + new_config.runner = new_config.valgrind_path.clone(); + let new_cx = TestCx { config: &new_config, ..*self }; + proc_res = new_cx.exec_compiled_test(); + + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + } +} diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index 4729b327de594..c779dd0583c4e 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -2,10 +2,10 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Write as _}; use std::sync::OnceLock; -use anyhow::{anyhow, Context}; +use anyhow::{Context, anyhow}; use regex::Regex; -use crate::parser::{unescape_llvm_string_contents, Parser}; +use crate::parser::{Parser, unescape_llvm_string_contents}; pub(crate) fn dump_covfun_mappings( llvm_ir: &str, diff --git a/src/tools/coverage-dump/src/prf_names.rs b/src/tools/coverage-dump/src/prf_names.rs index c5f9c4ce54cc5..96d097c79a315 100644 --- a/src/tools/coverage-dump/src/prf_names.rs +++ b/src/tools/coverage-dump/src/prf_names.rs @@ -4,7 +4,7 @@ use std::sync::OnceLock; use anyhow::{anyhow, ensure}; use regex::Regex; -use crate::parser::{unescape_llvm_string_contents, Parser}; +use crate::parser::{Parser, unescape_llvm_string_contents}; /// Scans through the contents of an LLVM IR assembly file to find `__llvm_prf_names` /// entries, decodes them, and creates a table that maps name hash values to diff --git a/src/tools/enzyme b/src/tools/enzyme new file mode 160000 index 0000000000000..2fe5164a2423d --- /dev/null +++ b/src/tools/enzyme @@ -0,0 +1 @@ +Subproject commit 2fe5164a2423dd67ef25e2c4fb204fd06362494b diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 53a26112911db..58224aed14879 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -12,7 +12,7 @@ use std::io::Write; use std::path::{Path, PathBuf}; use std::str::FromStr; -use mdbook::book::{parse_summary, BookItem, Chapter}; +use mdbook::book::{BookItem, Chapter, parse_summary}; use mdbook::{Config, MDBook}; use rustc_errors::codes::DIAGNOSTICS; diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs index c85e4aa371a2a..31b18c3dc1035 100644 --- a/src/tools/generate-copyright/src/cargo_metadata.rs +++ b/src/tools/generate-copyright/src/cargo_metadata.rs @@ -99,15 +99,12 @@ pub fn get_metadata( } // otherwise it's an out-of-tree dependency let package_id = Package { name: package.name, version: package.version.to_string() }; - output.insert( - package_id, - PackageMetadata { - license: package.license.unwrap_or_else(|| String::from("Unspecified")), - authors: package.authors, - notices: BTreeMap::new(), - is_in_libstd: None, - }, - ); + output.insert(package_id, PackageMetadata { + license: package.license.unwrap_or_else(|| String::from("Unspecified")), + authors: package.authors, + notices: BTreeMap::new(), + is_in_libstd: None, + }); } } diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs index ecfbb1955e779..5cdc4d53ab500 100644 --- a/src/tools/html-checker/main.rs +++ b/src/tools/html-checker/main.rs @@ -31,7 +31,7 @@ fn check_html_file(file: &Path) -> usize { .arg("--mute-id") // this option is useful in case we want to mute more warnings .arg("yes") .arg("--new-blocklevel-tags") - .arg("rustdoc-search") // custom elements + .arg("rustdoc-search,rustdoc-toolbar") // custom elements .arg("--mute") .arg(&to_mute_s) .arg(file); diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index 7d6ec475badd4..51146831efa40 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -5,7 +5,7 @@ use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary}; pub(crate) enum Kind { Module, ExternCrate, - Import, + Use, Struct, StructField, Union, @@ -18,7 +18,7 @@ pub(crate) enum Kind { TraitAlias, Impl, Static, - ForeignType, + ExternType, Macro, ProcAttribute, ProcDerive, @@ -36,7 +36,7 @@ impl Kind { match self { Module => true, ExternCrate => true, - Import => true, + Use => true, Union => true, Struct => true, Enum => true, @@ -50,7 +50,7 @@ impl Kind { Macro => true, ProcMacro => true, Primitive => true, - ForeignType => true, + ExternType => true, // FIXME(adotinthevoid): I'm not sure if these are correct Keyword => false, @@ -69,7 +69,7 @@ impl Kind { pub fn can_appear_in_import(self) -> bool { match self { Kind::Variant => true, - Kind::Import => false, + Kind::Use => false, other => other.can_appear_in_mod(), } } @@ -90,7 +90,7 @@ impl Kind { Kind::Module => false, Kind::ExternCrate => false, - Kind::Import => false, + Kind::Use => false, Kind::Struct => false, Kind::StructField => false, Kind::Union => false, @@ -102,7 +102,7 @@ impl Kind { Kind::TraitAlias => false, Kind::Impl => false, Kind::Static => false, - Kind::ForeignType => false, + Kind::ExternType => false, Kind::Macro => false, Kind::ProcAttribute => false, Kind::ProcDerive => false, @@ -135,7 +135,7 @@ impl Kind { use Kind::*; match i.inner { ItemEnum::Module(_) => Module, - ItemEnum::Import(_) => Import, + ItemEnum::Use(_) => Use, ItemEnum::Union(_) => Union, ItemEnum::Struct(_) => Struct, ItemEnum::StructField(_) => StructField, @@ -151,7 +151,7 @@ impl Kind { ItemEnum::Macro(_) => Macro, ItemEnum::ProcMacro(_) => ProcMacro, ItemEnum::Primitive(_) => Primitive, - ItemEnum::ForeignType => ForeignType, + ItemEnum::ExternType => ExternType, ItemEnum::ExternCrate { .. } => ExternCrate, ItemEnum::AssocConst { .. } => AssocConst, ItemEnum::AssocType { .. } => AssocType, @@ -166,10 +166,10 @@ impl Kind { ItemKind::Constant => Constant, ItemKind::Enum => Enum, ItemKind::ExternCrate => ExternCrate, - ItemKind::ForeignType => ForeignType, + ItemKind::ExternType => ExternType, ItemKind::Function => Function, ItemKind::Impl => Impl, - ItemKind::Import => Import, + ItemKind::Use => Use, ItemKind::Keyword => Keyword, ItemKind::Macro => Macro, ItemKind::Module => Module, diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs index aaaba78cb46d1..5cbf346086062 100644 --- a/src/tools/jsondoclint/src/main.rs +++ b/src/tools/jsondoclint/src/main.rs @@ -1,10 +1,10 @@ use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; -use anyhow::{bail, Result}; +use anyhow::{Result, bail}; use clap::Parser; use fs_err as fs; -use rustdoc_json_types::{Crate, Id, FORMAT_VERSION}; +use rustdoc_json_types::{Crate, FORMAT_VERSION, Id}; use serde::Serialize; use serde_json::Value; diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 0ffb96bef29ba..b04919bdd3edc 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -2,15 +2,16 @@ use std::collections::HashSet; use std::hash::Hash; use rustdoc_json_types::{ - Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs, - GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, ItemSummary, Module, Path, - Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeAlias, - TypeBinding, TypeBindingKind, Union, Variant, VariantKind, WherePredicate, + AssocItemConstraint, AssocItemConstraintKind, Constant, Crate, DynTrait, Enum, Function, + FunctionPointer, FunctionSignature, GenericArg, GenericArgs, GenericBound, GenericParamDef, + Generics, Id, Impl, ItemEnum, ItemSummary, Module, Path, Primitive, ProcMacro, Static, Struct, + StructKind, Term, Trait, TraitAlias, Type, TypeAlias, Union, Use, Variant, VariantKind, + WherePredicate, }; use serde_json::Value; use crate::item_kind::Kind; -use crate::{json_find, Error, ErrorKind}; +use crate::{Error, ErrorKind, json_find}; // This is a rustc implementation detail that we rely on here const LOCAL_CRATE_ID: u32 = 0; @@ -90,7 +91,7 @@ impl<'a> Validator<'a> { item.links.values().for_each(|id| self.add_any_id(id)); match &item.inner { - ItemEnum::Import(x) => self.check_import(x), + ItemEnum::Use(x) => self.check_use(x), ItemEnum::Union(x) => self.check_union(x), ItemEnum::Struct(x) => self.check_struct(x), ItemEnum::StructField(x) => self.check_struct_field(x), @@ -106,18 +107,18 @@ impl<'a> Validator<'a> { self.check_constant(const_); } ItemEnum::Static(x) => self.check_static(x), - ItemEnum::ForeignType => {} // nop + ItemEnum::ExternType => {} // nop ItemEnum::Macro(x) => self.check_macro(x), ItemEnum::ProcMacro(x) => self.check_proc_macro(x), ItemEnum::Primitive(x) => self.check_primitive_type(x), ItemEnum::Module(x) => self.check_module(x, id), // FIXME: Why don't these have their own structs? ItemEnum::ExternCrate { .. } => {} - ItemEnum::AssocConst { type_, default: _ } => self.check_type(type_), - ItemEnum::AssocType { generics, bounds, default } => { + ItemEnum::AssocConst { type_, value: _ } => self.check_type(type_), + ItemEnum::AssocType { generics, bounds, type_ } => { self.check_generics(generics); bounds.iter().for_each(|b| self.check_generic_bound(b)); - if let Some(ty) = default { + if let Some(ty) = type_ { self.check_type(ty); } } @@ -133,8 +134,8 @@ impl<'a> Validator<'a> { module.items.iter().for_each(|i| self.add_mod_item_id(i)); } - fn check_import(&mut self, x: &'a Import) { - if x.glob { + fn check_use(&mut self, x: &'a Use) { + if x.is_glob { self.add_glob_import_item_id(x.id.as_ref().unwrap()); } else if let Some(id) = &x.id { self.add_import_item_id(id); @@ -152,7 +153,7 @@ impl<'a> Validator<'a> { match &x.kind { StructKind::Unit => {} StructKind::Tuple(fields) => fields.iter().flatten().for_each(|f| self.add_field_id(f)), - StructKind::Plain { fields, fields_stripped: _ } => { + StructKind::Plain { fields, has_stripped_fields: _ } => { fields.iter().for_each(|f| self.add_field_id(f)) } } @@ -187,7 +188,7 @@ impl<'a> Validator<'a> { match kind { VariantKind::Plain => {} VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)), - VariantKind::Struct { fields, fields_stripped: _ } => { + VariantKind::Struct { fields, has_stripped_fields: _ } => { fields.iter().for_each(|f| self.add_field_id(f)) } } @@ -195,7 +196,7 @@ impl<'a> Validator<'a> { fn check_function(&mut self, x: &'a Function) { self.check_generics(&x.generics); - self.check_fn_decl(&x.decl); + self.check_function_signature(&x.sig); } fn check_trait(&mut self, x: &'a Trait, id: &Id) { @@ -267,8 +268,8 @@ impl<'a> Validator<'a> { Type::Array { type_, len: _ } => self.check_type(&**type_), Type::ImplTrait(bounds) => bounds.iter().for_each(|b| self.check_generic_bound(b)), Type::Infer => {} - Type::RawPointer { mutable: _, type_ } => self.check_type(&**type_), - Type::BorrowedRef { lifetime: _, mutable: _, type_ } => self.check_type(&**type_), + Type::RawPointer { is_mutable: _, type_ } => self.check_type(&**type_), + Type::BorrowedRef { lifetime: _, is_mutable: _, type_ } => self.check_type(&**type_), Type::QualifiedPath { name: _, args, self_type, trait_ } => { self.check_generic_args(&**args); self.check_type(&**self_type); @@ -279,7 +280,7 @@ impl<'a> Validator<'a> { } } - fn check_fn_decl(&mut self, x: &'a FnDecl) { + fn check_function_signature(&mut self, x: &'a FunctionSignature) { x.inputs.iter().for_each(|(_name, ty)| self.check_type(ty)); if let Some(output) = &x.output { self.check_type(output); @@ -309,9 +310,9 @@ impl<'a> Validator<'a> { fn check_generic_args(&mut self, x: &'a GenericArgs) { match x { - GenericArgs::AngleBracketed { args, bindings } => { + GenericArgs::AngleBracketed { args, constraints } => { args.iter().for_each(|arg| self.check_generic_arg(arg)); - bindings.iter().for_each(|bind| self.check_type_binding(bind)); + constraints.iter().for_each(|bind| self.check_assoc_item_constraint(bind)); } GenericArgs::Parenthesized { inputs, output } => { inputs.iter().for_each(|ty| self.check_type(ty)); @@ -325,7 +326,7 @@ impl<'a> Validator<'a> { fn check_generic_param_def(&mut self, gpd: &'a GenericParamDef) { match &gpd.kind { rustdoc_json_types::GenericParamDefKind::Lifetime { outlives: _ } => {} - rustdoc_json_types::GenericParamDefKind::Type { bounds, default, synthetic: _ } => { + rustdoc_json_types::GenericParamDefKind::Type { bounds, default, is_synthetic: _ } => { bounds.iter().for_each(|b| self.check_generic_bound(b)); if let Some(ty) = default { self.check_type(ty); @@ -346,11 +347,11 @@ impl<'a> Validator<'a> { } } - fn check_type_binding(&mut self, bind: &'a TypeBinding) { + fn check_assoc_item_constraint(&mut self, bind: &'a AssocItemConstraint) { self.check_generic_args(&bind.args); match &bind.binding { - TypeBindingKind::Equality(term) => self.check_term(term), - TypeBindingKind::Constraint(bounds) => { + AssocItemConstraintKind::Equality(term) => self.check_term(term), + AssocItemConstraintKind::Constraint(bounds) => { bounds.iter().for_each(|b| self.check_generic_bound(b)) } } @@ -388,7 +389,7 @@ impl<'a> Validator<'a> { } fn check_function_pointer(&mut self, fp: &'a FunctionPointer) { - self.check_fn_decl(&fp.decl); + self.check_function_signature(&fp.sig); fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs index f28702de06d50..d15aa7db31571 100644 --- a/src/tools/jsondoclint/src/validator/tests.rs +++ b/src/tools/jsondoclint/src/validator/tests.rs @@ -1,5 +1,5 @@ use rustc_hash::FxHashMap; -use rustdoc_json_types::{Item, ItemKind, Visibility, FORMAT_VERSION}; +use rustdoc_json_types::{FORMAT_VERSION, Item, ItemKind, Visibility}; use super::*; use crate::json_find::SelectorPart; @@ -25,42 +25,32 @@ fn errors_on_missing_links() { root: id("0"), crate_version: None, includes_private: false, - index: FxHashMap::from_iter([( - id("0"), - Item { - name: Some("root".to_owned()), - id: id(""), - crate_id: 0, - span: None, - visibility: Visibility::Public, - docs: None, - links: FxHashMap::from_iter([("Not Found".to_owned(), id("1"))]), - attrs: vec![], - deprecation: None, - inner: ItemEnum::Module(Module { - is_crate: true, - items: vec![], - is_stripped: false, - }), - }, - )]), + index: FxHashMap::from_iter([(id("0"), Item { + name: Some("root".to_owned()), + id: id(""), + crate_id: 0, + span: None, + visibility: Visibility::Public, + docs: None, + links: FxHashMap::from_iter([("Not Found".to_owned(), id("1"))]), + attrs: vec![], + deprecation: None, + inner: ItemEnum::Module(Module { is_crate: true, items: vec![], is_stripped: false }), + })]), paths: FxHashMap::default(), external_crates: FxHashMap::default(), format_version: rustdoc_json_types::FORMAT_VERSION, }; - check( - &k, - &[Error { - kind: ErrorKind::NotFound(vec![vec![ - SelectorPart::Field("index".to_owned()), - SelectorPart::Field("0".to_owned()), - SelectorPart::Field("links".to_owned()), - SelectorPart::Field("Not Found".to_owned()), - ]]), - id: id("1"), - }], - ); + check(&k, &[Error { + kind: ErrorKind::NotFound(vec![vec![ + SelectorPart::Field("index".to_owned()), + SelectorPart::Field("0".to_owned()), + SelectorPart::Field("links".to_owned()), + SelectorPart::Field("Not Found".to_owned()), + ]]), + id: id("1"), + }]); } // Test we would catch @@ -72,60 +62,48 @@ fn errors_on_local_in_paths_and_not_index() { crate_version: None, includes_private: false, index: FxHashMap::from_iter([ - ( - id("0:0:1572"), - Item { - id: id("0:0:1572"), - crate_id: 0, - name: Some("microcore".to_owned()), - span: None, - visibility: Visibility::Public, - docs: None, - links: FxHashMap::from_iter([(("prim@i32".to_owned(), id("0:1:1571")))]), - attrs: Vec::new(), - deprecation: None, - inner: ItemEnum::Module(Module { - is_crate: true, - items: vec![id("0:1:717")], - is_stripped: false, - }), - }, - ), - ( - id("0:1:717"), - Item { - id: id("0:1:717"), - crate_id: 0, - name: Some("i32".to_owned()), - span: None, - visibility: Visibility::Public, - docs: None, - links: FxHashMap::default(), - attrs: Vec::new(), - deprecation: None, - inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }), - }, - ), - ]), - paths: FxHashMap::from_iter([( - id("0:1:1571"), - ItemSummary { + (id("0:0:1572"), Item { + id: id("0:0:1572"), crate_id: 0, - path: vec!["microcore".to_owned(), "i32".to_owned()], - kind: ItemKind::Primitive, - }, - )]), + name: Some("microcore".to_owned()), + span: None, + visibility: Visibility::Public, + docs: None, + links: FxHashMap::from_iter([(("prim@i32".to_owned(), id("0:1:1571")))]), + attrs: Vec::new(), + deprecation: None, + inner: ItemEnum::Module(Module { + is_crate: true, + items: vec![id("0:1:717")], + is_stripped: false, + }), + }), + (id("0:1:717"), Item { + id: id("0:1:717"), + crate_id: 0, + name: Some("i32".to_owned()), + span: None, + visibility: Visibility::Public, + docs: None, + links: FxHashMap::default(), + attrs: Vec::new(), + deprecation: None, + inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }), + }), + ]), + paths: FxHashMap::from_iter([(id("0:1:1571"), ItemSummary { + crate_id: 0, + path: vec!["microcore".to_owned(), "i32".to_owned()], + kind: ItemKind::Primitive, + })]), external_crates: FxHashMap::default(), format_version: rustdoc_json_types::FORMAT_VERSION, }; - check( - &krate, - &[Error { - id: id("0:1:1571"), - kind: ErrorKind::Custom("Id for local item in `paths` but not in `index`".to_owned()), - }], - ); + check(&krate, &[Error { + id: id("0:1:1571"), + kind: ErrorKind::Custom("Id for local item in `paths` but not in `index`".to_owned()), + }]); } #[test] @@ -135,25 +113,18 @@ fn checks_local_crate_id_is_correct() { root: id("root"), crate_version: None, includes_private: false, - index: FxHashMap::from_iter([( - id("root"), - Item { - id: id("root"), - crate_id: LOCAL_CRATE_ID.wrapping_add(1), - name: Some("irrelavent".to_owned()), - span: None, - visibility: Visibility::Public, - docs: None, - links: FxHashMap::default(), - attrs: Vec::new(), - deprecation: None, - inner: ItemEnum::Module(Module { - is_crate: true, - items: vec![], - is_stripped: false, - }), - }, - )]), + index: FxHashMap::from_iter([(id("root"), Item { + id: id("root"), + crate_id: LOCAL_CRATE_ID.wrapping_add(1), + name: Some("irrelavent".to_owned()), + span: None, + visibility: Visibility::Public, + docs: None, + links: FxHashMap::default(), + attrs: Vec::new(), + deprecation: None, + inner: ItemEnum::Module(Module { is_crate: true, items: vec![], is_stripped: false }), + })]), paths: FxHashMap::default(), external_crates: FxHashMap::default(), format_version: FORMAT_VERSION, diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 72bb9db7e7414..8c7ff08ccd72c 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -19,30 +19,24 @@ mod groups; /// level of the lint, which will be more difficult to support, since rustc /// currently does not track that historical information. static RENAMES: &[(Level, &[(&str, &str)])] = &[ - ( - Level::Allow, - &[ - ("single-use-lifetime", "single-use-lifetimes"), - ("elided-lifetime-in-path", "elided-lifetimes-in-paths"), - ("async-idents", "keyword-idents"), - ("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"), - ("keyword-idents", "keyword-idents-2018"), - ("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"), - ], - ), - ( - Level::Warn, - &[ - ("bare-trait-object", "bare-trait-objects"), - ("unstable-name-collision", "unstable-name-collisions"), - ("unused-doc-comment", "unused-doc-comments"), - ("redundant-semicolon", "redundant-semicolons"), - ("overlapping-patterns", "overlapping-range-endpoints"), - ("non-fmt-panic", "non-fmt-panics"), - ("unused-tuple-struct-fields", "dead-code"), - ("static-mut-ref", "static-mut-refs"), - ], - ), + (Level::Allow, &[ + ("single-use-lifetime", "single-use-lifetimes"), + ("elided-lifetime-in-path", "elided-lifetimes-in-paths"), + ("async-idents", "keyword-idents"), + ("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"), + ("keyword-idents", "keyword-idents-2018"), + ("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"), + ]), + (Level::Warn, &[ + ("bare-trait-object", "bare-trait-objects"), + ("unstable-name-collision", "unstable-name-collisions"), + ("unused-doc-comment", "unused-doc-comments"), + ("redundant-semicolon", "redundant-semicolons"), + ("overlapping-patterns", "overlapping-range-endpoints"), + ("non-fmt-panic", "non-fmt-panics"), + ("unused-tuple-struct-fields", "dead-code"), + ("static-mut-ref", "static-mut-refs"), + ]), (Level::Deny, &[("exceeding-bitshifts", "arithmetic-overflow")]), ]; @@ -56,6 +50,8 @@ pub struct LintExtractor<'a> { pub rustc_path: &'a Path, /// The target arch to build the docs for. pub rustc_target: &'a str, + /// The target linker overriding `rustc`'s default + pub rustc_linker: Option<&'a str>, /// Verbose output. pub verbose: bool, /// Validate the style and the code example. @@ -459,6 +455,9 @@ impl<'a> LintExtractor<'a> { } cmd.arg("--error-format=json"); cmd.arg("--target").arg(self.rustc_target); + if let Some(target_linker) = self.rustc_linker { + cmd.arg(format!("-Clinker={target_linker}")); + } if options.contains(&"test") { cmd.arg("--test"); } diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 2055fed2b480c..e377283b1a453 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -27,6 +27,7 @@ fn doit() -> Result<(), Box> { let mut out_path = None; let mut rustc_path = None; let mut rustc_target = None; + let mut rustc_linker = None; let mut verbose = false; let mut validate = false; while let Some(arg) = args.next() { @@ -55,6 +56,12 @@ fn doit() -> Result<(), Box> { None => return Err("--rustc-target requires a value".into()), }; } + "--rustc-linker" => { + rustc_linker = match args.next() { + Some(s) => Some(s), + None => return Err("--rustc-linker requires a value".into()), + }; + } "-v" | "--verbose" => verbose = true, "--validate" => validate = true, s => return Err(format!("unexpected argument `{}`", s).into()), @@ -77,6 +84,7 @@ fn doit() -> Result<(), Box> { out_path: &out_path.unwrap(), rustc_path: &rustc_path.unwrap(), rustc_target: &rustc_target.unwrap(), + rustc_linker: rustc_linker.as_deref(), verbose, validate, }; diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 22c833a5488fa..b9441236bcd3e 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -12,6 +12,9 @@ on: schedule: - cron: '44 4 * * *' # At 4:44 UTC every day. +permissions: + contents: write + defaults: run: shell: bash diff --git a/src/tools/miri/.github/workflows/sysroots.yml b/src/tools/miri/.github/workflows/sysroots.yml index 73a10768db908..6a4f44ddd507a 100644 --- a/src/tools/miri/.github/workflows/sysroots.yml +++ b/src/tools/miri/.github/workflows/sysroots.yml @@ -13,7 +13,7 @@ jobs: name: Build the sysroots runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build the sysroots run: | cargo install -f rustup-toolchain-install-master diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index e4bfd9bd12282..002c44b0cc56f 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -39,22 +39,19 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.9.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" +checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" dependencies = [ + "anstyle", "unicode-width", - "yansi-term", ] [[package]] -name = "ansi_term" -version = "0.12.1" +name = "anstyle" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anyhow" @@ -126,9 +123,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.4" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", @@ -737,11 +734,11 @@ dependencies = [ [[package]] name = "prettydiff" -version = "0.6.4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff1fec61082821f8236cf6c0c14e8172b62ce8a72a0eedc30d3b247bb68dc11" +checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9" dependencies = [ - "ansi_term", + "owo-colors", "pad", ] @@ -865,14 +862,14 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.6.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481" +checksum = "70f5b7fc8060f4f8373f9381a630304b42e1183535d9beb1d3f596b236c9106a" dependencies = [ - "anyhow", - "log", "serde", "serde_json", + "thiserror", + "tracing", ] [[package]] @@ -962,6 +959,16 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "spanned" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" +dependencies = [ + "bstr", + "color-eyre", +] + [[package]] name = "syn" version = "2.0.72" @@ -1065,9 +1072,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ui_test" -version = "0.21.2" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d" +checksum = "32ee4c40e5a5f9fa6864ff976473e5d6a6e9884b6ce68b40690d9f87e1994c83" dependencies = [ "annotate-snippets", "anyhow", @@ -1079,7 +1086,6 @@ dependencies = [ "comma", "crossbeam-channel", "indicatif", - "lazy_static", "levenshtein", "prettydiff", "regex", @@ -1087,7 +1093,7 @@ dependencies = [ "rustfix", "serde", "serde_json", - "tempfile", + "spanned", ] [[package]] @@ -1120,28 +1126,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-sys" version = "0.48.0" @@ -1281,15 +1265,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "yansi-term" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" -dependencies = [ - "winapi", -] - [[package]] name = "zerocopy" version = "0.7.35" diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 4b7f3483ff7db..30cea9da3732c 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -37,8 +37,6 @@ features = ['unprefixed_malloc_on_supported_platforms'] [target.'cfg(unix)'.dependencies] libc = "0.2" - -[target.'cfg(target_os = "linux")'.dependencies] libffi = "3.2.0" libloading = "0.8" @@ -51,7 +49,7 @@ windows-sys = { version = "0.52", features = [ [dev-dependencies] colored = "2" -ui_test = "0.21.1" +ui_test = "0.26.5" rustc_version = "0.4" regex = "1.5.5" tempfile = "3" diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 5821adb96ce29..d8636915ea80e 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -187,7 +187,7 @@ Here is an example job for GitHub Actions: name: "Miri" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Miri run: | rustup toolchain install nightly --component miri @@ -216,9 +216,9 @@ degree documented below): - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we make no promises and we don't run tests for such targets. - We have unofficial support (not maintained by the Miri team itself) for some further operating systems. + - `solaris` / `illumos`: maintained by @devnexen. Supports `std::{env, thread, sync}`, but not `std::fs`. - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`. - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - - `solaris` / `illumos`: maintained by @devnexen. Support very incomplete, but a basic "hello world" works. - `wasm`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. - For targets on other operating systems, Miri might fail before even reaching the `main` function. @@ -383,7 +383,7 @@ to Miri failing to detect cases of undefined behavior in a program. file descriptors will be mixed up. This is **work in progress**; currently, only integer arguments and return values are supported (and no, pointer/integer casts to work around this limitation will not work; - they will fail horribly). It also only works on Linux hosts for now. + they will fail horribly). It also only works on Unix hosts for now. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file inside a directory called ``, and can be processed diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 1f66b6fa776d9..c7be71662bd5f 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -26,7 +26,7 @@ time ./miri install # We enable all features to make sure the Stacked Borrows consistency check runs. echo "Building debug version of Miri" export CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS --all-features" -time ./miri build --all-targets # the build that all the `./miri test` below will use +time ./miri build # the build that all the `./miri test` below will use endgroup @@ -66,7 +66,7 @@ function run_tests { time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test $TARGET_FLAG tests/{pass,panic} fi if [ -n "${MANY_SEEDS-}" ]; then - # Also run some many-seeds tests. + # Also run some many-seeds tests. (Also tests `./miri run`.) time for FILE in tests/many-seeds/*.rs; do ./miri run "--many-seeds=0..$MANY_SEEDS" $TARGET_FLAG "$FILE" done @@ -75,6 +75,8 @@ function run_tests { # Check that the benchmarks build and run, but only once. time HYPERFINE="hyperfine -w0 -r1" ./miri bench $TARGET_FLAG fi + # Smoke-test `./miri run --dep`. + ./miri run $TARGET_FLAG --dep tests/pass-dep/getrandom.rs ## test-cargo-miri # On Windows, there is always "python", not "python3" or "python2". @@ -148,11 +150,11 @@ case $HOST_TARGET in # Partially supported targets (tier 2) BASIC="empty_main integer vec string btreemap hello hashmap heap_alloc align" # ensures we have the basics: stdout/stderr, system allocator, randomness (for HashMap initialization) UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there - TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs - TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs - TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX threadname pthread-sync available-parallelism libc-time tls - TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX threadname pthread-sync available-parallelism libc-time tls - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX + TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs + TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs + TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls + TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX pthread --skip threadname --skip pthread_cond_timedwait TEST_TARGET=wasm32-wasip2 run_tests_minimal empty_main wasm heap_alloc libc-mem TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index 5e792abac175d..8f19576c51db2 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -61,9 +61,9 @@ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -98,6 +98,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "libc" version = "0.2.153" @@ -117,9 +123,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miri-script" @@ -131,6 +143,7 @@ dependencies = [ "itertools", "path_macro", "rustc_version", + "serde_json", "shell-words", "walkdir", "which", @@ -204,9 +217,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.4.2", "errno", @@ -215,6 +228,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "same-file" version = "1.0.6" @@ -230,6 +249,38 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "shell-words" version = "1.1.0" @@ -347,7 +398,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.6", ] [[package]] @@ -367,17 +418,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -388,9 +440,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -400,9 +452,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -412,9 +464,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -424,9 +482,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -436,9 +494,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -448,9 +506,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -460,9 +518,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "xshell" diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index 631d3a82102b5..2922c24d6c09c 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -23,3 +23,4 @@ xshell = "0.2.6" rustc_version = "0.4" dunce = "1.0.4" directories = "5" +serde_json = "1" diff --git a/src/tools/miri/miri-script/src/args.rs b/src/tools/miri/miri-script/src/args.rs index 16a21757b3535..c1688ca0fb6b2 100644 --- a/src/tools/miri/miri-script/src/args.rs +++ b/src/tools/miri/miri-script/src/args.rs @@ -1,7 +1,7 @@ use std::env; use std::iter; -use anyhow::{bail, Result}; +use anyhow::{Result, bail}; pub struct Args { args: iter::Peekable, diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index a9a8017590117..b0e62d5cda6f0 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -8,13 +8,13 @@ use std::path::PathBuf; use std::process; use std::time::Duration; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{Context, Result, anyhow, bail}; use path_macro::path; use walkdir::WalkDir; -use xshell::{cmd, Shell}; +use xshell::{Shell, cmd}; -use crate::util::*; use crate::Command; +use crate::util::*; /// Used for rustc syncs. const JOSH_FILTER: &str = @@ -494,23 +494,25 @@ impl Command { flags: Vec, ) -> Result<()> { let mut e = MiriEnv::new()?; + + // Preparation: get a sysroot, and get the miri binary. + let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?; + let miri_bin = + e.build_get_binary(".").context("failed to get filename of miri executable")?; + // More flags that we will pass before `flags` // (because `flags` may contain `--`). let mut early_flags = Vec::::new(); - // Add target, edition to flags. - if let Some(target) = &target { - early_flags.push("--target".into()); - early_flags.push(target.into()); - } - if verbose { - early_flags.push("--verbose".into()); + // In `dep` mode, the target is already passed via `MIRI_TEST_TARGET` + if !dep { + if let Some(target) = &target { + early_flags.push("--target".into()); + early_flags.push(target.into()); + } } early_flags.push("--edition".into()); early_flags.push(edition.as_deref().unwrap_or("2021").into()); - - // Prepare a sysroot, add it to the flags. (Also builds cargo-miri, which we need.) - let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?; early_flags.push("--sysroot".into()); early_flags.push(miri_sysroot.into()); @@ -523,18 +525,19 @@ impl Command { let run_miri = |e: &MiriEnv, seed_flag: Option| -> Result<()> { // The basic command that executes the Miri driver. let mut cmd = if dep { + // We invoke the test suite as that has all the logic for running with dependencies. e.cargo_cmd(".", "test") .args(&["--test", "ui"]) .args(quiet_flag) .arg("--") .args(&["--miri-run-dep-mode"]) } else { - e.cargo_cmd(".", "run").args(quiet_flag).arg("--") + cmd!(e.sh, "{miri_bin}") }; cmd.set_quiet(!verbose); // Add Miri flags let mut cmd = cmd.args(&miri_flags).args(&seed_flag).args(&early_flags).args(&flags); - // For `--dep` we also need to set the env var. + // For `--dep` we also need to set the target in the env var. if dep { if let Some(target) = &target { cmd = cmd.env("MIRI_TEST_TARGET", target); diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index 9214823710709..0620f3aaf0993 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -6,7 +6,7 @@ mod util; use std::ops::Range; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{Context, Result, anyhow, bail}; #[derive(Clone, Debug)] pub enum Command { diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs index 35c604b407e1e..f5a6a8188a0dc 100644 --- a/src/tools/miri/miri-script/src/util.rs +++ b/src/tools/miri/miri-script/src/util.rs @@ -1,13 +1,14 @@ use std::ffi::{OsStr, OsString}; +use std::io::BufRead; use std::ops::Range; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; -use std::thread; +use std::{env, iter, thread}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result, anyhow, bail}; use dunce::canonicalize; use path_macro::path; -use xshell::{cmd, Cmd, Shell}; +use xshell::{Cmd, Shell, cmd}; pub fn miri_dir() -> std::io::Result { const MIRI_SCRIPT_ROOT_DIR: &str = env!("CARGO_MANIFEST_DIR"); @@ -73,8 +74,11 @@ impl MiriEnv { let rustflags = { let mut flags = OsString::new(); // We set the rpath so that Miri finds the private rustc libraries it needs. - flags.push("-C link-args=-Wl,-rpath,"); - flags.push(libdir); + // (This only makes sense on Unix.) + if cfg!(unix) { + flags.push("-C link-args=-Wl,-rpath,"); + flags.push(&libdir); + } // Enable rustc-specific lints (ignored without `-Zunstable-options`). flags.push( " -Zunstable-options -Wrustc::internal -Wrust_2018_idioms -Wunused_lifetimes", @@ -88,6 +92,14 @@ impl MiriEnv { }; sh.set_var("RUSTFLAGS", rustflags); + // On Windows, the `-Wl,-rpath,` above does not help. Instead we add the libdir to the PATH, + // so that Windows can find the DLLs. + if cfg!(windows) { + let old_path = sh.var("PATH")?; + let new_path = env::join_paths(iter::once(libdir).chain(env::split_paths(&old_path)))?; + sh.set_var("PATH", new_path); + } + // Get extra flags for cargo. let cargo_extra_flags = std::env::var("CARGO_EXTRA_FLAGS").unwrap_or_default(); let cargo_extra_flags = flagsplit(&cargo_extra_flags); @@ -126,21 +138,40 @@ impl MiriEnv { pub fn build(&self, crate_dir: impl AsRef, args: &[String], quiet: bool) -> Result<()> { let quiet_flag = if quiet { Some("--quiet") } else { None }; - // We build the tests as well, (a) to avoid having rebuilds when building the tests later - // and (b) to have more parallelism during the build of Miri and its tests. - // This means `./miri run` without `--dep` will build Miri twice (for the sysroot with - // dev-dependencies, and then for running without dev-dependencies), but the way more common - // `./miri test` will avoid building Miri twice. - let mut cmd = self - .cargo_cmd(crate_dir, "build") - .args(&["--bins", "--tests"]) - .args(quiet_flag) - .args(args); + // We build all targets, since building *just* the bin target doesnot include + // `dev-dependencies` and that changes feature resolution. This also gets us more + // parallelism in `./miri test` as we build Miri and its tests together. + let mut cmd = + self.cargo_cmd(crate_dir, "build").args(&["--all-targets"]).args(quiet_flag).args(args); cmd.set_quiet(quiet); cmd.run()?; Ok(()) } + /// Returns the path to the main crate binary. Assumes that `build` has been called before. + pub fn build_get_binary(&self, crate_dir: impl AsRef) -> Result { + let cmd = + self.cargo_cmd(crate_dir, "build").args(&["--all-targets", "--message-format=json"]); + let output = cmd.output()?; + let mut bin = None; + for line in output.stdout.lines() { + let line = line?; + if line.starts_with("{") { + let json: serde_json::Value = serde_json::from_str(&line)?; + if json["reason"] == "compiler-artifact" + && !json["profile"]["test"].as_bool().unwrap() + && !json["executable"].is_null() + { + if bin.is_some() { + bail!("found two binaries in cargo output"); + } + bin = Some(PathBuf::from(json["executable"].as_str().unwrap())) + } + } + } + bin.ok_or_else(|| anyhow!("found no binary in cargo output")) + } + pub fn check(&self, crate_dir: impl AsRef, args: &[String]) -> Result<()> { self.cargo_cmd(crate_dir, "check").arg("--all-targets").args(args).run()?; Ok(()) diff --git a/src/tools/miri/miri.bat b/src/tools/miri/miri.bat index 6f9a8f38d6559..b046b6310ddad 100644 --- a/src/tools/miri/miri.bat +++ b/src/tools/miri/miri.bat @@ -5,8 +5,8 @@ set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target :: If any other steps are added, the "|| exit /b" must be appended to early :: return from the script. If not, it will continue execution. -cargo +stable build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml ^ - || (echo Failed to build miri-script. Is the 'stable' toolchain installed? & exit /b) +cargo +nightly build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml ^ + || (echo Failed to build miri-script. Is the 'nightly' toolchain installed? & exit /b) :: Forwards all arguments to this file to the executable. :: We invoke the binary directly to avoid going through rustup, which would set some extra diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index c33d9ad86149b..76fe17316ac65 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -0d634185dfddefe09047881175f35c65d68dcff1 +6ce376774c0bc46ac8be247bca93ff5a1287a8fc diff --git a/src/tools/miri/rustfmt.toml b/src/tools/miri/rustfmt.toml index be5af7379eae7..3f9311d9d1a50 100644 --- a/src/tools/miri/rustfmt.toml +++ b/src/tools/miri/rustfmt.toml @@ -1,4 +1,4 @@ -version = "Two" +style_edition = "2024" use_small_heuristics = "Max" match_arm_blocks = false match_arm_leading_pipes = "Preserve" diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 76c68add8cdc9..c19a962e6523e 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -5,7 +5,6 @@ mod reuse_pool; use std::cell::RefCell; use std::cmp::max; -use std::collections::hash_map::Entry; use rand::Rng; @@ -151,6 +150,95 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } + fn addr_from_alloc_id_uncached( + &self, + global_state: &mut GlobalStateInner, + alloc_id: AllocId, + memory_kind: MemoryKind, + ) -> InterpResult<'tcx, u64> { + let ecx = self.eval_context_ref(); + let mut rng = ecx.machine.rng.borrow_mut(); + let (size, align, kind) = ecx.get_alloc_info(alloc_id); + // This is either called immediately after allocation (and then cached), or when + // adjusting `tcx` pointers (which never get freed). So assert that we are looking + // at a live allocation. This also ensures that we never re-assign an address to an + // allocation that previously had an address, but then was freed and the address + // information was removed. + assert!(!matches!(kind, AllocKind::Dead)); + + // This allocation does not have a base address yet, pick or reuse one. + if ecx.machine.native_lib.is_some() { + // In native lib mode, we use the "real" address of the bytes for this allocation. + // This ensures the interpreted program and native code have the same view of memory. + let base_ptr = match kind { + AllocKind::LiveData => { + if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { + // For new global allocations, we always pre-allocate the memory to be able use the machine address directly. + let prepared_bytes = MiriAllocBytes::zeroed(size, align) + .unwrap_or_else(|| { + panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes") + }); + let ptr = prepared_bytes.as_ptr(); + // Store prepared allocation space to be picked up for use later. + global_state + .prepared_alloc_bytes + .try_insert(alloc_id, prepared_bytes) + .unwrap(); + ptr + } else { + ecx.get_alloc_bytes_unchecked_raw(alloc_id)? + } + } + AllocKind::Function | AllocKind::VTable => { + // Allocate some dummy memory to get a unique address for this function/vtable. + let alloc_bytes = + MiriAllocBytes::from_bytes(&[0u8; 1], Align::from_bytes(1).unwrap()); + let ptr = alloc_bytes.as_ptr(); + // Leak the underlying memory to ensure it remains unique. + std::mem::forget(alloc_bytes); + ptr + } + AllocKind::Dead => unreachable!(), + }; + // Ensure this pointer's provenance is exposed, so that it can be used by FFI code. + return Ok(base_ptr.expose_provenance().try_into().unwrap()); + } + // We are not in native lib mode, so we control the addresses ourselves. + if let Some((reuse_addr, clock)) = + global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, ecx.active_thread()) + { + if let Some(clock) = clock { + ecx.acquire_clock(&clock); + } + Ok(reuse_addr) + } else { + // We have to pick a fresh address. + // Leave some space to the previous allocation, to give it some chance to be less aligned. + // We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. + let slack = rng.gen_range(0..16); + // From next_base_addr + slack, round up to adjust for alignment. + let base_addr = global_state + .next_base_addr + .checked_add(slack) + .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; + let base_addr = align_addr(base_addr, align.bytes()); + + // Remember next base address. If this allocation is zero-sized, leave a gap of at + // least 1 to avoid two allocations having the same base address. (The logic in + // `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers + // need to be distinguishable!) + global_state.next_base_addr = base_addr + .checked_add(max(size.bytes(), 1)) + .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; + // Even if `Size` didn't overflow, we might still have filled up the address space. + if global_state.next_base_addr > ecx.target_usize_max() { + throw_exhaust!(AddressSpaceFull); + } + + Ok(base_addr) + } + } + fn addr_from_alloc_id( &self, alloc_id: AllocId, @@ -160,98 +248,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut global_state = ecx.machine.alloc_addresses.borrow_mut(); let global_state = &mut *global_state; - Ok(match global_state.base_addr.entry(alloc_id) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let mut rng = ecx.machine.rng.borrow_mut(); - let (size, align, kind) = ecx.get_alloc_info(alloc_id); - // This is either called immediately after allocation (and then cached), or when - // adjusting `tcx` pointers (which never get freed). So assert that we are looking - // at a live allocation. This also ensures that we never re-assign an address to an - // allocation that previously had an address, but then was freed and the address - // information was removed. - assert!(!matches!(kind, AllocKind::Dead)); - - // This allocation does not have a base address yet, pick or reuse one. - let base_addr = if ecx.machine.native_lib.is_some() { - // In native lib mode, we use the "real" address of the bytes for this allocation. - // This ensures the interpreted program and native code have the same view of memory. - match kind { - AllocKind::LiveData => { - let ptr = if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { - // For new global allocations, we always pre-allocate the memory to be able use the machine address directly. - let prepared_bytes = MiriAllocBytes::zeroed(size, align) - .unwrap_or_else(|| { - panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes") - }); - let ptr = prepared_bytes.as_ptr(); - // Store prepared allocation space to be picked up for use later. - global_state.prepared_alloc_bytes.try_insert(alloc_id, prepared_bytes).unwrap(); - ptr - } else { - ecx.get_alloc_bytes_unchecked_raw(alloc_id)? - }; - // Ensure this pointer's provenance is exposed, so that it can be used by FFI code. - ptr.expose_provenance().try_into().unwrap() - } - AllocKind::Function | AllocKind::VTable => { - // Allocate some dummy memory to get a unique address for this function/vtable. - let alloc_bytes = MiriAllocBytes::from_bytes(&[0u8; 1], Align::from_bytes(1).unwrap()); - // We don't need to expose these bytes as nobody is allowed to access them. - let addr = alloc_bytes.as_ptr().addr().try_into().unwrap(); - // Leak the underlying memory to ensure it remains unique. - std::mem::forget(alloc_bytes); - addr - } - AllocKind::Dead => unreachable!() - } - } else if let Some((reuse_addr, clock)) = global_state.reuse.take_addr( - &mut *rng, - size, - align, - memory_kind, - ecx.active_thread(), - ) { - if let Some(clock) = clock { - ecx.acquire_clock(&clock); - } - reuse_addr - } else { - // We have to pick a fresh address. - // Leave some space to the previous allocation, to give it some chance to be less aligned. - // We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. - let slack = rng.gen_range(0..16); - // From next_base_addr + slack, round up to adjust for alignment. - let base_addr = global_state - .next_base_addr - .checked_add(slack) - .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - let base_addr = align_addr(base_addr, align.bytes()); - - // Remember next base address. If this allocation is zero-sized, leave a gap - // of at least 1 to avoid two allocations having the same base address. - // (The logic in `alloc_id_from_addr` assumes unique addresses, and different - // function/vtable pointers need to be distinguishable!) - global_state.next_base_addr = base_addr - .checked_add(max(size.bytes(), 1)) - .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - // Even if `Size` didn't overflow, we might still have filled up the address space. - if global_state.next_base_addr > ecx.target_usize_max() { - throw_exhaust!(AddressSpaceFull); - } - - base_addr - }; - trace!( - "Assigning base address {:#x} to allocation {:?} (size: {}, align: {})", - base_addr, - alloc_id, - size.bytes(), - align.bytes(), - ); + match global_state.base_addr.get(&alloc_id) { + Some(&addr) => Ok(addr), + None => { + // First time we're looking for the absolute address of this allocation. + let base_addr = + self.addr_from_alloc_id_uncached(global_state, alloc_id, memory_kind)?; + trace!("Assigning base address {:#x} to allocation {:?}", base_addr, alloc_id); // Store address in cache. - entry.insert(base_addr); + global_state.base_addr.try_insert(alloc_id, base_addr).unwrap(); // Also maintain the opposite mapping in `int_to_ptr_map`, ensuring we keep it sorted. // We have a fast-path for the common case that this address is bigger than all previous ones. @@ -269,9 +275,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { }; global_state.int_to_ptr_map.insert(pos, (base_addr, alloc_id)); - base_addr + Ok(base_addr) } - }) + } } } @@ -359,16 +365,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This returns some prepared `MiriAllocBytes`, either because `addr_from_alloc_id` reserved // memory space in the past, or by doing the pre-allocation right upon being called. - fn get_global_alloc_bytes(&self, id: AllocId, kind: MemoryKind, bytes: &[u8], align: Align) -> InterpResult<'tcx, MiriAllocBytes> { + fn get_global_alloc_bytes( + &self, + id: AllocId, + kind: MemoryKind, + bytes: &[u8], + align: Align, + ) -> InterpResult<'tcx, MiriAllocBytes> { let ecx = self.eval_context_ref(); - Ok(if ecx.machine.native_lib.is_some() { + if ecx.machine.native_lib.is_some() { // In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`. - // This additional call ensures that some `MiriAllocBytes` are always prepared. + // This additional call ensures that some `MiriAllocBytes` are always prepared, just in case + // this function gets called before the first time `addr_from_alloc_id` gets called. ecx.addr_from_alloc_id(id, kind)?; - let mut global_state = ecx.machine.alloc_addresses.borrow_mut(); // The memory we need here will have already been allocated during an earlier call to // `addr_from_alloc_id` for this allocation. So don't create a new `MiriAllocBytes` here, instead // fetch the previously prepared bytes from `prepared_alloc_bytes`. + let mut global_state = ecx.machine.alloc_addresses.borrow_mut(); let mut prepared_alloc_bytes = global_state .prepared_alloc_bytes .remove(&id) @@ -378,10 +391,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert_eq!(prepared_alloc_bytes.len(), bytes.len()); // Copy allocation contents into prepared memory. prepared_alloc_bytes.copy_from_slice(bytes); - prepared_alloc_bytes + Ok(prepared_alloc_bytes) } else { - MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(&*bytes), align) - }) + Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)) + } } /// When a pointer is used for a memory access, this computes where in which allocation the diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs index 77fc9f53f9e37..f6c1675634460 100644 --- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs +++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs @@ -4,7 +4,7 @@ use rand::Rng; use rustc_target::abi::{Align, Size}; -use crate::{concurrency::VClock, MemoryKind, MiriConfig, ThreadId}; +use crate::{MemoryKind, MiriConfig, ThreadId, concurrency::VClock}; const MAX_POOL_SIZE: usize = 64; diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index fc2b3f9c6ea77..f792e75ad0855 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -12,19 +12,19 @@ use std::mem; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{Mutability, RetagKind}; -use rustc_middle::ty::{self, layout::HasParamEnv, Ty}; +use rustc_middle::ty::{self, Ty, layout::HasParamEnv}; use rustc_target::abi::{Abi, Size}; use crate::borrow_tracker::{ - stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder}, GlobalStateInner, ProtectorKind, + stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder}, }; use crate::concurrency::data_race::{NaReadType, NaWriteType}; use crate::*; -use diagnostics::{RetagCause, RetagInfo}; -pub use item::{Item, Permission}; -pub use stack::Stack; +use self::diagnostics::{RetagCause, RetagInfo}; +pub use self::item::{Item, Permission}; +pub use self::stack::Stack; pub type AllocState = Stacks; @@ -913,11 +913,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { new_perm: NewPermission, ) -> InterpResult<'tcx> { let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.sb_retag_reference( - &val, - new_perm, - RetagInfo { cause: self.retag_cause, in_field: self.in_field }, - )?; + let val = self.ecx.sb_retag_reference(&val, new_perm, RetagInfo { + cause: self.retag_cause, + in_field: self.in_field, + })?; self.ecx.write_immediate(*val, place)?; Ok(()) } @@ -1003,11 +1002,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { access: Some(AccessKind::Write), protector: Some(ProtectorKind::StrongProtector), }; - this.sb_retag_place( - place, - new_perm, - RetagInfo { cause: RetagCause::InPlaceFnPassing, in_field: false }, - ) + this.sb_retag_place(place, new_perm, RetagInfo { + cause: RetagCause::InPlaceFnPassing, + in_field: false, + }) } /// Mark the given tag as exposed. It was found on a pointer with the given AllocId. diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index 774b36919fe34..5c040983142f8 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -4,11 +4,11 @@ use std::ops::Range; use rustc_data_structures::fx::FxHashSet; use tracing::trace; +use crate::ProvenanceExtra; use crate::borrow_tracker::{ - stacked_borrows::{Item, Permission}, AccessKind, BorTag, + stacked_borrows::{Item, Permission}, }; -use crate::ProvenanceExtra; /// Exactly what cache size we should use is a difficult trade-off. There will always be some /// workload which has a `BorTag` working set which exceeds the size of the cache, and ends up diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index a753de28a041e..44ea7533b00cb 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -4,12 +4,12 @@ use std::ops::Range; use rustc_data_structures::fx::FxHashMap; use rustc_span::{Span, SpanData}; +use crate::borrow_tracker::ProtectorKind; use crate::borrow_tracker::tree_borrows::{ perms::{PermTransition, Permission}, tree::LocationState, unimap::UniIndex, }; -use crate::borrow_tracker::ProtectorKind; use crate::*; /// Cause of an access: either a real access or one diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 722cb79c66b10..2afe02dc2c7f8 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -1,6 +1,6 @@ use rustc_middle::{ mir::{Mutability, RetagKind}, - ty::{self, layout::HasParamEnv, Ty}, + ty::{self, Ty, layout::HasParamEnv}, }; use rustc_span::def_id::DefId; use rustc_target::abi::{Abi, Size}; @@ -19,8 +19,8 @@ mod unimap; #[cfg(test)] mod exhaustive; -use perms::Permission; -pub use tree::Tree; +use self::perms::Permission; +pub use self::tree::Tree; pub type AllocState = Tree; diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index c29bd719b15df..28f9dec7bb98a 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -1,9 +1,9 @@ use std::cmp::{Ordering, PartialOrd}; use std::fmt; +use crate::AccessKind; use crate::borrow_tracker::tree_borrows::diagnostics::TransitionError; use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness; -use crate::AccessKind; /// The activation states of a pointer. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -47,7 +47,7 @@ enum PermissionPriv { /// rejects: all child accesses (UB). Disabled, } -use PermissionPriv::*; +use self::PermissionPriv::*; impl PartialOrd for PermissionPriv { /// PermissionPriv is ordered by the reflexive transitive closure of @@ -345,18 +345,14 @@ pub mod diagnostics { use super::*; impl fmt::Display for PermissionPriv { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match self { - ReservedFrz { conflicted: false } => "Reserved", - ReservedFrz { conflicted: true } => "Reserved (conflicted)", - ReservedIM => "Reserved (interior mutable)", - Active => "Active", - Frozen => "Frozen", - Disabled => "Disabled", - } - ) + write!(f, "{}", match self { + ReservedFrz { conflicted: false } => "Reserved", + ReservedFrz { conflicted: true } => "Reserved (conflicted)", + ReservedIM => "Reserved (interior mutable)", + Active => "Active", + Frozen => "Frozen", + Disabled => "Disabled", + }) } } @@ -551,7 +547,7 @@ impl Permission { #[cfg(test)] mod propagation_optimization_checks { pub use super::*; - use crate::borrow_tracker::tree_borrows::exhaustive::{precondition, Exhaustive}; + use crate::borrow_tracker::tree_borrows::exhaustive::{Exhaustive, precondition}; impl Exhaustive for PermissionPriv { fn exhaustive() -> Box> { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 53e722259fdfb..a99c71d96b4b1 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -19,10 +19,10 @@ use rustc_span::Span; use rustc_target::abi::Size; use crate::borrow_tracker::tree_borrows::{ + Permission, diagnostics::{self, NodeDebugInfo, TbError, TransitionError}, perms::PermTransition, unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap}, - Permission, }; use crate::borrow_tracker::{GlobalState, ProtectorKind}; use crate::*; @@ -587,16 +587,13 @@ impl Tree { let mut debug_info = NodeDebugInfo::new(root_tag, root_default_perm, span); // name the root so that all allocations contain one named pointer debug_info.add_name("root of the allocation"); - nodes.insert( - root_idx, - Node { - tag: root_tag, - parent: None, - children: SmallVec::default(), - default_initial_perm: root_default_perm, - debug_info, - }, - ); + nodes.insert(root_idx, Node { + tag: root_tag, + parent: None, + children: SmallVec::default(), + default_initial_perm: root_default_perm, + debug_info, + }); nodes }; let rperms = { @@ -626,16 +623,13 @@ impl<'tcx> Tree { let idx = self.tag_mapping.insert(new_tag); let parent_idx = self.tag_mapping.get(&parent_tag).unwrap(); // Create the node - self.nodes.insert( - idx, - Node { - tag: new_tag, - parent: Some(parent_idx), - children: SmallVec::default(), - default_initial_perm, - debug_info: NodeDebugInfo::new(new_tag, default_initial_perm, span), - }, - ); + self.nodes.insert(idx, Node { + tag: new_tag, + parent: Some(parent_idx), + children: SmallVec::default(), + default_initial_perm, + debug_info: NodeDebugInfo::new(new_tag, default_initial_perm, span), + }); // Register new_tag as a child of parent_tag self.nodes.get_mut(parent_idx).unwrap().children.push(idx); // Initialize perms diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs index f64f7bf8e8c1e..5cd5040f80776 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs @@ -2,7 +2,7 @@ #![cfg(test)] use super::*; -use crate::borrow_tracker::tree_borrows::exhaustive::{precondition, Exhaustive}; +use crate::borrow_tracker::tree_borrows::exhaustive::{Exhaustive, precondition}; use std::fmt; impl Exhaustive for LocationState { diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 6fd207c92b937..b5b43f589f699 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -47,6 +47,7 @@ use std::{ }; use rustc_ast::Mutability; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashSet; use rustc_index::{Idx, IndexVec}; use rustc_middle::{mir, ty::Ty}; @@ -637,7 +638,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // The program didn't actually do a read, so suppress the memory access hooks. // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! - let old_val = this.run_for_validation(|| this.read_scalar(dest)).ok(); + let old_val = this.run_for_validation(|this| this.read_scalar(dest)).ok(); this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; this.validate_atomic_store(dest, atomic)?; this.buffered_atomic_write(val, dest, atomic, old_val) @@ -1047,32 +1048,31 @@ impl VClockAlloc { ) -> InterpResult<'tcx> { let current_span = machine.current_span(); let global = machine.data_race.as_ref().unwrap(); - if global.race_detecting() { - let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); - let mut alloc_ranges = self.alloc_ranges.borrow_mut(); - for (mem_clocks_range, mem_clocks) in - alloc_ranges.iter_mut(access_range.start, access_range.size) + if !global.race_detecting() { + return Ok(()); + } + let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); + let mut alloc_ranges = self.alloc_ranges.borrow_mut(); + for (mem_clocks_range, mem_clocks) in + alloc_ranges.iter_mut(access_range.start, access_range.size) + { + if let Err(DataRace) = + mem_clocks.read_race_detect(&mut thread_clocks, index, read_type, current_span) { - if let Err(DataRace) = - mem_clocks.read_race_detect(&mut thread_clocks, index, read_type, current_span) - { - drop(thread_clocks); - // Report data-race. - return Self::report_data_race( - global, - &machine.threads, - mem_clocks, - AccessType::NaRead(read_type), - access_range.size, - interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), - ty, - ); - } + drop(thread_clocks); + // Report data-race. + return Self::report_data_race( + global, + &machine.threads, + mem_clocks, + AccessType::NaRead(read_type), + access_range.size, + interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), + ty, + ); } - Ok(()) - } else { - Ok(()) } + Ok(()) } /// Detect data-races for an unsynchronized write operation. It will not perform @@ -1090,33 +1090,129 @@ impl VClockAlloc { ) -> InterpResult<'tcx> { let current_span = machine.current_span(); let global = machine.data_race.as_mut().unwrap(); - if global.race_detecting() { - let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); - for (mem_clocks_range, mem_clocks) in - self.alloc_ranges.get_mut().iter_mut(access_range.start, access_range.size) + if !global.race_detecting() { + return Ok(()); + } + let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); + for (mem_clocks_range, mem_clocks) in + self.alloc_ranges.get_mut().iter_mut(access_range.start, access_range.size) + { + if let Err(DataRace) = + mem_clocks.write_race_detect(&mut thread_clocks, index, write_type, current_span) { - if let Err(DataRace) = mem_clocks.write_race_detect( - &mut thread_clocks, - index, - write_type, - current_span, - ) { - drop(thread_clocks); - // Report data-race - return Self::report_data_race( - global, - &machine.threads, - mem_clocks, - AccessType::NaWrite(write_type), - access_range.size, - interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), - ty, - ); - } + drop(thread_clocks); + // Report data-race + return Self::report_data_race( + global, + &machine.threads, + mem_clocks, + AccessType::NaWrite(write_type), + access_range.size, + interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), + ty, + ); } - Ok(()) + } + Ok(()) + } +} + +/// Vector clock state for a stack frame (tracking the local variables +/// that do not have an allocation yet). +#[derive(Debug, Default)] +pub struct FrameState { + local_clocks: RefCell>, +} + +/// Stripped-down version of [`MemoryCellClocks`] for the clocks we need to keep track +/// of in a local that does not yet have addressable memory -- and hence can only +/// be accessed from the thread its stack frame belongs to, and cannot be access atomically. +#[derive(Debug)] +struct LocalClocks { + write: VTimestamp, + write_type: NaWriteType, + read: VTimestamp, +} + +impl Default for LocalClocks { + fn default() -> Self { + Self { write: VTimestamp::ZERO, write_type: NaWriteType::Allocate, read: VTimestamp::ZERO } + } +} + +impl FrameState { + pub fn local_write(&self, local: mir::Local, storage_live: bool, machine: &MiriMachine<'_>) { + let current_span = machine.current_span(); + let global = machine.data_race.as_ref().unwrap(); + if !global.race_detecting() { + return; + } + let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); + // This should do the same things as `MemoryCellClocks::write_race_detect`. + if !current_span.is_dummy() { + thread_clocks.clock.index_mut(index).span = current_span; + } + let mut clocks = self.local_clocks.borrow_mut(); + if storage_live { + let new_clocks = LocalClocks { + write: thread_clocks.clock[index], + write_type: NaWriteType::Allocate, + read: VTimestamp::ZERO, + }; + // There might already be an entry in the map for this, if the local was previously + // live already. + clocks.insert(local, new_clocks); } else { - Ok(()) + // This can fail to exist if `race_detecting` was false when the allocation + // occurred, in which case we can backdate this to the beginning of time. + let clocks = clocks.entry(local).or_default(); + clocks.write = thread_clocks.clock[index]; + clocks.write_type = NaWriteType::Write; + } + } + + pub fn local_read(&self, local: mir::Local, machine: &MiriMachine<'_>) { + let current_span = machine.current_span(); + let global = machine.data_race.as_ref().unwrap(); + if !global.race_detecting() { + return; + } + let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); + // This should do the same things as `MemoryCellClocks::read_race_detect`. + if !current_span.is_dummy() { + thread_clocks.clock.index_mut(index).span = current_span; + } + thread_clocks.clock.index_mut(index).set_read_type(NaReadType::Read); + // This can fail to exist if `race_detecting` was false when the allocation + // occurred, in which case we can backdate this to the beginning of time. + let mut clocks = self.local_clocks.borrow_mut(); + let clocks = clocks.entry(local).or_default(); + clocks.read = thread_clocks.clock[index]; + } + + pub fn local_moved_to_memory( + &self, + local: mir::Local, + alloc: &mut VClockAlloc, + machine: &MiriMachine<'_>, + ) { + let global = machine.data_race.as_ref().unwrap(); + if !global.race_detecting() { + return; + } + let (index, _thread_clocks) = global.active_thread_state_mut(&machine.threads); + // Get the time the last write actually happened. This can fail to exist if + // `race_detecting` was false when the write occurred, in that case we can backdate this + // to the beginning of time. + let local_clocks = self.local_clocks.borrow_mut().remove(&local).unwrap_or_default(); + for (_mem_clocks_range, mem_clocks) in alloc.alloc_ranges.get_mut().iter_mut_all() { + // The initialization write for this already happened, just at the wrong timestamp. + // Check that the thread index matches what we expect. + assert_eq!(mem_clocks.write.0, index); + // Convert the local's clocks into memory clocks. + mem_clocks.write = (index, local_clocks.write); + mem_clocks.write_type = local_clocks.write_type; + mem_clocks.read = VClock::new_with_index(index, local_clocks.read); } } } @@ -1305,69 +1401,67 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); assert!(access.is_atomic()); - if let Some(data_race) = &this.machine.data_race { - if data_race.race_detecting() { - let size = place.layout.size; - let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr(), 0)?; - // Load and log the atomic operation. - // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); - trace!( - "Atomic op({}) with ordering {:?} on {:?} (size={})", - access.description(None, None), - &atomic, - place.ptr(), - size.bytes() - ); + let Some(data_race) = &this.machine.data_race else { return Ok(()) }; + if !data_race.race_detecting() { + return Ok(()); + } + let size = place.layout.size; + let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr(), 0)?; + // Load and log the atomic operation. + // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. + let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); + trace!( + "Atomic op({}) with ordering {:?} on {:?} (size={})", + access.description(None, None), + &atomic, + place.ptr(), + size.bytes() + ); - let current_span = this.machine.current_span(); - // Perform the atomic operation. - data_race.maybe_perform_sync_operation( - &this.machine.threads, - current_span, - |index, mut thread_clocks| { - for (mem_clocks_range, mem_clocks) in - alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) - { - if let Err(DataRace) = op(mem_clocks, &mut thread_clocks, index, atomic) - { - mem::drop(thread_clocks); - return VClockAlloc::report_data_race( - data_race, - &this.machine.threads, - mem_clocks, - access, - place.layout.size, - interpret::Pointer::new( - alloc_id, - Size::from_bytes(mem_clocks_range.start), - ), - None, - ) - .map(|_| true); - } - } - - // This conservatively assumes all operations have release semantics - Ok(true) - }, - )?; - - // Log changes to atomic memory. - if tracing::enabled!(tracing::Level::TRACE) { - for (_offset, mem_clocks) in - alloc_meta.alloc_ranges.borrow().iter(base_offset, size) - { - trace!( - "Updated atomic memory({:?}, size={}) to {:#?}", - place.ptr(), - size.bytes(), - mem_clocks.atomic_ops - ); + let current_span = this.machine.current_span(); + // Perform the atomic operation. + data_race.maybe_perform_sync_operation( + &this.machine.threads, + current_span, + |index, mut thread_clocks| { + for (mem_clocks_range, mem_clocks) in + alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) + { + if let Err(DataRace) = op(mem_clocks, &mut thread_clocks, index, atomic) { + mem::drop(thread_clocks); + return VClockAlloc::report_data_race( + data_race, + &this.machine.threads, + mem_clocks, + access, + place.layout.size, + interpret::Pointer::new( + alloc_id, + Size::from_bytes(mem_clocks_range.start), + ), + None, + ) + .map(|_| true); } } + + // This conservatively assumes all operations have release semantics + Ok(true) + }, + )?; + + // Log changes to atomic memory. + if tracing::enabled!(tracing::Level::TRACE) { + for (_offset, mem_clocks) in alloc_meta.alloc_ranges.borrow().iter(base_offset, size) { + trace!( + "Updated atomic memory({:?}, size={}) to {:#?}", + place.ptr(), + size.bytes(), + mem_clocks.atomic_ops + ); } } + Ok(()) } } diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index c23e5737280e7..9c2c6ae133023 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -1,7 +1,6 @@ use std::collections::VecDeque; use rustc_index::Idx; -use rustc_middle::ty::layout::TyAndLayout; use super::sync::EvalContextExtPriv as _; use super::vector_clock::VClock; @@ -30,13 +29,17 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn init_once_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx>, - lock_layout: TyAndLayout<'tcx>, + lock: &MPlaceTy<'tcx>, offset: u64, ) -> InterpResult<'tcx, InitOnceId> { let this = self.eval_context_mut(); - this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.init_onces)? - .ok_or_else(|| err_ub_format!("init_once has invalid ID").into()) + this.get_or_create_id( + lock, + offset, + |ecx| &mut ecx.machine.sync.init_onces, + |_| Ok(Default::default()), + )? + .ok_or_else(|| err_ub_format!("init_once has invalid ID").into()) } #[inline] diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index 17789fe9f87fa..c5082b4e40b4c 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -7,4 +7,4 @@ pub mod thread; mod vector_clock; pub mod weak_memory; -pub use vector_clock::VClock; +pub use self::vector_clock::VClock; diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index d972831c7689f..bc4d805687268 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -1,10 +1,11 @@ -use std::collections::{hash_map::Entry, VecDeque}; +use std::any::Any; +use std::collections::{VecDeque, hash_map::Entry}; use std::ops::Not; use std::time::Duration; use rustc_data_structures::fx::FxHashMap; use rustc_index::{Idx, IndexVec}; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_target::abi::Size; use super::init_once::InitOnce; use super::vector_clock::VClock; @@ -77,6 +78,9 @@ struct Mutex { queue: VecDeque, /// Mutex clock. This tracks the moment of the last unlock. clock: VClock, + + /// Additional data that can be set by shim implementations. + data: Option>, } declare_id!(RwLockId); @@ -113,6 +117,9 @@ struct RwLock { /// locks. /// This is only relevant when there is an active reader. clock_current_readers: VClock, + + /// Additional data that can be set by shim implementations. + data: Option>, } declare_id!(CondvarId); @@ -127,6 +134,9 @@ struct Condvar { /// Contains the clock of the last thread to /// perform a condvar-signal. clock: VClock, + + /// Additional data that can be set by shim implementations. + data: Option>, } /// The futex state. @@ -168,23 +178,25 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Returns `None` if memory stores a non-zero invalid ID. /// /// `get_objs` must return the `IndexVec` that stores all the objects of this type. + /// `create_obj` must create the new object if initialization is needed. #[inline] - fn get_or_create_id( + fn get_or_create_id( &mut self, - lock_op: &OpTy<'tcx>, - lock_layout: TyAndLayout<'tcx>, + lock: &MPlaceTy<'tcx>, offset: u64, get_objs: impl for<'a> Fn(&'a mut MiriInterpCx<'tcx>) -> &'a mut IndexVec, + create_obj: impl for<'a> FnOnce(&'a mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, T>, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let value_place = - this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?; + let offset = Size::from_bytes(offset); + assert!(lock.layout.size >= offset + this.machine.layouts.u32.size); + let id_place = lock.offset(offset, this.machine.layouts.u32, this)?; let next_index = get_objs(this).next_index(); // Since we are lazy, this update has to be atomic. let (old, success) = this .atomic_compare_exchange_scalar( - &value_place, + &id_place, &ImmTy::from_uint(0u32, this.machine.layouts.u32), Scalar::from_u32(next_index.to_u32()), AtomicRwOrd::Relaxed, // deliberately *no* synchronization @@ -196,7 +208,8 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { // We set the in-memory ID to `next_index`, now also create this object in the machine // state. - let new_index = get_objs(this).push(T::default()); + let obj = create_obj(this)?; + let new_index = get_objs(this).push(obj); assert_eq!(next_index, new_index); Some(new_index) } else { @@ -210,6 +223,32 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { }) } + /// Eagerly creates a Miri sync structure. + /// + /// `create_id` will store the index of the sync_structure in the memory pointed to by + /// `lock_op`, so that future calls to `get_or_create_id` will see it as initialized. + /// - `lock_op` must hold a pointer to the sync structure. + /// - `lock_layout` must be the memory layout of the sync structure. + /// - `offset` must be the offset inside the sync structure where its miri id will be stored. + /// - `get_objs` is described in `get_or_create_id`. + /// - `obj` must be the new sync object. + fn create_id( + &mut self, + lock: &MPlaceTy<'tcx>, + offset: u64, + get_objs: impl for<'a> Fn(&'a mut MiriInterpCx<'tcx>) -> &'a mut IndexVec, + obj: T, + ) -> InterpResult<'tcx, Id> { + let this = self.eval_context_mut(); + let offset = Size::from_bytes(offset); + assert!(lock.layout.size >= offset + this.machine.layouts.u32.size); + let id_place = lock.offset(offset, this.machine.layouts.u32, this)?; + + let new_index = get_objs(this).push(obj); + this.write_scalar(Scalar::from_u32(new_index.to_u32()), &id_place)?; + Ok(new_index) + } + fn condvar_reacquire_mutex( &mut self, mutex: MutexId, @@ -236,37 +275,115 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // situations. impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Eagerly create and initialize a new mutex. + fn mutex_create( + &mut self, + lock: &MPlaceTy<'tcx>, + offset: u64, + data: Option>, + ) -> InterpResult<'tcx, MutexId> { + let this = self.eval_context_mut(); + this.create_id(lock, offset, |ecx| &mut ecx.machine.sync.mutexes, Mutex { + data, + ..Default::default() + }) + } + + /// Lazily create a new mutex. + /// `initialize_data` must return any additional data that a user wants to associate with the mutex. fn mutex_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx>, - lock_layout: TyAndLayout<'tcx>, + lock: &MPlaceTy<'tcx>, offset: u64, + initialize_data: impl for<'a> FnOnce( + &'a mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, Option>>, ) -> InterpResult<'tcx, MutexId> { let this = self.eval_context_mut(); - this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.mutexes)? - .ok_or_else(|| err_ub_format!("mutex has invalid ID").into()) + this.get_or_create_id( + lock, + offset, + |ecx| &mut ecx.machine.sync.mutexes, + |ecx| initialize_data(ecx).map(|data| Mutex { data, ..Default::default() }), + )? + .ok_or_else(|| err_ub_format!("mutex has invalid ID").into()) + } + + /// Retrieve the additional data stored for a mutex. + fn mutex_get_data<'a, T: 'static>(&'a mut self, id: MutexId) -> Option<&'a T> + where + 'tcx: 'a, + { + let this = self.eval_context_ref(); + this.machine.sync.mutexes[id].data.as_deref().and_then(|p| p.downcast_ref::()) } fn rwlock_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx>, - lock_layout: TyAndLayout<'tcx>, + lock: &MPlaceTy<'tcx>, offset: u64, + initialize_data: impl for<'a> FnOnce( + &'a mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, Option>>, ) -> InterpResult<'tcx, RwLockId> { let this = self.eval_context_mut(); - this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.rwlocks)? - .ok_or_else(|| err_ub_format!("rwlock has invalid ID").into()) + this.get_or_create_id( + lock, + offset, + |ecx| &mut ecx.machine.sync.rwlocks, + |ecx| initialize_data(ecx).map(|data| RwLock { data, ..Default::default() }), + )? + .ok_or_else(|| err_ub_format!("rwlock has invalid ID").into()) + } + + /// Retrieve the additional data stored for a rwlock. + fn rwlock_get_data<'a, T: 'static>(&'a mut self, id: RwLockId) -> Option<&'a T> + where + 'tcx: 'a, + { + let this = self.eval_context_ref(); + this.machine.sync.rwlocks[id].data.as_deref().and_then(|p| p.downcast_ref::()) + } + + /// Eagerly create and initialize a new condvar. + fn condvar_create( + &mut self, + condvar: &MPlaceTy<'tcx>, + offset: u64, + data: Option>, + ) -> InterpResult<'tcx, CondvarId> { + let this = self.eval_context_mut(); + this.create_id(condvar, offset, |ecx| &mut ecx.machine.sync.condvars, Condvar { + data, + ..Default::default() + }) } fn condvar_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx>, - lock_layout: TyAndLayout<'tcx>, + lock: &MPlaceTy<'tcx>, offset: u64, + initialize_data: impl for<'a> FnOnce( + &'a mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, Option>>, ) -> InterpResult<'tcx, CondvarId> { let this = self.eval_context_mut(); - this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.condvars)? - .ok_or_else(|| err_ub_format!("condvar has invalid ID").into()) + this.get_or_create_id( + lock, + offset, + |ecx| &mut ecx.machine.sync.condvars, + |ecx| initialize_data(ecx).map(|data| Condvar { data, ..Default::default() }), + )? + .ok_or_else(|| err_ub_format!("condvar has invalid ID").into()) + } + + /// Retrieve the additional data stored for a condvar. + fn condvar_get_data<'a, T: 'static>(&'a mut self, id: CondvarId) -> Option<&'a T> + where + 'tcx: 'a, + { + let this = self.eval_context_ref(); + this.machine.sync.condvars[id].data.as_deref().and_then(|p| p.downcast_ref::()) } #[inline] diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 79f292f696599..4efe2beb1558e 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -530,7 +530,9 @@ impl<'tcx> ThreadManager<'tcx> { } /// Mutably borrow the stack of the active thread. - fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + pub fn active_thread_stack_mut( + &mut self, + ) -> &mut Vec>> { &mut self.threads[self.active_thread].stack } pub fn all_stacks( @@ -888,12 +890,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; // We make a full copy of this allocation. - let mut alloc = - alloc.inner().adjust_from_tcx(&this.tcx, |bytes, align| Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)), |ptr| this.global_root_pointer(ptr))?; + let mut alloc = alloc.inner().adjust_from_tcx( + &this.tcx, + |bytes, align| { + Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)) + }, + |ptr| this.global_root_pointer(ptr), + )?; // This allocation will be deallocated when the thread dies, so it is not in read-only memory. alloc.mutability = Mutability::Mut; // Create a fresh allocation with this content. - let ptr = this.allocate_raw_ptr(alloc, MiriMemoryKind::Tls.into())?; + let ptr = this.insert_allocation(alloc, MiriMemoryKind::Tls.into())?; this.machine.threads.set_thread_local_alloc(def_id, ptr); Ok(ptr) } diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index c3496bc1a0c8a..901b097c1bd77 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -1,5 +1,5 @@ use rustc_index::Idx; -use rustc_span::{Span, SpanData, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, SpanData}; use smallvec::SmallVec; use std::{ cmp::Ordering, @@ -130,6 +130,9 @@ impl Ord for VTimestamp { /// also this means that there is only one unique valid length /// for each set of vector clock values and hence the PartialEq /// and Eq derivations are correct. +/// +/// This means we cannot represent a clock where the last entry is a timestamp-0 read that occurs +/// because of a retag. That's fine, all it does is risk wrong diagnostics in a extreme corner case. #[derive(PartialEq, Eq, Default, Debug)] pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); @@ -137,6 +140,9 @@ impl VClock { /// Create a new vector-clock containing all zeros except /// for a value at the given index pub(super) fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { + if timestamp.time() == 0 { + return VClock::default(); + } let len = index.index() + 1; let mut vec = smallvec::smallvec![VTimestamp::ZERO; len]; vec[index.index()] = timestamp; diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 92f344d13b72c..4445550512b49 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Write}; use std::num::NonZero; use rustc_errors::{Diag, DiagMessage, Level}; -use rustc_span::{SpanData, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, SpanData, Symbol}; use rustc_target::abi::{Align, Size}; use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory; diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index bb623c66892a0..8c8ed9c4ddc3b 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -13,9 +13,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::{ - self, + self, Ty, TyCtxt, layout::{LayoutCx, LayoutOf}, - Ty, TyCtxt, }; use rustc_target::spec::abi::Abi; @@ -277,7 +276,7 @@ pub fn create_ecx<'tcx>( config: &MiriConfig, ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> { let param_env = ty::ParamEnv::reveal_all(); - let layout_cx = LayoutCx { tcx, param_env }; + let layout_cx = LayoutCx::new(tcx, param_env); let mut ecx = InterpCx::new(tcx, rustc_span::DUMMY_SP, param_env, MiriMachine::new(config, layout_cx)); @@ -458,14 +457,7 @@ pub fn eval_entry<'tcx>( panic::resume_unwind(panic_payload) }); // `Ok` can never happen. - #[cfg(not(bootstrap))] let Err(res) = res; - #[cfg(bootstrap)] - let res = match res { - Err(res) => res, - // `Ok` can never happen - Ok(never) => match never {}, - }; // Machine cleanup. Only do this if all threads have terminated; threads that are still running // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396). diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index a546ad20fef98..10e5882b5ba89 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -7,12 +7,12 @@ use std::time::Duration; use rand::RngCore; -use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_hir::{ - def::{DefKind, Namespace}, - def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}, Safety, + def::{DefKind, Namespace}, + def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE}, }; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -21,9 +21,8 @@ use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::mir; use rustc_middle::ty::layout::{FnAbiOf, MaybeResult}; use rustc_middle::ty::{ - self, + self, FloatTy, IntTy, Ty, TyCtxt, UintTy, layout::{LayoutOf, TyAndLayout}, - FloatTy, IntTy, Ty, TyCtxt, UintTy, }; use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; @@ -869,7 +868,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type fn deref_pointer_as( &self, - op: &impl Readable<'tcx, Provenance>, + op: &impl Projectable<'tcx, Provenance>, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_ref(); @@ -880,7 +879,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Calculates the MPlaceTy given the offset and layout of an access on an operand fn deref_pointer_and_offset( &self, - op: &impl Readable<'tcx, Provenance>, + op: &impl Projectable<'tcx, Provenance>, offset: u64, base_layout: TyAndLayout<'tcx>, value_layout: TyAndLayout<'tcx>, @@ -897,7 +896,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn deref_pointer_and_read( &self, - op: &impl Readable<'tcx, Provenance>, + op: &impl Projectable<'tcx, Provenance>, offset: u64, base_layout: TyAndLayout<'tcx>, value_layout: TyAndLayout<'tcx>, @@ -909,7 +908,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn deref_pointer_and_write( &mut self, - op: &impl Readable<'tcx, Provenance>, + op: &impl Projectable<'tcx, Provenance>, offset: u64, value: impl Into, base_layout: TyAndLayout<'tcx>, diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index d76f622e84baf..6365e0efd5129 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -1,7 +1,7 @@ use rustc_middle::{mir, mir::BinOp, ty}; use crate::*; -use helpers::check_arg_count; +use self::helpers::check_arg_count; pub enum AtomicOp { /// The `bool` indicates whether the result of the operation should be negated (`UnOp::Not`, diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 18b22827bdb15..b8352b575a4ac 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -3,22 +3,19 @@ mod atomic; mod simd; -use std::iter; - use rand::Rng; use rustc_apfloat::{Float, Round}; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::{ mir, ty::{self, FloatTy}, }; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use rustc_target::abi::Size; use crate::*; -use atomic::EvalContextExt as _; -use helpers::{check_arg_count, ToHost, ToSoft}; -use simd::EvalContextExt as _; +use self::atomic::EvalContextExt as _; +use self::helpers::{ToHost, ToSoft, check_arg_count}; +use self::simd::EvalContextExt as _; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { @@ -119,19 +116,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.copy_op(dest, &place)?; } - "write_bytes" | "volatile_set_memory" => { + "volatile_set_memory" => { let [ptr, val_byte, count] = check_arg_count(args)?; - let ty = ptr.layout.ty.builtin_deref(true).unwrap(); - let ty_layout = this.layout_of(ty)?; - let val_byte = this.read_scalar(val_byte)?.to_u8()?; - let ptr = this.read_pointer(ptr)?; - let count = this.read_target_usize(count)?; - // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), - // but no actual allocation can be big enough for the difference to be noticeable. - let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { - err_ub_format!("overflow computing total size of `{intrinsic_name}`") - })?; - this.write_bytes_ptr(ptr, iter::repeat(val_byte).take(byte_count.bytes_usize()))?; + this.write_bytes_intrinsic(ptr, val_byte, count, "volatile_set_memory")?; } // Memory model / provenance manipulation @@ -152,8 +139,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // ``` // Would not be considered UB, or the other way around (`is_val_statically_known(0)`). "is_val_statically_known" => { - let [arg] = check_arg_count(args)?; - this.validate_operand(arg, /*recursive*/ false)?; + let [_arg] = check_arg_count(args)?; + // FIXME: should we check for validity here? It's tricky because we do not have a + // place. Codegen does not seem to set any attributes like `noundef` for intrinsic + // calls, so we don't *have* to do anything. let branch: bool = this.machine.rng.get_mut().gen(); this.write_scalar(Scalar::from_bool(branch), dest)?; } diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index a5afd029b6519..2bc11d63a3951 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -3,10 +3,10 @@ use either::Either; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::{mir, ty, ty::FloatTy}; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use rustc_target::abi::{Endian, HasDataLayout}; -use crate::helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool, ToHost, ToSoft}; +use crate::helpers::{ToHost, ToSoft, bool_to_simd_element, check_arg_count, simd_element_to_bool}; use crate::*; #[derive(Copy, Clone)] @@ -50,8 +50,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "bitreverse" => { let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, op_len); @@ -200,9 +200,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { use mir::BinOp; let [left, right] = check_arg_count(args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -291,10 +291,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "fma" => { let [a, b, c] = check_arg_count(args)?; - let (a, a_len) = this.operand_to_simd(a)?; - let (b, b_len) = this.operand_to_simd(b)?; - let (c, c_len) = this.operand_to_simd(c)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (a, a_len) = this.project_to_simd(a)?; + let (b, b_len) = this.project_to_simd(b)?; + let (c, c_len) = this.project_to_simd(c)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, a_len); assert_eq!(dest_len, b_len); @@ -345,7 +345,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { use mir::BinOp; let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; + let (op, op_len) = this.project_to_simd(op)?; let imm_from_bool = |b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool); @@ -408,7 +408,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { use mir::BinOp; let [op, init] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; + let (op, op_len) = this.project_to_simd(op)?; let init = this.read_immediate(init)?; let mir_op = match intrinsic_name { @@ -426,10 +426,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "select" => { let [mask, yes, no] = check_arg_count(args)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (yes, yes_len) = this.operand_to_simd(yes)?; - let (no, no_len) = this.operand_to_simd(no)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (mask, mask_len) = this.project_to_simd(mask)?; + let (yes, yes_len) = this.project_to_simd(yes)?; + let (no, no_len) = this.project_to_simd(no)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, mask_len); assert_eq!(dest_len, yes_len); @@ -448,9 +448,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Variant of `select` that takes a bitmask rather than a "vector of bool". "select_bitmask" => { let [mask, yes, no] = check_arg_count(args)?; - let (yes, yes_len) = this.operand_to_simd(yes)?; - let (no, no_len) = this.operand_to_simd(no)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (yes, yes_len) = this.project_to_simd(yes)?; + let (no, no_len) = this.project_to_simd(no)?; + let (dest, dest_len) = this.project_to_simd(dest)?; let bitmask_len = dest_len.next_multiple_of(8); if bitmask_len > 64 { throw_unsup_format!( @@ -522,7 +522,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts a "vector of bool" into a bitmask. "bitmask" => { let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; + let (op, op_len) = this.project_to_simd(op)?; let bitmask_len = op_len.next_multiple_of(8); if bitmask_len > 64 { throw_unsup_format!( @@ -570,8 +570,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "cast" | "as" | "cast_ptr" | "expose_provenance" | "with_exposed_provenance" => { let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, op_len); @@ -627,9 +627,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "shuffle_generic" => { let [left, right] = check_arg_count(args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; let index = generic_args[2] .expect_const() @@ -662,26 +662,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "shuffle" => { let [left, right, index] = check_arg_count(args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - // `index` is an array, not a SIMD type - let ty::Array(_, index_len) = index.layout.ty.kind() else { - span_bug!( - this.cur_span(), - "simd_shuffle index argument has non-array type {}", - index.layout.ty - ) - }; - let index_len = index_len.eval_target_usize(*this.tcx, this.param_env()); + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (index, index_len) = this.project_to_simd(index)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(left_len, right_len); assert_eq!(index_len, dest_len); for i in 0..dest_len { let src_index: u64 = this - .read_immediate(&this.project_index(index, i)?)? + .read_immediate(&this.project_index(&index, i)?)? .to_scalar() .to_u32()? .into(); @@ -702,10 +693,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "gather" => { let [passthru, ptrs, mask] = check_arg_count(args)?; - let (passthru, passthru_len) = this.operand_to_simd(passthru)?; - let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (passthru, passthru_len) = this.project_to_simd(passthru)?; + let (ptrs, ptrs_len) = this.project_to_simd(ptrs)?; + let (mask, mask_len) = this.project_to_simd(mask)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, passthru_len); assert_eq!(dest_len, ptrs_len); @@ -728,9 +719,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "scatter" => { let [value, ptrs, mask] = check_arg_count(args)?; - let (value, value_len) = this.operand_to_simd(value)?; - let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; + let (value, value_len) = this.project_to_simd(value)?; + let (ptrs, ptrs_len) = this.project_to_simd(ptrs)?; + let (mask, mask_len) = this.project_to_simd(mask)?; assert_eq!(ptrs_len, value_len); assert_eq!(ptrs_len, mask_len); @@ -748,10 +739,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "masked_load" => { let [mask, ptr, default] = check_arg_count(args)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; + let (mask, mask_len) = this.project_to_simd(mask)?; let ptr = this.read_pointer(ptr)?; - let (default, default_len) = this.operand_to_simd(default)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (default, default_len) = this.project_to_simd(default)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, mask_len); assert_eq!(dest_len, default_len); @@ -775,9 +766,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "masked_store" => { let [mask, ptr, vals] = check_arg_count(args)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; + let (mask, mask_len) = this.project_to_simd(mask)?; let ptr = this.read_pointer(ptr)?; - let (vals, vals_len) = this.operand_to_simd(vals)?; + let (vals, vals_len) = this.project_to_simd(vals)?; assert_eq!(mask_len, vals_len); diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 8a59206943d18..6e015813e77a7 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -51,6 +51,8 @@ clippy::cast_lossless, clippy::cast_possible_truncation, )] +#![cfg_attr(not(bootstrap), feature(unqualified_local_imports))] +#![cfg_attr(not(bootstrap), warn(unqualified_local_imports))] // Needed for rustdoc from bootstrap (with `-Znormalize-docs`). #![recursion_limit = "256"] @@ -113,13 +115,13 @@ pub type PlaceTy<'tcx> = interpret::PlaceTy<'tcx, machine::Provenance>; pub type MPlaceTy<'tcx> = interpret::MPlaceTy<'tcx, machine::Provenance>; pub use crate::intrinsics::EvalContextExt as _; +pub use crate::shims::EmulateItemResult; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::TlsData; -pub use crate::shims::EmulateItemResult; pub use crate::alloc_addresses::{EvalContextExt as _, ProvenanceMode}; pub use crate::alloc_bytes::MiriAllocBytes; @@ -140,11 +142,11 @@ pub use crate::concurrency::{ }, }; pub use crate::diagnostics::{ - report_error, EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, + EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error, }; pub use crate::eval::{ - create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, - ValidationMode, + AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, ValidationMode, + create_ecx, eval_entry, }; pub use crate::helpers::{AccessKind, EvalContextExt as _}; pub use crate::machine::{ diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 66c6966d1a6c3..b93feeeee3365 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -8,9 +8,9 @@ use std::fmt; use std::path::Path; use std::process; -use rand::rngs::StdRng; use rand::Rng; use rand::SeedableRng; +use rand::rngs::StdRng; use rustc_attr::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -20,9 +20,8 @@ use rustc_middle::{ mir, query::TyCtxtAt, ty::{ - self, - layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout}, - Instance, Ty, TyCtxt, + self, Instance, Ty, TyCtxt, + layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout}, }, }; use rustc_session::config::InliningThreshold; @@ -81,24 +80,42 @@ pub struct FrameExtra<'tcx> { /// an additional bit of "salt" into the cache key. This salt is fixed per-frame /// so that within a call, a const will have a stable address. salt: usize, + + /// Data race detector per-frame data. + pub data_race: Option, } impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = - self; + let FrameExtra { + borrow_tracker, + catch_unwind, + timing: _, + is_user_relevant, + salt, + data_race, + } = self; f.debug_struct("FrameData") .field("borrow_tracker", borrow_tracker) .field("catch_unwind", catch_unwind) + .field("is_user_relevant", is_user_relevant) + .field("salt", salt) + .field("data_race", data_race) .finish() } } impl VisitProvenance for FrameExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = - self; + let FrameExtra { + catch_unwind, + borrow_tracker, + timing: _, + is_user_relevant: _, + salt: _, + data_race: _, + } = self; catch_unwind.visit_provenance(visit); borrow_tracker.visit_provenance(visit); @@ -363,8 +380,8 @@ pub struct PrimitiveLayouts<'tcx> { } impl<'tcx> PrimitiveLayouts<'tcx> { - fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { - let tcx = layout_cx.tcx; + fn new(layout_cx: LayoutCx<'tcx>) -> Result> { + let tcx = layout_cx.tcx(); let mut_raw_ptr = Ty::new_mut_ptr(tcx, tcx.types.unit); let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit); Ok(Self { @@ -535,9 +552,9 @@ pub struct MiriMachine<'tcx> { pub(crate) basic_block_count: u64, /// Handle of the optional shared object file for native functions. - #[cfg(target_os = "linux")] + #[cfg(unix)] pub native_lib: Option<(libloading::Library, std::path::PathBuf)>, - #[cfg(not(target_os = "linux"))] + #[cfg(not(unix))] pub native_lib: Option, /// Run a garbage collector for BorTags every N basic blocks. @@ -572,22 +589,20 @@ pub struct MiriMachine<'tcx> { /// Invariant: the promised alignment will never be less than the native alignment of the /// allocation. pub(crate) symbolic_alignment: RefCell>, + + /// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes). + union_data_ranges: FxHashMap, RangeSet>, } impl<'tcx> MiriMachine<'tcx> { - pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { - let tcx = layout_cx.tcx; + pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx>) -> Self { + let tcx = layout_cx.tcx(); let local_crates = helpers::get_local_crates(tcx); let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); let profiler = config.measureme_out.as_ref().map(|out| { - let crate_name = layout_cx - .tcx - .sess - .opts - .crate_name - .clone() - .unwrap_or_else(|| "unknown-crate".to_string()); + let crate_name = + tcx.sess.opts.crate_name.clone().unwrap_or_else(|| "unknown-crate".to_string()); let pid = process::id(); // We adopt the same naming scheme for the profiler output that rustc uses. In rustc, // the PID is padded so that the nondeterministic value of the PID does not spread @@ -678,9 +693,9 @@ impl<'tcx> MiriMachine<'tcx> { report_progress: config.report_progress, basic_block_count: 0, clock: Clock::new(config.isolated_op == IsolatedOp::Allow), - #[cfg(target_os = "linux")] + #[cfg(unix)] native_lib: config.native_lib.as_ref().map(|lib_file_path| { - let target_triple = layout_cx.tcx.sess.opts.target_triple.triple(); + let target_triple = tcx.sess.opts.target_triple.triple(); // Check if host target == the session target. if env!("TARGET") != target_triple { panic!( @@ -700,9 +715,9 @@ impl<'tcx> MiriMachine<'tcx> { lib_file_path.clone(), ) }), - #[cfg(not(target_os = "linux"))] + #[cfg(not(unix))] native_lib: config.native_lib.as_ref().map(|_| { - panic!("loading external .so files is only supported on Linux") + panic!("calling functions from native libraries via FFI is only supported on Unix") }), gc_interval: config.gc_interval, since_gc: 0, @@ -714,6 +729,7 @@ impl<'tcx> MiriMachine<'tcx> { allocation_spans: RefCell::new(FxHashMap::default()), const_cache: RefCell::new(FxHashMap::default()), symbolic_alignment: RefCell::new(FxHashMap::default()), + union_data_ranges: FxHashMap::default(), } } @@ -826,6 +842,7 @@ impl VisitProvenance for MiriMachine<'_> { allocation_spans: _, const_cache: _, symbolic_alignment: _, + union_data_ranges: _, } = self; threads.visit_provenance(visit); @@ -1062,13 +1079,10 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { // Call the lang item. let panic = ecx.tcx.lang_items().get(reason.lang_item()).unwrap(); let panic = ty::Instance::mono(ecx.tcx.tcx, panic); - ecx.call_function( - panic, - Abi::Rust, - &[], - None, - StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable }, - )?; + ecx.call_function(panic, Abi::Rust, &[], None, StackPopCleanup::Goto { + ret: None, + unwind: mir::UnwindAction::Unreachable, + })?; Ok(()) } @@ -1277,12 +1291,12 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ) -> InterpResult<'tcx, Cow<'b, Allocation>> { let kind = Self::GLOBAL_KIND.unwrap().into(); - let alloc = alloc.adjust_from_tcx(&ecx.tcx, + let alloc = alloc.adjust_from_tcx( + &ecx.tcx, |bytes, align| ecx.get_global_alloc_bytes(id, kind, bytes, align), |ptr| ecx.global_root_pointer(ptr), )?; - let extra = - Self::init_alloc_extra(ecx, id, kind, alloc.size(), alloc.align)?; + let extra = Self::init_alloc_extra(ecx, id, kind, alloc.size(), alloc.align)?; Ok(Cow::Owned(alloc.with_extra(extra))) } @@ -1441,6 +1455,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { timing, is_user_relevant: ecx.machine.is_user_relevant(&frame), salt: ecx.machine.rng.borrow_mut().gen::() % ADDRS_PER_ANON_GLOBAL, + data_race: ecx.machine.data_race.as_ref().map(|_| data_race::FrameState::default()), }; Ok(frame.with_extra(extra)) @@ -1546,7 +1561,25 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { res } - fn after_local_allocated( + fn after_local_read(ecx: &InterpCx<'tcx, Self>, local: mir::Local) -> InterpResult<'tcx> { + if let Some(data_race) = &ecx.frame().extra.data_race { + data_race.local_read(local, &ecx.machine); + } + Ok(()) + } + + fn after_local_write( + ecx: &mut InterpCx<'tcx, Self>, + local: mir::Local, + storage_live: bool, + ) -> InterpResult<'tcx> { + if let Some(data_race) = &ecx.frame().extra.data_race { + data_race.local_write(local, storage_live, &ecx.machine); + } + Ok(()) + } + + fn after_local_moved_to_memory( ecx: &mut InterpCx<'tcx, Self>, local: mir::Local, mplace: &MPlaceTy<'tcx>, @@ -1554,9 +1587,17 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else { panic!("after_local_allocated should only be called on fresh allocations"); }; + // Record the span where this was allocated: the declaration of the local. let local_decl = &ecx.frame().body().local_decls[local]; let span = local_decl.source_info.span; ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None)); + // The data race system has to fix the clocks used for this write. + let (alloc_info, machine) = ecx.get_alloc_extra_mut(alloc_id)?; + if let Some(data_race) = + &machine.threads.active_thread_stack().last().unwrap().extra.data_race + { + data_race.local_moved_to_memory(local, alloc_info.data_race.as_mut().unwrap(), machine); + } Ok(()) } @@ -1627,4 +1668,12 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx.machine.rng.borrow_mut().gen::() % ADDRS_PER_ANON_GLOBAL } } + + fn cached_union_data_range<'e>( + ecx: &'e mut InterpCx<'tcx, Self>, + ty: Ty<'tcx>, + compute_range: impl FnOnce() -> RangeSet, + ) -> Cow<'e, RangeSet> { + Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range)) + } } diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index bc44e672bd85e..1b6a7255eefbe 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -1,6 +1,6 @@ use std::iter; -use rand::{seq::IteratorRandom, Rng}; +use rand::{Rng, seq::IteratorRandom}; use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir; use rustc_target::abi::Size; diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 9bb6777a9b047..edff17c0514ce 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -2,7 +2,7 @@ use crate::*; use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance, Ty}; -use rustc_span::{hygiene, BytePos, Loc, Symbol}; +use rustc_span::{BytePos, Loc, Symbol, hygiene}; use rustc_target::{abi::Size, spec::abi::Abi}; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 6586ea8e48cff..279df042dea97 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -3,7 +3,7 @@ use std::ffi::{OsStr, OsString}; use rustc_data_structures::fx::FxHashMap; use crate::*; -use shims::{unix::UnixEnvVars, windows::WindowsEnvVars}; +use self::shims::{unix::UnixEnvVars, windows::WindowsEnvVars}; #[derive(Default)] pub enum EnvVars<'tcx> { diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 17ac2638a69f4..788de8162cb70 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -63,10 +63,10 @@ impl<'tcx> MiriMachine<'tcx> { match this.tcx.sess.target.os.as_ref() { "linux" => { - Self::null_ptr_extern_statics( - this, - &["__cxa_thread_atexit_impl", "__clock_gettime64"], - )?; + Self::null_ptr_extern_statics(this, &[ + "__cxa_thread_atexit_impl", + "__clock_gettime64", + ])?; Self::weak_symbol_extern_statics(this, &["getrandom", "statx"])?; } "freebsd" => { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index d40dbdba80f1e..11cb9740e3e6d 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -15,7 +15,7 @@ use rustc_target::{ use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; use crate::*; -use helpers::{ToHost, ToSoft}; +use self::helpers::{ToHost, ToSoft}; /// Type of dynamic symbols (for `dlsym` et al) #[derive(Debug, Copy, Clone)] @@ -196,7 +196,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { if size == 0 { throw_ub_format!("creating allocation with size 0"); } - if i128::from(size) > this.tcx.data_layout.pointer_size.signed_int_max() { + if size > this.max_size_of_val().bytes() { throw_ub_format!("creating an allocation larger than half the address space"); } if let Err(e) = Align::from_bytes(align) { @@ -226,7 +226,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); // First deal with any external C functions in linked .so file. - #[cfg(target_os = "linux")] + #[cfg(unix)] if this.machine.native_lib.as_ref().is_some() { use crate::shims::native_lib::EvalContextExt as _; // An Ok(false) here means that the function being called was not exported @@ -441,19 +441,34 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "malloc" => { let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_target_usize(size)?; - let res = this.malloc(size, /*zero_init:*/ false)?; - this.write_pointer(res, dest)?; + if size <= this.max_size_of_val().bytes() { + let res = this.malloc(size, /*zero_init:*/ false)?; + this.write_pointer(res, dest)?; + } else { + // If this does not fit in an isize, return null and, on Unix, set errno. + if this.target_os_is_unix() { + let einval = this.eval_libc("ENOMEM"); + this.set_last_error(einval)?; + } + this.write_null(dest)?; + } } "calloc" => { - let [items, len] = + let [items, elem_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let items = this.read_target_usize(items)?; - let len = this.read_target_usize(len)?; - let size = items - .checked_mul(len) - .ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; - let res = this.malloc(size, /*zero_init:*/ true)?; - this.write_pointer(res, dest)?; + let elem_size = this.read_target_usize(elem_size)?; + if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) { + let res = this.malloc(size.bytes(), /*zero_init:*/ true)?; + this.write_pointer(res, dest)?; + } else { + // On size overflow, return null and, on Unix, set errno. + if this.target_os_is_unix() { + let einval = this.eval_libc("ENOMEM"); + this.set_last_error(einval)?; + } + this.write_null(dest)?; + } } "free" => { let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -465,8 +480,17 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_target_usize(new_size)?; - let res = this.realloc(old_ptr, new_size)?; - this.write_pointer(res, dest)?; + if new_size <= this.max_size_of_val().bytes() { + let res = this.realloc(old_ptr, new_size)?; + this.write_pointer(res, dest)?; + } else { + // If this does not fit in an isize, return null and, on Unix, set errno. + if this.target_os_is_unix() { + let einval = this.eval_libc("ENOMEM"); + this.set_last_error(einval)?; + } + this.write_null(dest)?; + } } // Rust allocation @@ -903,8 +927,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { name if name.starts_with("llvm.ctpop.v") => { let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, op_len); diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 7d5349f26b127..a689ac2b3784e 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -2,7 +2,7 @@ mod alloc; mod backtrace; -#[cfg(target_os = "linux")] +#[cfg(unix)] mod native_lib; mod unix; mod wasi; @@ -17,7 +17,7 @@ pub mod panic; pub mod time; pub mod tls; -pub use unix::{DirTable, EpollInterestTable, FdTable}; +pub use self::unix::{DirTable, EpollInterestTable, FdTable}; /// What needs to be done after emulating an item (a shim or an intrinsic) is done. pub enum EmulateItemResult { diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 25d96fbd7331f..e4998c37f3fe6 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -240,13 +240,16 @@ fn imm_to_carg<'tcx>(v: ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'t ty::RawPtr(_, mutability) => { // Arbitrary mutable pointer accesses are not currently supported in Miri. if mutability.is_mut() { - throw_unsup_format!("unsupported mutable pointer type for native call: {}", v.layout.ty); + throw_unsup_format!( + "unsupported mutable pointer type for native call: {}", + v.layout.ty + ); } else { let s = v.to_scalar().to_pointer(cx)?.addr(); // This relies on the `expose_provenance` in `addr_from_alloc_id`. CArg::RawPtr(std::ptr::with_exposed_provenance_mut(s.bytes_usize())) } - }, + } _ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty), }) } diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index 533992e35ab17..a1be2ae8b588b 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -7,8 +7,8 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf; use crate::*; diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index ab705ddccab6e..52c4394591c2d 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -13,11 +13,11 @@ use rustc_ast::Mutability; use rustc_middle::{mir, ty}; -use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; +use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use self::helpers::check_arg_count; /// Holds all of the relevant data for when unwinding hits a `try` frame. #[derive(Debug)] @@ -248,13 +248,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Call the lang item associated with this message. let fn_item = this.tcx.require_lang_item(msg.panic_function(), None); let instance = ty::Instance::mono(this.tcx.tcx, fn_item); - this.call_function( - instance, - Abi::Rust, - &[], - None, - StackPopCleanup::Goto { ret: None, unwind }, - )?; + this.call_function(instance, Abi::Rust, &[], None, StackPopCleanup::Goto { + ret: None, + unwind, + })?; } } Ok(()) diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 52d83cd72997e..b3ea7098dfe81 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -1,7 +1,7 @@ //! Implement thread-local storage. -use std::collections::btree_map::Entry as BTreeEntry; use std::collections::BTreeMap; +use std::collections::btree_map::Entry as BTreeEntry; use std::task::Poll; use rustc_middle::ty; diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 54bf3a3ae8295..324607cc1eda3 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -4,8 +4,8 @@ use std::io::ErrorKind; use std::mem; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf; use rustc_target::abi::Size; use crate::*; diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 3ca5f6bb2dff5..6b78ce7ad47bb 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -21,53 +21,68 @@ pub(crate) enum FlockOp { Unlock, } -/// Represents an open file descriptor. +/// Represents an open file description. pub trait FileDescription: std::fmt::Debug + Any { fn name(&self) -> &'static str; - /// Reads as much as possible into the given buffer, and returns the number of bytes read. + /// Reads as much as possible into the given buffer `ptr`. + /// `len` indicates how many bytes we should try to read. + /// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error. fn read<'tcx>( &self, _self_ref: &FileDescriptionRef, _communicate_allowed: bool, - _bytes: &mut [u8], + _ptr: Pointer, + _len: usize, + _dest: &MPlaceTy<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ) -> InterpResult<'tcx> { throw_unsup_format!("cannot read from {}", self.name()); } - /// Writes as much as possible from the given buffer, and returns the number of bytes written. + /// Writes as much as possible from the given buffer `ptr`. + /// `len` indicates how many bytes we should try to write. + /// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error. fn write<'tcx>( &self, _self_ref: &FileDescriptionRef, _communicate_allowed: bool, - _bytes: &[u8], + _ptr: Pointer, + _len: usize, + _dest: &MPlaceTy<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ) -> InterpResult<'tcx> { throw_unsup_format!("cannot write to {}", self.name()); } - /// Reads as much as possible into the given buffer from a given offset, - /// and returns the number of bytes read. + /// Reads as much as possible into the given buffer `ptr` from a given offset. + /// `len` indicates how many bytes we should try to read. + /// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error. fn pread<'tcx>( &self, _communicate_allowed: bool, - _bytes: &mut [u8], _offset: u64, + _ptr: Pointer, + _len: usize, + _dest: &MPlaceTy<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ) -> InterpResult<'tcx> { throw_unsup_format!("cannot pread from {}", self.name()); } - /// Writes as much as possible from the given buffer starting at a given offset, - /// and returns the number of bytes written. + /// Writes as much as possible from the given buffer `ptr` starting at a given offset. + /// `ptr` is the pointer to the user supplied read buffer. + /// `len` indicates how many bytes we should try to write. + /// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error. fn pwrite<'tcx>( &self, _communicate_allowed: bool, - _bytes: &[u8], + _ptr: Pointer, + _len: usize, _offset: u64, + _dest: &MPlaceTy<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ) -> InterpResult<'tcx> { throw_unsup_format!("cannot pwrite to {}", self.name()); } @@ -125,14 +140,18 @@ impl FileDescription for io::Stdin { &self, _self_ref: &FileDescriptionRef, communicate_allowed: bool, - bytes: &mut [u8], - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx> { + let mut bytes = vec![0; len]; if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. helpers::isolation_abort_error("`read` from stdin")?; } - Ok(Read::read(&mut { self }, bytes)) + let result = Read::read(&mut { self }, &mut bytes); + ecx.return_read_bytes_and_count(ptr, &bytes, result, dest) } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -149,9 +168,12 @@ impl FileDescription for io::Stdout { &self, _self_ref: &FileDescriptionRef, _communicate_allowed: bool, - bytes: &[u8], - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx> { + let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; // We allow writing to stderr even with isolation enabled. let result = Write::write(&mut { self }, bytes); // Stdout is buffered, flush to make sure it appears on the @@ -160,8 +182,7 @@ impl FileDescription for io::Stdout { // the host -- there is no good in adding extra buffering // here. io::stdout().flush().unwrap(); - - Ok(result) + ecx.return_written_byte_count_or_error(result, dest) } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -178,12 +199,16 @@ impl FileDescription for io::Stderr { &self, _self_ref: &FileDescriptionRef, _communicate_allowed: bool, - bytes: &[u8], - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx> { + let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; // We allow writing to stderr even with isolation enabled. // No need to flush, stderr is not buffered. - Ok(Write::write(&mut { self }, bytes)) + let result = Write::write(&mut { self }, bytes); + ecx.return_written_byte_count_or_error(result, dest) } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -204,11 +229,14 @@ impl FileDescription for NullOutput { &self, _self_ref: &FileDescriptionRef, _communicate_allowed: bool, - bytes: &[u8], - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + _ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx> { // We just don't write anything, but report to the user that we did. - Ok(Ok(bytes.len())) + let result = Ok(len); + ecx.return_written_byte_count_or_error(result, dest) } } @@ -303,7 +331,7 @@ pub struct FdTable { impl VisitProvenance for FdTable { fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { - // All our FileDescriptor do not have any tags. + // All our FileDescription instances do not have any tags. } } @@ -337,18 +365,18 @@ impl FdTable { } pub fn insert(&mut self, fd_ref: FileDescriptionRef) -> i32 { - self.insert_ref_with_min_fd(fd_ref, 0) + self.insert_with_min_num(fd_ref, 0) } - /// Insert a file description, giving it a file descriptor that is at least `min_fd`. - fn insert_ref_with_min_fd(&mut self, file_handle: FileDescriptionRef, min_fd: i32) -> i32 { + /// Insert a file description, giving it a file descriptor that is at least `min_fd_num`. + fn insert_with_min_num(&mut self, file_handle: FileDescriptionRef, min_fd_num: i32) -> i32 { // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in // between used FDs, the find_map combinator will return it. If the first such unused FD // is after all other used FDs, the find_map combinator will return None, and we will use // the FD following the greatest FD thus far. let candidate_new_fd = - self.fds.range(min_fd..).zip(min_fd..).find_map(|((fd, _fh), counter)| { - if *fd != counter { + self.fds.range(min_fd_num..).zip(min_fd_num..).find_map(|((fd_num, _fd), counter)| { + if *fd_num != counter { // There was a gap in the fds stored, return the first unused one // (note that this relies on BTreeMap iterating in key order) Some(counter) @@ -357,61 +385,61 @@ impl FdTable { None } }); - let new_fd = candidate_new_fd.unwrap_or_else(|| { + let new_fd_num = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.fds.last_key_value().map(|(fd, _)| fd.strict_add(1)).unwrap_or(min_fd) + self.fds.last_key_value().map(|(fd_num, _)| fd_num.strict_add(1)).unwrap_or(min_fd_num) }); - self.fds.try_insert(new_fd, file_handle).unwrap(); - new_fd + self.fds.try_insert(new_fd_num, file_handle).unwrap(); + new_fd_num } - pub fn get(&self, fd: i32) -> Option { - let fd = self.fds.get(&fd)?; + pub fn get(&self, fd_num: i32) -> Option { + let fd = self.fds.get(&fd_num)?; Some(fd.clone()) } - pub fn remove(&mut self, fd: i32) -> Option { - self.fds.remove(&fd) + pub fn remove(&mut self, fd_num: i32) -> Option { + self.fds.remove(&fd_num) } - pub fn is_fd(&self, fd: i32) -> bool { - self.fds.contains_key(&fd) + pub fn is_fd_num(&self, fd_num: i32) -> bool { + self.fds.contains_key(&fd_num) } } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, Scalar> { + fn dup(&mut self, old_fd_num: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let Some(dup_fd) = this.machine.fds.get(old_fd) else { + let Some(fd) = this.machine.fds.get(old_fd_num) else { return Ok(Scalar::from_i32(this.fd_not_found()?)); }; - Ok(Scalar::from_i32(this.machine.fds.insert_ref_with_min_fd(dup_fd, 0))) + Ok(Scalar::from_i32(this.machine.fds.insert(fd))) } - fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, Scalar> { + fn dup2(&mut self, old_fd_num: i32, new_fd_num: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let Some(dup_fd) = this.machine.fds.get(old_fd) else { + let Some(fd) = this.machine.fds.get(old_fd_num) else { return Ok(Scalar::from_i32(this.fd_not_found()?)); }; - if new_fd != old_fd { + if new_fd_num != old_fd_num { // Close new_fd if it is previously opened. // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive. - if let Some(file_description) = this.machine.fds.fds.insert(new_fd, dup_fd) { + if let Some(old_new_fd) = this.machine.fds.fds.insert(new_fd_num, fd) { // Ignore close error (not interpreter's) according to dup2() doc. - file_description.close(this.machine.communicate(), this)?.ok(); + old_new_fd.close(this.machine.communicate(), this)?.ok(); } } - Ok(Scalar::from_i32(new_fd)) + Ok(Scalar::from_i32(new_fd_num)) } - fn flock(&mut self, fd: i32, op: i32) -> InterpResult<'tcx, Scalar> { + fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let Some(file_descriptor) = this.machine.fds.get(fd) else { + let Some(fd) = this.machine.fds.get(fd_num) else { return Ok(Scalar::from_i32(this.fd_not_found()?)); }; @@ -436,8 +464,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("unsupported flags {:#x}", op); }; - let result = file_descriptor.flock(this.machine.communicate(), parsed_op)?; - drop(file_descriptor); + let result = fd.flock(this.machine.communicate(), parsed_op)?; + drop(fd); // return `0` if flock is successful let result = result.map(|()| 0i32); Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) @@ -452,7 +480,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args.len() ); } - let fd = this.read_scalar(&args[0])?.to_i32()?; + let fd_num = this.read_scalar(&args[0])?.to_i32()?; let cmd = this.read_scalar(&args[1])?.to_i32()?; // We only support getting the flags for a descriptor. @@ -461,7 +489,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - Ok(Scalar::from_i32(if this.machine.fds.is_fd(fd) { + Ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) { this.eval_libc_i32("FD_CLOEXEC") } else { this.fd_not_found()? @@ -481,9 +509,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let start = this.read_scalar(&args[2])?.to_i32()?; - match this.machine.fds.get(fd) { - Some(dup_fd) => - Ok(Scalar::from_i32(this.machine.fds.insert_ref_with_min_fd(dup_fd, start))), + match this.machine.fds.get(fd_num) { + Some(fd) => Ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))), None => Ok(Scalar::from_i32(this.fd_not_found()?)), } } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { @@ -494,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(Scalar::from_i32(-1)); } - this.ffullsync_fd(fd) + this.ffullsync_fd(fd_num) } else { throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd); } @@ -503,12 +530,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn close(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let fd = this.read_scalar(fd_op)?.to_i32()?; + let fd_num = this.read_scalar(fd_op)?.to_i32()?; - let Some(file_description) = this.machine.fds.remove(fd) else { + let Some(fd) = this.machine.fds.remove(fd_num) else { return Ok(Scalar::from_i32(this.fd_not_found()?)); }; - let result = file_description.close(this.machine.communicate(), this)?; + let result = fd.close(this.machine.communicate(), this)?; // return `0` if close is successful let result = result.map(|()| 0i32); Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) @@ -532,16 +559,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// and keeps the cursor unchanged. fn read( &mut self, - fd: i32, + fd_num: i32, buf: Pointer, count: u64, offset: Option, - ) -> InterpResult<'tcx, Scalar> { + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - // Isolation check is done via `FileDescriptor` trait. + // Isolation check is done via `FileDescription` trait. - trace!("Reading from FD {}, size {}", fd, count); + trace!("Reading from FD {}, size {}", fd_num, count); // Check that the *entire* buffer is actually valid memory. this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; @@ -551,60 +579,48 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let count = count .min(u64::try_from(this.target_isize_max()).unwrap()) .min(u64::try_from(isize::MAX).unwrap()); + let count = usize::try_from(count).unwrap(); // now it fits in a `usize` let communicate = this.machine.communicate(); // We temporarily dup the FD to be able to retain mutable access to `this`. - let Some(fd) = this.machine.fds.get(fd) else { + let Some(fd) = this.machine.fds.get(fd_num) else { trace!("read: FD not found"); - return Ok(Scalar::from_target_isize(this.fd_not_found()?, this)); + let res: i32 = this.fd_not_found()?; + this.write_int(res, dest)?; + return Ok(()); }; trace!("read: FD mapped to {fd:?}"); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than // `usize::MAX` because it is bounded by the host's `isize`. - let mut bytes = vec![0; usize::try_from(count).unwrap()]; - let result = match offset { - None => fd.read(&fd, communicate, &mut bytes, this), + + match offset { + None => fd.read(&fd, communicate, buf, count, dest, this)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_target_isize(-1, this)); + this.write_int(-1, dest)?; + return Ok(()); }; - fd.pread(communicate, &mut bytes, offset, this) + fd.pread(communicate, offset, buf, count, dest, this)? } }; - - // `File::read` never returns a value larger than `count`, so this cannot fail. - match result?.map(|c| i64::try_from(c).unwrap()) { - Ok(read_bytes) => { - // If reading to `bytes` did not fail, we write those bytes to the buffer. - // Crucially, if fewer than `bytes.len()` bytes were read, only write - // that much into the output buffer! - this.write_bytes_ptr( - buf, - bytes[..usize::try_from(read_bytes).unwrap()].iter().copied(), - )?; - Ok(Scalar::from_target_isize(read_bytes, this)) - } - Err(e) => { - this.set_last_error_from_io_error(e)?; - Ok(Scalar::from_target_isize(-1, this)) - } - } + Ok(()) } fn write( &mut self, - fd: i32, + fd_num: i32, buf: Pointer, count: u64, offset: Option, - ) -> InterpResult<'tcx, Scalar> { + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - // Isolation check is done via `FileDescriptor` trait. + // Isolation check is done via `FileDescription` trait. // Check that the *entire* buffer is actually valid memory. this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; @@ -614,27 +630,72 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let count = count .min(u64::try_from(this.target_isize_max()).unwrap()) .min(u64::try_from(isize::MAX).unwrap()); + let count = usize::try_from(count).unwrap(); // now it fits in a `usize` let communicate = this.machine.communicate(); - let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned(); // We temporarily dup the FD to be able to retain mutable access to `this`. - let Some(fd) = this.machine.fds.get(fd) else { - return Ok(Scalar::from_target_isize(this.fd_not_found()?, this)); + let Some(fd) = this.machine.fds.get(fd_num) else { + let res: i32 = this.fd_not_found()?; + this.write_int(res, dest)?; + return Ok(()); }; - let result = match offset { - None => fd.write(&fd, communicate, &bytes, this), + match offset { + None => fd.write(&fd, communicate, buf, count, dest, this)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_target_isize(-1, this)); + this.write_int(-1, dest)?; + return Ok(()); }; - fd.pwrite(communicate, &bytes, offset, this) + fd.pwrite(communicate, buf, count, offset, dest, this)? } }; + Ok(()) + } - let result = result?.map(|c| i64::try_from(c).unwrap()); - Ok(Scalar::from_target_isize(this.try_unwrap_io_result(result)?, this)) + /// Helper to implement `FileDescription::read`: + /// `result` should be the return value of some underlying `read` call that used `bytes` as its output buffer. + /// The length of `bytes` must not exceed either the host's or the target's `isize`. + /// If `Result` indicates success, `bytes` is written to `buf` and the size is written to `dest`. + /// Otherwise, `-1` is written to `dest` and the last libc error is set appropriately. + fn return_read_bytes_and_count( + &mut self, + buf: Pointer, + bytes: &[u8], + result: io::Result, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + match result { + Ok(read_bytes) => { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + // Crucially, if fewer than `bytes.len()` bytes were read, only write + // that much into the output buffer! + this.write_bytes_ptr(buf, bytes[..read_bytes].iter().copied())?; + // The actual read size is always less than what got originally requested so this cannot fail. + this.write_int(u64::try_from(read_bytes).unwrap(), dest)?; + return Ok(()); + } + Err(e) => { + this.set_last_error_from_io_error(e)?; + this.write_int(-1, dest)?; + return Ok(()); + } + } + } + + /// This function writes the number of written bytes (given in `result`) to `dest`, or sets the + /// last libc error and writes -1 to dest. + fn return_written_byte_count_or_error( + &mut self, + result: io::Result, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let result = this.try_unwrap_io_result(result.map(|c| i64::try_from(c).unwrap()))?; + this.write_int(result, dest)?; + Ok(()) } } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 273a99b31164b..c06ce57e610a0 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -11,11 +11,11 @@ use crate::shims::alloc::EvalContextExt as _; use crate::shims::unix::*; use crate::*; -use shims::unix::android::foreign_items as android; -use shims::unix::freebsd::foreign_items as freebsd; -use shims::unix::linux::foreign_items as linux; -use shims::unix::macos::foreign_items as macos; -use shims::unix::solarish::foreign_items as solarish; +use self::shims::unix::android::foreign_items as android; +use self::shims::unix::freebsd::foreign_items as freebsd; +use self::shims::unix::linux::foreign_items as linux; +use self::shims::unix::macos::foreign_items as macos; +use self::shims::unix::solarish::foreign_items as solarish; pub fn is_dyn_sym(name: &str, target_os: &str) -> bool { match name { @@ -92,8 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; - let result = this.read(fd, buf, count, None)?; - this.write_scalar(result, dest)?; + this.read(fd, buf, count, None, dest)?; } "write" => { let [fd, buf, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -101,9 +100,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); - let result = this.write(fd, buf, count, None)?; - // Now, `result` is the value we return back to the program. - this.write_scalar(result, dest)?; + this.write(fd, buf, count, None, dest)?; } "pread" => { let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -111,8 +108,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; - let result = this.read(fd, buf, count, Some(offset))?; - this.write_scalar(result, dest)?; + this.read(fd, buf, count, Some(offset), dest)?; } "pwrite" => { let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -121,9 +117,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let count = this.read_target_usize(n)?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); - let result = this.write(fd, buf, count, Some(offset))?; - // Now, `result` is the value we return back to the program. - this.write_scalar(result, dest)?; + this.write(fd, buf, count, Some(offset), dest)?; } "pread64" => { let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -131,8 +125,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; - let result = this.read(fd, buf, count, Some(offset))?; - this.write_scalar(result, dest)?; + this.read(fd, buf, count, Some(offset), dest)?; } "pwrite64" => { let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -141,9 +134,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let count = this.read_target_usize(n)?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); - let result = this.write(fd, buf, count, Some(offset))?; - // Now, `result` is the value we return back to the program. - this.write_scalar(result, dest)?; + this.write(fd, buf, count, Some(offset), dest)?; } "close" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -363,14 +354,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // // Linux: https://www.unix.com/man-page/linux/3/reallocarray/ // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray - match nmemb.checked_mul(size) { + match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) { None => { let einval = this.eval_libc("ENOMEM"); this.set_last_error(einval)?; this.write_null(dest)?; } Some(len) => { - let res = this.realloc(ptr, len)?; + let res = this.realloc(ptr, len.bytes())?; this.write_pointer(res, dest)?; } } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index e00758bb98de6..c90839138ce6f 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::fs::{ - read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, + DirBuilder, File, FileType, OpenOptions, ReadDir, read_dir, remove_dir, remove_file, rename, }; use std::io::{self, ErrorKind, IsTerminal, Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; @@ -15,7 +15,7 @@ use crate::shims::os_str::bytes_to_os_str; use crate::shims::unix::fd::FileDescriptionRef; use crate::shims::unix::*; use crate::*; -use shims::time::system_time_to_duration; +use self::shims::time::system_time_to_duration; use self::fd::FlockOp; @@ -34,32 +34,43 @@ impl FileDescription for FileHandle { &self, _self_ref: &FileDescriptionRef, communicate_allowed: bool, - bytes: &mut [u8], - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - Ok((&mut &self.file).read(bytes)) + let mut bytes = vec![0; len]; + let result = (&mut &self.file).read(&mut bytes); + ecx.return_read_bytes_and_count(ptr, &bytes, result, dest) } fn write<'tcx>( &self, _self_ref: &FileDescriptionRef, communicate_allowed: bool, - bytes: &[u8], - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - Ok((&mut &self.file).write(bytes)) + let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; + let result = (&mut &self.file).write(bytes); + ecx.return_written_byte_count_or_error(result, dest) } fn pread<'tcx>( &self, communicate_allowed: bool, - bytes: &mut [u8], offset: u64, - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); + let mut bytes = vec![0; len]; // Emulates pread using seek + read + seek to restore cursor position. // Correctness of this emulation relies on sequential nature of Miri execution. // The closure is used to emulate `try` block, since we "bubble" `io::Error` using `?`. @@ -67,27 +78,31 @@ impl FileDescription for FileHandle { let mut f = || { let cursor_pos = file.stream_position()?; file.seek(SeekFrom::Start(offset))?; - let res = file.read(bytes); + let res = file.read(&mut bytes); // Attempt to restore cursor position even if the read has failed file.seek(SeekFrom::Start(cursor_pos)) .expect("failed to restore file position, this shouldn't be possible"); res }; - Ok(f()) + let result = f(); + ecx.return_read_bytes_and_count(ptr, &bytes, result, dest) } fn pwrite<'tcx>( &self, communicate_allowed: bool, - bytes: &[u8], + ptr: Pointer, + len: usize, offset: u64, - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + dest: &MPlaceTy<'tcx>, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); // Emulates pwrite using seek + write + seek to restore cursor position. // Correctness of this emulation relies on sequential nature of Miri execution. // The closure is used to emulate `try` block, since we "bubble" `io::Error` using `?`. let file = &mut &self.file; + let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; let mut f = || { let cursor_pos = file.stream_position()?; file.seek(SeekFrom::Start(offset))?; @@ -97,7 +112,8 @@ impl FileDescription for FileHandle { .expect("failed to restore file position, this shouldn't be possible"); res }; - Ok(f()) + let result = f(); + ecx.return_written_byte_count_or_error(result, dest) } fn seek<'tcx>( @@ -173,7 +189,7 @@ impl FileDescription for FileHandle { use windows_sys::Win32::{ Foundation::{ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, HANDLE, TRUE}, Storage::FileSystem::{ - LockFileEx, UnlockFile, LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, + LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, LockFileEx, UnlockFile, }, }; let fh = self.file.as_raw_handle() as HANDLE; @@ -554,10 +570,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?)) } - fn lseek64(&mut self, fd: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> { + fn lseek64(&mut self, fd_num: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - // Isolation check is done via `FileDescriptor` trait. + // Isolation check is done via `FileDescription` trait. let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { if offset < 0 { @@ -580,13 +596,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let communicate = this.machine.communicate(); - let Some(file_description) = this.machine.fds.get(fd) else { + let Some(fd) = this.machine.fds.get(fd_num) else { return Ok(Scalar::from_i64(this.fd_not_found()?)); }; - let result = file_description - .seek(communicate, seek_from)? - .map(|offset| i64::try_from(offset).unwrap()); - drop(file_description); + let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap()); + drop(fd); let result = this.try_unwrap_io_result(result)?; Ok(Scalar::from_i64(result)) @@ -721,7 +735,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(Scalar::from_i32(this.fd_not_found()?)); } - let metadata = match FileMetadata::from_fd(this, fd)? { + let metadata = match FileMetadata::from_fd_num(this, fd)? { Some(metadata) => metadata, None => return Ok(Scalar::from_i32(-1)), }; @@ -808,7 +822,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If the path is empty, and the AT_EMPTY_PATH flag is set, we query the open file // represented by dirfd, whether it's a directory or otherwise. let metadata = if path.as_os_str().is_empty() && empty_path_flag { - FileMetadata::from_fd(this, dirfd)? + FileMetadata::from_fd_num(this, dirfd)? } else { FileMetadata::from_path(this, &path, follow_symlink)? }; @@ -1260,7 +1274,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { })) } - fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> { + fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Reject if isolation is enabled. @@ -1270,30 +1284,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(Scalar::from_i32(this.fd_not_found()?)); } - let Some(file_description) = this.machine.fds.get(fd) else { + let Some(fd) = this.machine.fds.get(fd_num) else { return Ok(Scalar::from_i32(this.fd_not_found()?)); }; // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = - file_description.downcast::().ok_or_else(|| { - err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors") - })?; + let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { + err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors") + })?; if *writable { if let Ok(length) = length.try_into() { let result = file.set_len(length); - drop(file_description); + drop(fd); let result = this.try_unwrap_io_result(result.map(|_| 0i32))?; Ok(Scalar::from_i32(result)) } else { - drop(file_description); + drop(fd); let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; Ok(Scalar::from_i32(-1)) } } else { - drop(file_description); + drop(fd); // The file is not writable let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; @@ -1321,18 +1334,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { self.ffullsync_fd(fd) } - fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, Scalar> { + fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let Some(file_description) = this.machine.fds.get(fd) else { + let Some(fd) = this.machine.fds.get(fd_num) else { return Ok(Scalar::from_i32(this.fd_not_found()?)); }; // Only regular files support synchronization. - let FileHandle { file, writable } = - file_description.downcast::().ok_or_else(|| { - err_unsup_format!("`fsync` is only supported on file-backed file descriptors") - })?; + let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { + err_unsup_format!("`fsync` is only supported on file-backed file descriptors") + })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); - drop(file_description); + drop(fd); Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } @@ -1348,16 +1360,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(Scalar::from_i32(this.fd_not_found()?)); } - let Some(file_description) = this.machine.fds.get(fd) else { + let Some(fd) = this.machine.fds.get(fd) else { return Ok(Scalar::from_i32(this.fd_not_found()?)); }; // Only regular files support synchronization. - let FileHandle { file, writable } = - file_description.downcast::().ok_or_else(|| { - err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors") - })?; + let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { + err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors") + })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); - drop(file_description); + drop(fd); Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } @@ -1396,18 +1407,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(Scalar::from_i32(this.fd_not_found()?)); } - let Some(file_description) = this.machine.fds.get(fd) else { + let Some(fd) = this.machine.fds.get(fd) else { return Ok(Scalar::from_i32(this.fd_not_found()?)); }; // Only regular files support synchronization. - let FileHandle { file, writable } = - file_description.downcast::().ok_or_else(|| { - err_unsup_format!( - "`sync_data_range` is only supported on file-backed file descriptors" - ) - })?; + let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { + err_unsup_format!("`sync_data_range` is only supported on file-backed file descriptors") + })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); - drop(file_description); + drop(fd); Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } @@ -1699,15 +1707,15 @@ impl FileMetadata { FileMetadata::from_meta(ecx, metadata) } - fn from_fd<'tcx>( + fn from_fd_num<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - fd: i32, + fd_num: i32, ) -> InterpResult<'tcx, Option> { - let Some(file_description) = ecx.machine.fds.get(fd) else { + let Some(fd) = ecx.machine.fds.get(fd_num) else { return ecx.fd_not_found().map(|_: i32| None); }; - let file = &file_description + let file = &fd .downcast::() .ok_or_else(|| { err_unsup_format!( @@ -1717,7 +1725,7 @@ impl FileMetadata { .file; let metadata = file.metadata(); - drop(file_description); + drop(fd); FileMetadata::from_meta(ecx, metadata) } diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index ee86cf5f26d7f..3d4fe770e99e9 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -51,7 +51,10 @@ impl EpollEventInstance { #[derive(Clone, Debug)] pub struct EpollEventInterest { /// The file descriptor value of the file description registered. - file_descriptor: i32, + /// This is only used for ready_list, to inform userspace which FD triggered an event. + /// For that, it is crucial to preserve the original FD number. + /// This FD number must never be "dereferenced" to a file description inside Miri. + fd_num: i32, /// The events bitmask retrieved from `epoll_event`. events: u32, /// The data retrieved from `epoll_event`. @@ -61,8 +64,8 @@ pub struct EpollEventInterest { data: u64, /// Ready list of the epoll instance under which this EpollEventInterest is registered. ready_list: Rc>>, - /// The file descriptor value that this EpollEventInterest is registered under. - epfd: i32, + /// The epoll file description that this EpollEventInterest is registered under. + weak_epfd: WeakFileDescriptionRef, } /// EpollReadyEvents reflects the readiness of a file description. @@ -339,11 +342,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Create an epoll_interest. let interest = Rc::new(RefCell::new(EpollEventInterest { - file_descriptor: fd, + fd_num: fd, events, data, ready_list: Rc::clone(ready_list), - epfd: epfd_value, + weak_epfd: epfd.downgrade(), })); if op == epoll_ctl_add { @@ -553,12 +556,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if is_updated { // Edge-triggered notification only notify one thread even if there are // multiple threads block on the same epfd. - let epfd = this.machine.fds.get(epoll_interest.borrow().epfd).unwrap(); // This unwrap can never fail because if the current epoll instance were - // closed and its epfd value reused, the upgrade of weak_epoll_interest + // closed, the upgrade of weak_epoll_interest // above would fail. This guarantee holds because only the epoll instance // holds a strong ref to epoll_interest. + let epfd = epoll_interest.borrow().weak_epfd.upgrade().unwrap(); // FIXME: We can randomly pick a thread to unblock. if let Some(thread_id) = epfd.downcast::().unwrap().thread_id.borrow_mut().pop() @@ -615,7 +618,7 @@ fn check_and_update_one_event_interest<'tcx>( // If there is any event that we are interested in being specified as ready, // insert an epoll_return to the ready list. if flags != 0 { - let epoll_key = (id, epoll_event_interest.file_descriptor); + let epoll_key = (id, epoll_event_interest.fd_num); let ready_list = &mut epoll_event_interest.ready_list.borrow_mut(); let event_instance = EpollEventInstance::new(flags, epoll_event_interest.data); // Triggers the notification by inserting it to the ready list. diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index 77d16a032aae9..d1d461daa993e 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -2,18 +2,12 @@ use std::cell::{Cell, RefCell}; use std::io; use std::io::{Error, ErrorKind}; -use std::mem; - -use rustc_target::abi::Endian; use crate::shims::unix::fd::FileDescriptionRef; use crate::shims::unix::linux::epoll::{EpollReadyEvents, EvalContextExt as _}; use crate::shims::unix::*; use crate::{concurrency::VClock, *}; -// We'll only do reads and writes in chunks of size u64. -const U64_ARRAY_SIZE: usize = mem::size_of::(); - /// Maximum value that the eventfd counter can hold. const MAX_COUNTER: u64 = u64::MAX - 1; @@ -62,37 +56,50 @@ impl FileDescription for Event { &self, self_ref: &FileDescriptionRef, _communicate_allowed: bool, - bytes: &mut [u8], + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ) -> InterpResult<'tcx> { + // We're treating the buffer as a `u64`. + let ty = ecx.machine.layouts.u64; // Check the size of slice, and return error only if the size of the slice < 8. - let Some(bytes) = bytes.first_chunk_mut::() else { - return Ok(Err(Error::from(ErrorKind::InvalidInput))); - }; + if len < ty.size.bytes_usize() { + ecx.set_last_error_from_io_error(Error::from(ErrorKind::InvalidInput))?; + ecx.write_int(-1, dest)?; + return Ok(()); + } + + // eventfd read at the size of u64. + let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty); + // Block when counter == 0. let counter = self.counter.get(); if counter == 0 { if self.is_nonblock { - return Ok(Err(Error::from(ErrorKind::WouldBlock))); - } else { - //FIXME: blocking is not supported - throw_unsup_format!("eventfd: blocking is unsupported"); + ecx.set_last_error_from_io_error(Error::from(ErrorKind::WouldBlock))?; + ecx.write_int(-1, dest)?; + return Ok(()); } + + throw_unsup_format!("eventfd: blocking is unsupported"); } else { // Synchronize with all prior `write` calls to this FD. ecx.acquire_clock(&self.clock.borrow()); - // Return the counter in the host endianness using the buffer provided by caller. - *bytes = match ecx.tcx.sess.target.endian { - Endian::Little => counter.to_le_bytes(), - Endian::Big => counter.to_be_bytes(), - }; + + // Give old counter value to userspace, and set counter value to 0. + ecx.write_int(counter, &buf_place)?; self.counter.set(0); + // When any of the event happened, we check and update the status of all supported event // types for current file description. ecx.check_and_update_readiness(self_ref)?; - return Ok(Ok(U64_ARRAY_SIZE)); + // Tell userspace how many bytes we wrote. + ecx.write_int(buf_place.layout.size.bytes(), dest)?; } + + Ok(()) } /// A write call adds the 8-byte integer value supplied in @@ -111,21 +118,27 @@ impl FileDescription for Event { &self, self_ref: &FileDescriptionRef, _communicate_allowed: bool, - bytes: &[u8], + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { + ) -> InterpResult<'tcx> { + // We're treating the buffer as a `u64`. + let ty = ecx.machine.layouts.u64; // Check the size of slice, and return error only if the size of the slice < 8. - let Some(bytes) = bytes.first_chunk::() else { - return Ok(Err(Error::from(ErrorKind::InvalidInput))); - }; - // Convert from bytes to int according to host endianness. - let num = match ecx.tcx.sess.target.endian { - Endian::Little => u64::from_le_bytes(*bytes), - Endian::Big => u64::from_be_bytes(*bytes), - }; + if len < ty.layout.size.bytes_usize() { + let result = Err(Error::from(ErrorKind::InvalidInput)); + return ecx.return_written_byte_count_or_error(result, dest); + } + + // Read the user supplied value from the pointer. + let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty); + let num = ecx.read_scalar(&buf_place)?.to_u64()?; + // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1. if num == u64::MAX { - return Ok(Err(Error::from(ErrorKind::InvalidInput))); + let result = Err(Error::from(ErrorKind::InvalidInput)); + return ecx.return_written_byte_count_or_error(result, dest); } // If the addition does not let the counter to exceed the maximum value, update the counter. // Else, block. @@ -137,20 +150,20 @@ impl FileDescription for Event { } self.counter.set(new_count); } - None | Some(u64::MAX) => { + None | Some(u64::MAX) => if self.is_nonblock { - return Ok(Err(Error::from(ErrorKind::WouldBlock))); + let result = Err(Error::from(ErrorKind::WouldBlock)); + return ecx.return_written_byte_count_or_error(result, dest); } else { - //FIXME: blocking is not supported throw_unsup_format!("eventfd: blocking is unsupported"); - } - } + }, }; // When any of the event happened, we check and update the status of all supported event // types for current file description. ecx.check_and_update_readiness(self_ref)?; - Ok(Ok(U64_ARRAY_SIZE)) + // Return how many bytes we read. + ecx.write_int(buf_place.layout.size.bytes(), dest) } } diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index d64f13f63d91f..6418280d03504 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -5,10 +5,10 @@ use crate::machine::SIGRTMAX; use crate::machine::SIGRTMIN; use crate::shims::unix::*; use crate::*; -use shims::unix::linux::epoll::EvalContextExt as _; -use shims::unix::linux::eventfd::EvalContextExt as _; -use shims::unix::linux::mem::EvalContextExt as _; -use shims::unix::linux::sync::futex; +use self::shims::unix::linux::epoll::EvalContextExt as _; +use self::shims::unix::linux::eventfd::EvalContextExt as _; +use self::shims::unix::linux::mem::EvalContextExt as _; +use self::shims::unix::linux::sync::futex; pub fn is_dyn_sym(name: &str) -> bool { matches!(name, "statx") diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 47b887dec9473..95a41752059dc 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -78,6 +78,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(environ, dest)?; } + // Random data generation + "CCRandomGenerateBytes" => { + let [bytes, count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let bytes = this.read_pointer(bytes)?; + let count = this.read_target_usize(count)?; + let success = this.eval_libc_i32("kCCSuccess"); + this.gen_random(bytes, count)?; + this.write_int(success, dest)?; + } + // Time related shims "mach_absolute_time" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs index 5e5fccb587b4b..8f9237a1d46ea 100644 --- a/src/tools/miri/src/shims/unix/macos/sync.rs +++ b/src/tools/miri/src/shims/unix/macos/sync.rs @@ -14,12 +14,13 @@ use crate::*; impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn os_unfair_lock_getid(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> { + fn os_unfair_lock_getid(&mut self, lock_ptr: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> { let this = self.eval_context_mut(); + let lock = this.deref_pointer(lock_ptr)?; // os_unfair_lock holds a 32-bit value, is initialized with zero and // must be assumed to be opaque. Therefore, we can just store our // internal mutex ID in the structure without anyone noticing. - this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0) + this.mutex_get_or_create_id(&lock, 0, |_| Ok(None)) } } diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index de5a5d0759c4b..33ed0e2698226 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -42,10 +42,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let map_shared = this.eval_libc_i32("MAP_SHARED"); let map_fixed = this.eval_libc_i32("MAP_FIXED"); - // This is a horrible hack, but on MacOS and Solaris the guard page mechanism uses mmap + // This is a horrible hack, but on MacOS and Solarish the guard page mechanism uses mmap // in a way we do not support. We just give it the return value it expects. if this.frame_in_std() - && matches!(&*this.tcx.sess.target.os, "macos" | "solaris") + && matches!(&*this.tcx.sess.target.os, "macos" | "solaris" | "illumos") && (flags & map_fixed) != 0 { return Ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this)); diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 7da6d7b02a2a0..a95b4d3d30793 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -14,18 +14,18 @@ mod linux; mod macos; mod solarish; -pub use env::UnixEnvVars; -pub use fd::{FdTable, FileDescription}; -pub use fs::DirTable; -pub use linux::epoll::EpollInterestTable; +pub use self::env::UnixEnvVars; +pub use self::fd::{FdTable, FileDescription}; +pub use self::fs::DirTable; +pub use self::linux::epoll::EpollInterestTable; // All the Unix-specific extension traits -pub use env::EvalContextExt as _; -pub use fd::EvalContextExt as _; -pub use fs::EvalContextExt as _; -pub use mem::EvalContextExt as _; -pub use sync::EvalContextExt as _; -pub use thread::EvalContextExt as _; -pub use unnamed_socket::EvalContextExt as _; +pub use self::env::EvalContextExt as _; +pub use self::fd::EvalContextExt as _; +pub use self::fs::EvalContextExt as _; +pub use self::mem::EvalContextExt as _; +pub use self::sync::EvalContextExt as _; +pub use self::thread::EvalContextExt as _; +pub use self::unnamed_socket::EvalContextExt as _; // Make up some constants. const UID: u32 = 1000; diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 0b889b1182248..fea994663c076 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -11,17 +11,17 @@ use crate::*; #[inline] fn mutexattr_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { Ok(match &*ecx.tcx.sess.target.os { - "linux" | "illumos" | "solaris" | "macos" => 0, + "linux" | "illumos" | "solaris" | "macos" | "freebsd" | "android" => 0, os => throw_unsup_format!("`pthread_mutexattr` is not supported on {os}"), }) } fn mutexattr_get_kind<'tcx>( ecx: &MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx>, + attr_ptr: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( - attr_op, + attr_ptr, mutexattr_kind_offset(ecx)?, ecx.libc_ty_layout("pthread_mutexattr_t"), ecx.machine.layouts.i32, @@ -31,11 +31,11 @@ fn mutexattr_get_kind<'tcx>( fn mutexattr_set_kind<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx>, + attr_ptr: &OpTy<'tcx>, kind: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( - attr_op, + attr_ptr, mutexattr_kind_offset(ecx)?, Scalar::from_i32(kind), ecx.libc_ty_layout("pthread_mutexattr_t"), @@ -43,30 +43,40 @@ fn mutexattr_set_kind<'tcx>( ) } -/// A flag that allows to distinguish `PTHREAD_MUTEX_NORMAL` from -/// `PTHREAD_MUTEX_DEFAULT`. Since in `glibc` they have the same numeric values, -/// but different behaviour, we need a way to distinguish them. We do this by -/// setting this bit flag to the `PTHREAD_MUTEX_NORMAL` mutexes. See the comment -/// in `pthread_mutexattr_settype` function. -const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; - -fn is_mutex_kind_default<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> { - Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")) +/// To differentiate "the mutex kind has not been changed" from +/// "the mutex kind has been set to PTHREAD_MUTEX_DEFAULT and that is +/// equal to some other mutex kind", we make the default value of this +/// field *not* PTHREAD_MUTEX_DEFAULT but this special flag. +const PTHREAD_MUTEX_KIND_UNCHANGED: i32 = 0x8000000; + +/// The mutex kind. +#[derive(Debug, Clone, Copy)] +pub enum MutexKind { + Normal, + Default, + Recursive, + ErrorCheck, } -fn is_mutex_kind_normal<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> { - let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL"); - Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG)) +#[derive(Debug)] +/// Additional data that we attach with each mutex instance. +pub struct AdditionalMutexData { + /// The mutex kind, used by some mutex implementations like pthreads mutexes. + pub kind: MutexKind, + + /// The address of the mutex. + pub address: u64, } -// pthread_mutex_t is between 24 and 48 bytes, depending on the platform. +// pthread_mutex_t is between 4 and 48 bytes, depending on the platform. // We ignore the platform layout and store our own fields: // - id: u32 -// - kind: i32 fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { + // When adding a new OS, make sure we also support all its static initializers in + // `mutex_kind_from_static_initializer`! let offset = match &*ecx.tcx.sess.target.os { - "linux" | "illumos" | "solaris" => 0, + "linux" | "illumos" | "solaris" | "freebsd" | "android" => 0, // macOS stores a signature in the first bytes, so we have to move to offset 4. "macos" => 4, os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"), @@ -74,104 +84,139 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { // Sanity-check this against PTHREAD_MUTEX_INITIALIZER (but only once): // the id must start out as 0. + // FIXME on some platforms (e.g linux) there are more static initializers for + // recursive or error checking mutexes. We should also add thme in this sanity check. static SANITY: AtomicBool = AtomicBool::new(false); if !SANITY.swap(true, Ordering::Relaxed) { - let static_initializer = ecx.eval_path(&["libc", "PTHREAD_MUTEX_INITIALIZER"]); - let id_field = static_initializer - .offset(Size::from_bytes(offset), ecx.machine.layouts.u32, ecx) - .unwrap(); - let id = ecx.read_scalar(&id_field).unwrap().to_u32().unwrap(); - assert_eq!( - id, 0, - "PTHREAD_MUTEX_INITIALIZER is incompatible with our pthread_mutex layout: id is not 0" - ); + let check_static_initializer = |name| { + let static_initializer = ecx.eval_path(&["libc", name]); + let id_field = static_initializer + .offset(Size::from_bytes(offset), ecx.machine.layouts.u32, ecx) + .unwrap(); + let id = ecx.read_scalar(&id_field).unwrap().to_u32().unwrap(); + assert_eq!(id, 0, "{name} is incompatible with our pthread_mutex layout: id is not 0"); + }; + + check_static_initializer("PTHREAD_MUTEX_INITIALIZER"); + // Check non-standard initializers. + match &*ecx.tcx.sess.target.os { + "linux" => { + check_static_initializer("PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP"); + check_static_initializer("PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP"); + check_static_initializer("PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP"); + } + "illumos" | "solaris" | "macos" | "freebsd" | "android" => { + // No non-standard initializers. + } + os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"), + } } Ok(offset) } -fn mutex_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 { - // These offsets are picked for compatibility with Linux's static initializer - // macros, e.g. PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP.) - let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - - // Sanity-check this against PTHREAD_MUTEX_INITIALIZER (but only once): - // the kind must start out as PTHREAD_MUTEX_DEFAULT. - static SANITY: AtomicBool = AtomicBool::new(false); - if !SANITY.swap(true, Ordering::Relaxed) { - let static_initializer = ecx.eval_path(&["libc", "PTHREAD_MUTEX_INITIALIZER"]); - let kind_field = static_initializer - .offset(Size::from_bytes(mutex_kind_offset(ecx)), ecx.machine.layouts.i32, ecx) - .unwrap(); - let kind = ecx.read_scalar(&kind_field).unwrap().to_i32().unwrap(); - assert_eq!( - kind, - ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"), - "PTHREAD_MUTEX_INITIALIZER is incompatible with our pthread_mutex layout: kind is not PTHREAD_MUTEX_DEFAULT" - ); - } - - offset +/// Eagerly create and initialize a new mutex. +fn mutex_create<'tcx>( + ecx: &mut MiriInterpCx<'tcx>, + mutex_ptr: &OpTy<'tcx>, + kind: MutexKind, +) -> InterpResult<'tcx> { + let mutex = ecx.deref_pointer(mutex_ptr)?; + let address = mutex.ptr().addr().bytes(); + let data = Box::new(AdditionalMutexData { address, kind }); + ecx.mutex_create(&mutex, mutex_id_offset(ecx)?, Some(data))?; + Ok(()) } +/// Returns the `MutexId` of the mutex stored at `mutex_op`. +/// +/// `mutex_get_id` will also check if the mutex has been moved since its first use and +/// return an error if it has. fn mutex_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx>, + mutex_ptr: &OpTy<'tcx>, ) -> InterpResult<'tcx, MutexId> { - ecx.mutex_get_or_create_id( - mutex_op, - ecx.libc_ty_layout("pthread_mutex_t"), - mutex_id_offset(ecx)?, - ) -} + let mutex = ecx.deref_pointer(mutex_ptr)?; + let address = mutex.ptr().addr().bytes(); + + let id = ecx.mutex_get_or_create_id(&mutex, mutex_id_offset(ecx)?, |ecx| { + // This is called if a static initializer was used and the lock has not been assigned + // an ID yet. We have to determine the mutex kind from the static initializer. + let kind = mutex_kind_from_static_initializer(ecx, &mutex)?; + + Ok(Some(Box::new(AdditionalMutexData { kind, address }))) + })?; + + // Check that the mutex has not been moved since last use. + let data = ecx + .mutex_get_data::(id) + .expect("data should always exist for pthreads"); + if data.address != address { + throw_ub_format!("pthread_mutex_t can't be moved after first use") + } -fn mutex_reset_id<'tcx>( - ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx>, -) -> InterpResult<'tcx, ()> { - ecx.deref_pointer_and_write( - mutex_op, - mutex_id_offset(ecx)?, - Scalar::from_u32(0), - ecx.libc_ty_layout("pthread_mutex_t"), - ecx.machine.layouts.u32, - ) + Ok(id) } -fn mutex_get_kind<'tcx>( +/// Returns the kind of a static initializer. +fn mutex_kind_from_static_initializer<'tcx>( ecx: &MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx>, -) -> InterpResult<'tcx, i32> { - ecx.deref_pointer_and_read( - mutex_op, - mutex_kind_offset(ecx), - ecx.libc_ty_layout("pthread_mutex_t"), - ecx.machine.layouts.i32, - )? - .to_i32() + mutex: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx, MutexKind> { + Ok(match &*ecx.tcx.sess.target.os { + // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT. + "linux" => { + let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex.offset(Size::from_bytes(offset), ecx.machine.layouts.i32, ecx)?; + let kind = ecx.read_scalar(&kind_place)?.to_i32()?; + // Here we give PTHREAD_MUTEX_DEFAULT priority so that + // PTHREAD_MUTEX_INITIALIZER behaves like `pthread_mutex_init` with a NULL argument. + if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT") { + MutexKind::Default + } else { + mutex_translate_kind(ecx, kind)? + } + } + _ => MutexKind::Default, + }) } -fn mutex_set_kind<'tcx>( - ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx>, +fn mutex_translate_kind<'tcx>( + ecx: &MiriInterpCx<'tcx>, kind: i32, -) -> InterpResult<'tcx, ()> { - ecx.deref_pointer_and_write( - mutex_op, - mutex_kind_offset(ecx), - Scalar::from_i32(kind), - ecx.libc_ty_layout("pthread_mutex_t"), - ecx.machine.layouts.i32, - ) +) -> InterpResult<'tcx, MutexKind> { + Ok(if kind == (ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")) { + MutexKind::Normal + } else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") { + MutexKind::ErrorCheck + } else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") { + MutexKind::Recursive + } else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT") + || kind == PTHREAD_MUTEX_KIND_UNCHANGED + { + // We check this *last* since PTHREAD_MUTEX_DEFAULT may be numerically equal to one of the + // others, and we want an explicit `mutexattr_settype` to work as expected. + MutexKind::Default + } else { + throw_unsup_format!("unsupported type of mutex: {kind}"); + }) } -// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. +// pthread_rwlock_t is between 4 and 56 bytes, depending on the platform. // We ignore the platform layout and store our own fields: // - id: u32 +#[derive(Debug)] +/// Additional data that we attach with each rwlock instance. +pub struct AdditionalRwLockData { + /// The address of the rwlock. + pub address: u64, +} + fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { let offset = match &*ecx.tcx.sess.target.os { - "linux" | "illumos" | "solaris" => 0, + "linux" | "illumos" | "solaris" | "freebsd" | "android" => 0, // macOS stores a signature in the first bytes, so we have to move to offset 4. "macos" => 4, os => throw_unsup_format!("`pthread_rwlock` is not supported on {os}"), @@ -197,13 +242,24 @@ fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { fn rwlock_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - rwlock_op: &OpTy<'tcx>, + rwlock_ptr: &OpTy<'tcx>, ) -> InterpResult<'tcx, RwLockId> { - ecx.rwlock_get_or_create_id( - rwlock_op, - ecx.libc_ty_layout("pthread_rwlock_t"), - rwlock_id_offset(ecx)?, - ) + let rwlock = ecx.deref_pointer(rwlock_ptr)?; + let address = rwlock.ptr().addr().bytes(); + + let id = ecx.rwlock_get_or_create_id(&rwlock, rwlock_id_offset(ecx)?, |_| { + Ok(Some(Box::new(AdditionalRwLockData { address }))) + })?; + + // Check that the rwlock has not been moved since last use. + let data = ecx + .rwlock_get_data::(id) + .expect("data should always exist for pthreads"); + if data.address != address { + throw_ub_format!("pthread_rwlock_t can't be moved after first use") + } + + Ok(id) } // pthread_condattr_t. @@ -213,7 +269,7 @@ fn rwlock_get_id<'tcx>( #[inline] fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { Ok(match &*ecx.tcx.sess.target.os { - "linux" | "illumos" | "solaris" => 0, + "linux" | "illumos" | "solaris" | "freebsd" | "android" => 0, // macOS does not have a clock attribute. os => throw_unsup_format!("`pthread_condattr` clock field is not supported on {os}"), }) @@ -221,10 +277,10 @@ fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u fn condattr_get_clock_id<'tcx>( ecx: &MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx>, + attr_ptr: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( - attr_op, + attr_ptr, condattr_clock_offset(ecx)?, ecx.libc_ty_layout("pthread_condattr_t"), ecx.machine.layouts.i32, @@ -232,13 +288,26 @@ fn condattr_get_clock_id<'tcx>( .to_i32() } +fn cond_translate_clock_id<'tcx>( + ecx: &MiriInterpCx<'tcx>, + raw_id: i32, +) -> InterpResult<'tcx, ClockId> { + Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") { + ClockId::Realtime + } else if raw_id == ecx.eval_libc_i32("CLOCK_MONOTONIC") { + ClockId::Monotonic + } else { + throw_unsup_format!("unsupported clock id: {raw_id}"); + }) +} + fn condattr_set_clock_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx>, + attr_ptr: &OpTy<'tcx>, clock_id: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( - attr_op, + attr_ptr, condattr_clock_offset(ecx)?, Scalar::from_i32(clock_id), ecx.libc_ty_layout("pthread_condattr_t"), @@ -246,14 +315,13 @@ fn condattr_set_clock_id<'tcx>( ) } -// pthread_cond_t. +// pthread_cond_t can be only 4 bytes in size, depending on the platform. // We ignore the platform layout and store our own fields: // - id: u32 -// - clock: i32 fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { let offset = match &*ecx.tcx.sess.target.os { - "linux" | "illumos" | "solaris" => 0, + "linux" | "illumos" | "solaris" | "freebsd" | "android" => 0, // macOS stores a signature in the first bytes, so we have to move to offset 4. "macos" => 4, os => throw_unsup_format!("`pthread_cond` is not supported on {os}"), @@ -277,88 +345,42 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { Ok(offset) } -/// Determines whether this clock represents the real-time clock, CLOCK_REALTIME. -fn is_cond_clock_realtime<'tcx>(ecx: &MiriInterpCx<'tcx>, clock_id: i32) -> bool { - // To ensure compatibility with PTHREAD_COND_INITIALIZER on all platforms, - // we can't just compare with CLOCK_REALTIME: on Solarish, PTHREAD_COND_INITIALIZER - // makes the clock 0 but CLOCK_REALTIME is 3. - // However, we need to always be able to distinguish this from CLOCK_MONOTONIC. - clock_id == ecx.eval_libc_i32("CLOCK_REALTIME") - || (clock_id == 0 && clock_id != ecx.eval_libc_i32("CLOCK_MONOTONIC")) +#[derive(Debug, Clone, Copy)] +enum ClockId { + Realtime, + Monotonic, } -fn cond_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 { - // macOS doesn't have a clock attribute, but to keep the code uniform we store - // a clock ID in the pthread_cond_t anyway. There's enough space. - let offset = 8; - - // Sanity-check this against PTHREAD_COND_INITIALIZER (but only once): - // the clock must start out as CLOCK_REALTIME. - static SANITY: AtomicBool = AtomicBool::new(false); - if !SANITY.swap(true, Ordering::Relaxed) { - let static_initializer = ecx.eval_path(&["libc", "PTHREAD_COND_INITIALIZER"]); - let id_field = static_initializer - .offset(Size::from_bytes(offset), ecx.machine.layouts.i32, ecx) - .unwrap(); - let id = ecx.read_scalar(&id_field).unwrap().to_i32().unwrap(); - assert!( - is_cond_clock_realtime(ecx, id), - "PTHREAD_COND_INITIALIZER is incompatible with our pthread_cond layout: clock is not CLOCK_REALTIME" - ); - } +#[derive(Debug)] +/// Additional data that we attach with each cond instance. +struct AdditionalCondData { + /// The address of the cond. + address: u64, - offset + /// The clock id of the cond. + clock_id: ClockId, } fn cond_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx>, + cond_ptr: &OpTy<'tcx>, ) -> InterpResult<'tcx, CondvarId> { - ecx.condvar_get_or_create_id( - cond_op, - ecx.libc_ty_layout("pthread_cond_t"), - cond_id_offset(ecx)?, - ) -} - -fn cond_reset_id<'tcx>( - ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx>, -) -> InterpResult<'tcx, ()> { - ecx.deref_pointer_and_write( - cond_op, - cond_id_offset(ecx)?, - Scalar::from_i32(0), - ecx.libc_ty_layout("pthread_cond_t"), - ecx.machine.layouts.u32, - ) -} - -fn cond_get_clock_id<'tcx>( - ecx: &MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx>, -) -> InterpResult<'tcx, i32> { - ecx.deref_pointer_and_read( - cond_op, - cond_clock_offset(ecx), - ecx.libc_ty_layout("pthread_cond_t"), - ecx.machine.layouts.i32, - )? - .to_i32() -} + let cond = ecx.deref_pointer(cond_ptr)?; + let address = cond.ptr().addr().bytes(); + let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |_ecx| { + // This used the static initializer. The clock there is always CLOCK_REALTIME. + Ok(Some(Box::new(AdditionalCondData { address, clock_id: ClockId::Realtime }))) + })?; + + // Check that the mutex has not been moved since last use. + let data = ecx + .condvar_get_data::(id) + .expect("data should always exist for pthreads"); + if data.address != address { + throw_ub_format!("pthread_cond_t can't be moved after first use") + } -fn cond_set_clock_id<'tcx>( - ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx>, - clock_id: i32, -) -> InterpResult<'tcx, ()> { - ecx.deref_pointer_and_write( - cond_op, - cond_clock_offset(ecx), - Scalar::from_i32(clock_id), - ecx.libc_ty_layout("pthread_cond_t"), - ecx.machine.layouts.i32, - ) + Ok(id) } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -366,8 +388,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); - let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"); - mutexattr_set_kind(this, attr_op, default_kind)?; + mutexattr_set_kind(this, attr_op, PTHREAD_MUTEX_KIND_UNCHANGED)?; Ok(()) } @@ -380,30 +401,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let kind = this.read_scalar(kind_op)?.to_i32()?; - if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL") { - // In `glibc` implementation, the numeric values of - // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal. - // However, a mutex created by explicitly passing - // `PTHREAD_MUTEX_NORMAL` type has in some cases different behaviour - // from the default mutex for which the type was not explicitly - // specified. For a more detailed discussion, please see - // https://github.com/rust-lang/miri/issues/1419. - // - // To distinguish these two cases in already constructed mutexes, we - // use the same trick as glibc: for the case when - // `pthread_mutexattr_settype` is called explicitly, we set the - // `PTHREAD_MUTEX_NORMAL_FLAG` flag. - let normal_kind = kind | PTHREAD_MUTEX_NORMAL_FLAG; - // Check that after setting the flag, the kind is distinguishable - // from all other kinds. - assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")); - assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")); - assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")); - mutexattr_set_kind(this, attr_op, normal_kind)?; - } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT") + if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL") + || kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT") || kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") || kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") { + // Make sure we do not mix this up with the "unchanged" kind. + assert_ne!(kind, PTHREAD_MUTEX_KIND_UNCHANGED); mutexattr_set_kind(this, attr_op, kind)?; } else { let einval = this.eval_libc_i32("EINVAL"); @@ -447,15 +451,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let attr = this.read_pointer(attr_op)?; let kind = if this.ptr_is_null(attr)? { - this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT") + MutexKind::Default } else { - mutexattr_get_kind(this, attr_op)? + mutex_translate_kind(this, mutexattr_get_kind(this, attr_op)?)? }; - // Write 0 to use the same code path as the static initializers. - mutex_reset_id(this, mutex_op)?; - - mutex_set_kind(this, mutex_op, kind)?; + mutex_create(this, mutex_op, kind)?; Ok(()) } @@ -467,8 +468,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?; let id = mutex_get_id(this, mutex_op)?; + let kind = this + .mutex_get_data::(id) + .expect("data should always exist for pthread mutexes") + .kind; let ret = if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); @@ -477,19 +481,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(()); } else { // Trying to acquire the same mutex again. - if is_mutex_kind_default(this, kind)? { - throw_ub_format!("trying to acquire already locked default mutex"); - } else if is_mutex_kind_normal(this, kind)? { - throw_machine_stop!(TerminationInfo::Deadlock); - } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") { - this.eval_libc_i32("EDEADLK") - } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") { - this.mutex_lock(id); - 0 - } else { - throw_unsup_format!( - "called pthread_mutex_lock on an unsupported type of mutex" - ); + match kind { + MutexKind::Default => + throw_ub_format!("trying to acquire already locked default mutex"), + MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock), + MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"), + MutexKind::Recursive => { + this.mutex_lock(id); + 0 + } } } } else { @@ -504,26 +504,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?; let id = mutex_get_id(this, mutex_op)?; + let kind = this + .mutex_get_data::(id) + .expect("data should always exist for pthread mutexes") + .kind; Ok(Scalar::from_i32(if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); if owner_thread != this.active_thread() { this.eval_libc_i32("EBUSY") } else { - if is_mutex_kind_default(this, kind)? - || is_mutex_kind_normal(this, kind)? - || kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") - { - this.eval_libc_i32("EBUSY") - } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") { - this.mutex_lock(id); - 0 - } else { - throw_unsup_format!( - "called pthread_mutex_trylock on an unsupported type of mutex" - ); + match kind { + MutexKind::Default | MutexKind::Normal | MutexKind::ErrorCheck => + this.eval_libc_i32("EBUSY"), + MutexKind::Recursive => { + this.mutex_lock(id); + 0 + } } } } else { @@ -536,8 +534,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?; let id = mutex_get_id(this, mutex_op)?; + let kind = this + .mutex_get_data::(id) + .expect("data should always exist for pthread mutexes") + .kind; if let Some(_old_locked_count) = this.mutex_unlock(id)? { // The mutex was locked by the current thread. @@ -546,20 +547,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The mutex was locked by another thread or not locked at all. See // the “Unlock When Not Owner” column in // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html. - if is_mutex_kind_default(this, kind)? { - throw_ub_format!( - "unlocked a default mutex that was not locked by the current thread" - ); - } else if is_mutex_kind_normal(this, kind)? { - throw_ub_format!( - "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" - ); - } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") - || kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") - { - Ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))) - } else { - throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex"); + match kind { + MutexKind::Default => + throw_ub_format!( + "unlocked a default mutex that was not locked by the current thread" + ), + MutexKind::Normal => + throw_ub_format!( + "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" + ), + MutexKind::ErrorCheck | MutexKind::Recursive => + Ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))), } } } @@ -567,16 +565,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); + // Reading the field also has the side-effect that we detect double-`destroy` + // since we make the field unint below. let id = mutex_get_id(this, mutex_op)?; if this.mutex_is_locked(id) { throw_ub_format!("destroyed a locked mutex"); } - // Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit. - mutex_get_kind(this, mutex_op)?; - mutex_get_id(this, mutex_op)?; - // This might lead to false positives, see comment in pthread_mutexattr_destroy this.write_uninit( &this.deref_pointer_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?, @@ -678,15 +674,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); + // Reading the field also has the side-effect that we detect double-`destroy` + // since we make the field unint below. let id = rwlock_get_id(this, rwlock_op)?; if this.rwlock_is_locked(id) { throw_ub_format!("destroyed a locked rwlock"); } - // Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit. - rwlock_get_id(this, rwlock_op)?; - // This might lead to false positives, see comment in pthread_mutexattr_destroy this.write_uninit( &this.deref_pointer_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?, @@ -776,11 +771,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { condattr_get_clock_id(this, attr_op)? }; - - // Write 0 to use the same code path as the static initializers. - cond_reset_id(this, cond_op)?; - - cond_set_clock_id(this, cond_op, clock_id)?; + let clock_id = cond_translate_clock_id(this, clock_id)?; + + let cond = this.deref_pointer(cond_op)?; + let address = cond.ptr().addr().bytes(); + this.condvar_create( + &cond, + cond_id_offset(this)?, + Some(Box::new(AdditionalCondData { address, clock_id })), + )?; Ok(()) } @@ -835,7 +834,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mutex_id = mutex_get_id(this, mutex_op)?; // Extract the timeout. - let clock_id = cond_get_clock_id(this, cond_op)?; + let clock_id = this + .condvar_get_data::(id) + .expect("additional data should always be present for pthreads") + .clock_id; let duration = match this .read_timespec(&this.deref_pointer_as(abstime_op, this.libc_ty_layout("timespec"))?)? { @@ -846,13 +848,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(()); } }; - let timeout_clock = if is_cond_clock_realtime(this, clock_id) { - this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?; - TimeoutClock::RealTime - } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC") { - TimeoutClock::Monotonic - } else { - throw_unsup_format!("unsupported clock id: {}", clock_id); + let timeout_clock = match clock_id { + ClockId::Realtime => { + this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?; + TimeoutClock::RealTime + } + ClockId::Monotonic => TimeoutClock::Monotonic, }; this.condvar_wait( @@ -870,15 +871,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); + // Reading the field also has the side-effect that we detect double-`destroy` + // since we make the field unint below. let id = cond_get_id(this, cond_op)?; if this.condvar_is_awaited(id) { throw_ub_format!("destroying an awaited conditional variable"); } - // Destroying an uninit pthread_cond is UB, so check to make sure it's not uninit. - cond_get_id(this, cond_op)?; - cond_get_clock_id(this, cond_op)?; - // This might lead to false positives, see comment in pthread_mutexattr_destroy this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?; // FIXME: delete interpreter state associated with this condvar. diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index 127aef29244c5..db6872319ea48 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -7,6 +7,8 @@ use std::collections::VecDeque; use std::io; use std::io::{Error, ErrorKind, Read}; +use rustc_target::abi::Size; + use crate::shims::unix::fd::{FileDescriptionRef, WeakFileDescriptionRef}; use crate::shims::unix::linux::epoll::{EpollReadyEvents, EvalContextExt as _}; use crate::shims::unix::*; @@ -126,14 +128,17 @@ impl FileDescription for AnonSocket { &self, _self_ref: &FileDescriptionRef, _communicate_allowed: bool, - bytes: &mut [u8], + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { - let request_byte_size = bytes.len(); + ) -> InterpResult<'tcx> { + let mut bytes = vec![0; len]; // Always succeed on read size 0. - if request_byte_size == 0 { - return Ok(Ok(0)); + if len == 0 { + let result = Ok(0); + return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest); } let Some(readbuf) = &self.readbuf else { @@ -146,7 +151,8 @@ impl FileDescription for AnonSocket { if self.peer_fd().upgrade().is_none() { // Socketpair with no peer and empty buffer. // 0 bytes successfully read indicates end-of-file. - return Ok(Ok(0)); + let result = Ok(0); + return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest); } else { if self.is_nonblock { // Non-blocking socketpair with writer and empty buffer. @@ -154,7 +160,8 @@ impl FileDescription for AnonSocket { // EAGAIN or EWOULDBLOCK can be returned for socket, // POSIX.1-2001 allows either error to be returned for this case. // Since there is no ErrorKind for EAGAIN, WouldBlock is used. - return Ok(Err(Error::from(ErrorKind::WouldBlock))); + let result = Err(Error::from(ErrorKind::WouldBlock)); + return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest); } else { // Blocking socketpair with writer and empty buffer. // FIXME: blocking is currently not supported @@ -170,7 +177,7 @@ impl FileDescription for AnonSocket { // Do full read / partial read based on the space available. // Conveniently, `read` exists on `VecDeque` and has exactly the desired behavior. - let actual_read_size = readbuf.buf.read(bytes).unwrap(); + let actual_read_size = readbuf.buf.read(&mut bytes).unwrap(); // Need to drop before others can access the readbuf again. drop(readbuf); @@ -186,28 +193,32 @@ impl FileDescription for AnonSocket { ecx.check_and_update_readiness(&peer_fd)?; } - return Ok(Ok(actual_read_size)); + let result = Ok(actual_read_size); + ecx.return_read_bytes_and_count(ptr, &bytes, result, dest) } fn write<'tcx>( &self, _self_ref: &FileDescriptionRef, _communicate_allowed: bool, - bytes: &[u8], + ptr: Pointer, + len: usize, + dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result> { - let write_size = bytes.len(); + ) -> InterpResult<'tcx> { // Always succeed on write size 0. // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.") - if write_size == 0 { - return Ok(Ok(0)); + if len == 0 { + let result = Ok(0); + return ecx.return_written_byte_count_or_error(result, dest); } // We are writing to our peer's readbuf. let Some(peer_fd) = self.peer_fd().upgrade() else { // If the upgrade from Weak to Rc fails, it indicates that all read ends have been // closed. - return Ok(Err(Error::from(ErrorKind::BrokenPipe))); + let result = Err(Error::from(ErrorKind::BrokenPipe)); + return ecx.return_written_byte_count_or_error(result, dest); }; let Some(writebuf) = &peer_fd.downcast::().unwrap().readbuf else { @@ -221,7 +232,8 @@ impl FileDescription for AnonSocket { if available_space == 0 { if self.is_nonblock { // Non-blocking socketpair with a full buffer. - return Ok(Err(Error::from(ErrorKind::WouldBlock))); + let result = Err(Error::from(ErrorKind::WouldBlock)); + return ecx.return_written_byte_count_or_error(result, dest); } else { // Blocking socketpair with a full buffer. throw_unsup_format!("socketpair write: blocking isn't supported yet"); @@ -232,7 +244,8 @@ impl FileDescription for AnonSocket { writebuf.clock.join(clock); } // Do full write / partial write based on the space available. - let actual_write_size = write_size.min(available_space); + let actual_write_size = len.min(available_space); + let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; writebuf.buf.extend(&bytes[..actual_write_size]); // Need to stop accessing peer_fd so that it can be notified. @@ -242,7 +255,8 @@ impl FileDescription for AnonSocket { // The kernel does this even if the fd was already readable before, so we follow suit. ecx.check_and_update_readiness(&peer_fd)?; - return Ok(Ok(actual_write_size)); + let result = Ok(actual_write_size); + ecx.return_written_byte_count_or_error(result, dest) } } diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 495df18a6eaa2..178b0a1a4612e 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -5,7 +5,7 @@ use std::io::ErrorKind; use rustc_data_structures::fx::FxHashMap; use crate::*; -use helpers::windows_check_buffer_size; +use self::helpers::windows_check_buffer_size; #[derive(Default)] pub struct WindowsEnvVars { diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index f840ba161650e..f385ed4ac115a 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -11,7 +11,7 @@ use rustc_target::spec::abi::Abi; use crate::shims::os_str::bytes_to_os_str; use crate::shims::windows::*; use crate::*; -use shims::windows::handle::{Handle, PseudoHandle}; +use self::shims::windows::handle::{Handle, PseudoHandle}; pub fn is_dyn_sym(name: &str) -> bool { // std does dynamic detection for these symbols diff --git a/src/tools/miri/src/shims/windows/mod.rs b/src/tools/miri/src/shims/windows/mod.rs index 65f682b9dad9a..537c724e52665 100644 --- a/src/tools/miri/src/shims/windows/mod.rs +++ b/src/tools/miri/src/shims/windows/mod.rs @@ -5,9 +5,9 @@ mod handle; mod sync; mod thread; -pub use env::WindowsEnvVars; +pub use self::env::WindowsEnvVars; // All the Windows-specific extension traits -pub use env::EvalContextExt as _; -pub use handle::EvalContextExt as _; -pub use sync::EvalContextExt as _; -pub use thread::EvalContextExt as _; +pub use self::env::EvalContextExt as _; +pub use self::handle::EvalContextExt as _; +pub use self::sync::EvalContextExt as _; +pub use self::thread::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index e1fbb77037cfb..51b0129356baa 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -10,9 +10,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Windows sync primitives are pointer sized. // We only use the first 4 bytes for the id. - fn init_once_get_id(&mut self, init_once_op: &OpTy<'tcx>) -> InterpResult<'tcx, InitOnceId> { + fn init_once_get_id(&mut self, init_once_ptr: &OpTy<'tcx>) -> InterpResult<'tcx, InitOnceId> { let this = self.eval_context_mut(); - this.init_once_get_or_create_id(init_once_op, this.windows_ty_layout("INIT_ONCE"), 0) + let init_once = this.deref_pointer(init_once_ptr)?; + this.init_once_get_or_create_id(&init_once, 0) } /// Returns `true` if we were succssful, `false` if we would block. diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index f3ddf6072af1f..9f93fc5f0810f 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; use crate::*; -use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; +use self::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs index e4e1531157a42..dbbae0731e0b7 100644 --- a/src/tools/miri/src/shims/x86/aesni.rs +++ b/src/tools/miri/src/shims/x86/aesni.rs @@ -1,5 +1,5 @@ -use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index 2f6569e1823de..bdc4fc9446915 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -1,14 +1,14 @@ use rustc_apfloat::{ieee::Double, ieee::Single}; use rustc_middle::mir; -use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use super::{ - bin_op_simd_float_all, conditional_dot_product, convert_float_to_int, horizontal_bin_op, - mask_load, mask_store, round_all, test_bits_masked, test_high_bits_masked, unary_op_ps, - FloatBinOp, FloatUnaryOp, + FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, conditional_dot_product, convert_float_to_int, + horizontal_bin_op, mask_load, mask_store, round_all, test_bits_masked, test_high_bits_masked, + unary_op_ps, }; use crate::*; @@ -159,9 +159,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [data, control] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (data, data_len) = this.operand_to_simd(data)?; - let (control, control_len) = this.operand_to_simd(control)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (data, data_len) = this.project_to_simd(data)?; + let (control, control_len) = this.project_to_simd(control)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, data_len); assert_eq!(dest_len, control_len); @@ -193,9 +193,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [data, control] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (data, data_len) = this.operand_to_simd(data)?; - let (control, control_len) = this.operand_to_simd(control)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (data, data_len) = this.project_to_simd(data)?; + let (control, control_len) = this.project_to_simd(control)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, data_len); assert_eq!(dest_len, control_len); diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 7f6c9336a9749..1dda1a10a0503 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -1,12 +1,12 @@ use rustc_middle::mir; -use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use super::{ - horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb, packusdw, - packuswb, pmulhrsw, psign, shift_simd_by_scalar, shift_simd_by_simd, ShiftOp, + ShiftOp, horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb, + packusdw, packuswb, pmulhrsw, psign, shift_simd_by_scalar, shift_simd_by_simd, }; use crate::*; @@ -62,10 +62,10 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert_eq!(dest.layout, src.layout); - let (src, _) = this.operand_to_simd(src)?; - let (offsets, offsets_len) = this.operand_to_simd(offsets)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (src, _) = this.project_to_simd(src)?; + let (offsets, offsets_len) = this.project_to_simd(offsets)?; + let (mask, mask_len) = this.project_to_simd(mask)?; + let (dest, dest_len) = this.project_to_simd(dest)?; // There are cases like dest: i32x4, offsets: i64x2 // If dest has more elements than offset, extra dest elements are filled with zero. @@ -118,9 +118,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(left_len, right_len); assert_eq!(dest_len.strict_mul(2), left_len); @@ -155,9 +155,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(left_len, right_len); assert_eq!(dest_len.strict_mul(2), left_len); @@ -271,9 +271,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -330,9 +330,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(left_len, right_len); assert_eq!(left_len, dest_len.strict_mul(8)); @@ -363,9 +363,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 305e59fa0cd60..9139156fd0e4d 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1,15 +1,15 @@ use rand::Rng as _; -use rustc_apfloat::{ieee::Single, Float}; -use rustc_middle::ty::layout::LayoutOf as _; +use rustc_apfloat::{Float, ieee::Single}; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::{mir, ty}; use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::bool_to_simd_element; +use self::helpers::bool_to_simd_element; mod aesni; mod avx; @@ -314,9 +314,9 @@ fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>( right: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -344,9 +344,9 @@ fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>( right: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -430,8 +430,8 @@ fn unary_op_ss<'tcx>( op: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, op_len); @@ -453,8 +453,8 @@ fn unary_op_ps<'tcx>( op: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, op_len); @@ -491,8 +491,8 @@ fn shift_simd_by_scalar<'tcx>( which: ShiftOp, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (left, left_len) = this.operand_to_simd(left)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); // `right` may have a different length, and we only care about its @@ -547,9 +547,9 @@ fn shift_simd_by_simd<'tcx>( which: ShiftOp, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -613,9 +613,9 @@ fn round_first<'tcx, F: rustc_apfloat::Float>( rounding: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -643,8 +643,8 @@ fn round_all<'tcx, F: rustc_apfloat::Float>( rounding: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, op_len); @@ -695,8 +695,8 @@ fn convert_float_to_int<'tcx>( rnd: rustc_apfloat::Round, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; // Output must be *signed* integers. assert!(matches!(dest.layout.field(this, 0).ty.kind(), ty::Int(_))); @@ -729,8 +729,8 @@ fn int_abs<'tcx>( op: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(op_len, dest_len); @@ -906,8 +906,8 @@ fn test_bits_masked<'tcx>( ) -> InterpResult<'tcx, (bool, bool)> { assert_eq!(op.layout, mask.layout); - let (op, op_len) = this.operand_to_simd(op)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; + let (op, op_len) = this.project_to_simd(op)?; + let (mask, mask_len) = this.project_to_simd(mask)?; assert_eq!(op_len, mask_len); @@ -937,8 +937,8 @@ fn test_high_bits_masked<'tcx>( ) -> InterpResult<'tcx, (bool, bool)> { assert_eq!(op.layout, mask.layout); - let (op, op_len) = this.operand_to_simd(op)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; + let (op, op_len) = this.project_to_simd(op)?; + let (mask, mask_len) = this.project_to_simd(mask)?; assert_eq!(op_len, mask_len); @@ -967,8 +967,8 @@ fn mask_load<'tcx>( mask: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (mask, mask_len) = this.project_to_simd(mask)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, mask_len); @@ -1000,8 +1000,8 @@ fn mask_store<'tcx>( mask: &OpTy<'tcx>, value: &OpTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (value, value_len) = this.operand_to_simd(value)?; + let (mask, mask_len) = this.project_to_simd(mask)?; + let (value, value_len) = this.project_to_simd(value)?; assert_eq!(value_len, mask_len); @@ -1014,9 +1014,12 @@ fn mask_store<'tcx>( let value = this.project_index(&value, i)?; if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + // *Non-inbounds* pointer arithmetic to compute the destination. + // (That's why we can't use a place projection.) let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx); - // Unaligned copy, which is what we want. - this.mem_copy(value.ptr(), ptr, value.layout.size, /*nonoverlapping*/ true)?; + // Deref the pointer *unaligned*, and do the copy. + let dest = this.ptr_to_mplace_unaligned(ptr, value.layout); + this.copy_op(&value, &dest)?; } } @@ -1095,9 +1098,9 @@ fn pmulhrsw<'tcx>( right: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -1313,9 +1316,9 @@ fn psign<'tcx>( right: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs index e9cc28be34cff..d9cd34377e683 100644 --- a/src/tools/miri/src/shims/x86/sha.rs +++ b/src/tools/miri/src/shims/x86/sha.rs @@ -23,7 +23,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sha").unwrap(); - fn read<'c>(this: &mut MiriInterpCx<'c>, reg: &MPlaceTy<'c>) -> InterpResult<'c, [u32; 4]> { + fn read<'c>(this: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> { let mut res = [0; 4]; // We reverse the order because x86 is little endian but the copied implementation uses // big endian. @@ -53,10 +53,10 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "256rnds2" => { let [a, b, k] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (a_reg, a_len) = this.operand_to_simd(a)?; - let (b_reg, b_len) = this.operand_to_simd(b)?; - let (k_reg, k_len) = this.operand_to_simd(k)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (a_reg, a_len) = this.project_to_simd(a)?; + let (b_reg, b_len) = this.project_to_simd(b)?; + let (k_reg, k_len) = this.project_to_simd(k)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(a_len, 4); assert_eq!(b_len, 4); @@ -74,9 +74,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "256msg1" => { let [a, b] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (a_reg, a_len) = this.operand_to_simd(a)?; - let (b_reg, b_len) = this.operand_to_simd(b)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (a_reg, a_len) = this.project_to_simd(a)?; + let (b_reg, b_len) = this.project_to_simd(b)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(a_len, 4); assert_eq!(b_len, 4); @@ -92,9 +92,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "256msg2" => { let [a, b] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (a_reg, a_len) = this.operand_to_simd(a)?; - let (b_reg, b_len) = this.operand_to_simd(b)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (a_reg, a_len) = this.project_to_simd(a)?; + let (b_reg, b_len) = this.project_to_simd(b)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(a_len, 4); assert_eq!(b_len, 4); diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 07a4eaa85f3e3..254d25bb5293a 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -3,8 +3,8 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use super::{ - bin_op_simd_float_all, bin_op_simd_float_first, unary_op_ps, unary_op_ss, FloatBinOp, - FloatUnaryOp, + FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, bin_op_simd_float_first, unary_op_ps, + unary_op_ss, }; use crate::*; @@ -130,8 +130,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; assert_eq!(left_len, right_len); @@ -157,7 +157,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts the first component of `op` from f32 to i32/i64. "cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => { let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (op, _) = this.operand_to_simd(op)?; + let (op, _) = this.project_to_simd(op)?; let op = this.read_immediate(&this.project_index(&op, 0)?)?; @@ -187,8 +187,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 163d74a6de4e9..7c23e37266430 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -3,8 +3,8 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use super::{ - bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, packssdw, packsswb, - packuswb, shift_simd_by_scalar, FloatBinOp, ShiftOp, + FloatBinOp, ShiftOp, bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, + packssdw, packsswb, packuswb, shift_simd_by_scalar, }; use crate::*; @@ -42,9 +42,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(left_len, right_len); assert_eq!(dest_len.strict_mul(2), left_len); @@ -81,9 +81,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; // left and right are u8x16, dest is u64x2 assert_eq!(left_len, right_len); @@ -270,8 +270,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; assert_eq!(left_len, right_len); @@ -297,7 +297,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts the first component of `op` from f64 to i32/i64. "cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => { let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (op, _) = this.operand_to_simd(op)?; + let (op, _) = this.project_to_simd(op)?; let op = this.read_immediate(&this.project_index(&op, 0)?)?; @@ -325,9 +325,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, _) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, _) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index 9e048fb9eb841..8fcdc491c0ca3 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -29,9 +29,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right, imm] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -118,8 +118,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "phminposuw" => { let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; // Find minimum let mut min_value = u16::MAX; diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 4e50d5e5dcfbf..0b6e0d9e0d7e7 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -1,6 +1,6 @@ use rustc_middle::mir; -use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index ecacaeb9af524..096b0fb9e4b17 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -34,9 +34,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); @@ -84,9 +84,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(left_len, right_len); assert_eq!(dest_len.strict_mul(2), left_len); diff --git a/src/tools/miri/test-cargo-miri/src/main.rs b/src/tools/miri/test-cargo-miri/src/main.rs index 048577ef15a61..d171ec1c0d1c4 100644 --- a/src/tools/miri/test-cargo-miri/src/main.rs +++ b/src/tools/miri/test-cargo-miri/src/main.rs @@ -23,7 +23,7 @@ fn main() { // (We rely on the test runner to always disable isolation when passing no arguments.) if std::env::args().len() <= 1 { fn host_to_target_path(path: String) -> PathBuf { - use std::ffi::{c_char, CStr, CString}; + use std::ffi::{CStr, CString, c_char}; let path = CString::new(path).unwrap(); let mut out = Vec::with_capacity(1024); diff --git a/src/tools/miri/test-cargo-miri/subcrate/main.rs b/src/tools/miri/test-cargo-miri/subcrate/main.rs index 52161098788b5..96f849e7633ac 100644 --- a/src/tools/miri/test-cargo-miri/subcrate/main.rs +++ b/src/tools/miri/test-cargo-miri/subcrate/main.rs @@ -5,7 +5,7 @@ fn main() { println!("subcrate running"); fn host_to_target_path(path: String) -> PathBuf { - use std::ffi::{c_char, CStr, CString}; + use std::ffi::{CStr, CString, c_char}; let path = CString::new(path).unwrap(); let mut out = Vec::with_capacity(1024); diff --git a/src/tools/miri/test-cargo-miri/subcrate/test.rs b/src/tools/miri/test-cargo-miri/subcrate/test.rs index 1681c721dc2e2..b60cf20339b77 100644 --- a/src/tools/miri/test-cargo-miri/subcrate/test.rs +++ b/src/tools/miri/test-cargo-miri/subcrate/test.rs @@ -8,7 +8,7 @@ fn main() { println!("subcrate testing"); fn host_to_target_path(path: String) -> PathBuf { - use std::ffi::{c_char, CStr, CString}; + use std::ffi::{CStr, CString, c_char}; let path = CString::new(path).unwrap(); let mut out = Vec::with_capacity(1024); diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index 39d412817289d..9a4431eb7048d 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/Cargo.lock @@ -172,6 +172,7 @@ dependencies = [ name = "miri-test-deps" version = "0.1.0" dependencies = [ + "cfg-if", "getrandom 0.1.16", "getrandom 0.2.15", "libc", diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml index c24422df26cf2..e7eff46afca52 100644 --- a/src/tools/miri/test_dependencies/Cargo.toml +++ b/src/tools/miri/test_dependencies/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" # all dependencies (and their transitive ones) listed here can be used in `tests/`. libc = "0.2" num_cpus = "1.10.1" +cfg-if = "1" getrandom_01 = { package = "getrandom", version = "0.1" } getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] } diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs index d6604f3713946..546909a13ea5f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs @@ -1,4 +1,4 @@ -//@ only-target-darwin +//@only-target: darwin use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr index 7e890681c436a..3fd02d38aae4f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr @@ -1,11 +1,11 @@ error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread - --> $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC + --> tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs:LL:CC | LL | libc::os_unfair_lock_assert_not_owner(lock.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread | = note: BACKTRACE: - = note: inside `main` at $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs index ddd8b572eaf0b..4cbd34329f8ff 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs @@ -1,4 +1,4 @@ -//@ only-target-darwin +//@only-target: darwin use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr index 3724f7996fb8b..0b5dfe4ba61b8 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr @@ -1,11 +1,11 @@ error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread - --> $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC + --> tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs:LL:CC | LL | libc::os_unfair_lock_assert_owner(lock.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread | = note: BACKTRACE: - = note: inside `main` at $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs index eb98adeba0730..a13e85733958e 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs @@ -1,4 +1,4 @@ -//@ only-target-darwin +//@only-target: darwin use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr index 644462a1b05f9..3b02936b1f214 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr @@ -1,11 +1,11 @@ error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread - --> $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC + --> tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs:LL:CC | LL | libc::os_unfair_lock_lock(lock.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to lock an os_unfair_lock that is already locked by the current thread | = note: BACKTRACE: - = note: inside `main` at $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs index aed467552ab9f..2bef8bcca4d1a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs @@ -1,4 +1,4 @@ -//@ only-target-darwin +//@only-target: darwin use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr index 6a8d12fa80760..192e1cdc47527 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr @@ -1,11 +1,11 @@ error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread - --> $DIR/apple_os_unfair_lock_unowned.rs:LL:CC + --> tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs:LL:CC | LL | libc::os_unfair_lock_unlock(lock.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to unlock an os_unfair_lock not owned by the current thread | = note: BACKTRACE: - = note: inside `main` at $DIR/apple_os_unfair_lock_unowned.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs index f22f17be0df56..047fe07df14b4 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr index 899c217efbff7..4cf1b4af12ada 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/libc_pthread_cond_double_destroy.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC | LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_cond_double_destroy.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr new file mode 100644 index 0000000000000..6e90c490a231c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: pthread_cond_t can't be moved after first use + --> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC + | +LL | libc::pthread_cond_destroy(cond2.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_cond_t can't be moved after first use + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `check` at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC +note: inside `main` + --> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC + | +LL | check() + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.rs new file mode 100644 index 0000000000000..8fd0caac75189 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.rs @@ -0,0 +1,37 @@ +//@revisions: static_initializer init +//@ignore-target: windows # No pthreads on Windows + +/// Test that moving a pthread_cond between uses fails. + +fn main() { + check() +} + +#[cfg(init)] +fn check() { + unsafe { + use core::mem::MaybeUninit; + let mut cond = MaybeUninit::::uninit(); + + libc::pthread_cond_init(cond.as_mut_ptr(), std::ptr::null()); + + // move pthread_cond_t + let mut cond2 = cond; + + libc::pthread_cond_destroy(cond2.as_mut_ptr()); //~[init] ERROR: pthread_cond_t can't be moved after first use + } +} + +#[cfg(static_initializer)] +fn check() { + unsafe { + let mut cond = libc::PTHREAD_COND_INITIALIZER; + + libc::pthread_cond_signal(&mut cond as *mut _); + + // move pthread_cond_t + let mut cond2 = cond; + + libc::pthread_cond_destroy(&mut cond2 as *mut _); //~[static_initializer] ERROR: pthread_cond_t can't be moved after first use + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr new file mode 100644 index 0000000000000..ba726ac7f386e --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: pthread_cond_t can't be moved after first use + --> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC + | +LL | libc::pthread_cond_destroy(&mut cond2 as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_cond_t can't be moved after first use + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `check` at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC +note: inside `main` + --> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC + | +LL | check() + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs index d0ccab4de5b58..90e33d58673a2 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs @@ -1,5 +1,5 @@ -//@ignore-target-windows: No pthreads on Windows -//@ignore-target-apple: Our macOS condattr don't have any fields so we do not notice this. +//@ignore-target: windows # No pthreads on Windows +//@ignore-target: apple # Our macOS condattr don't have any fields so we do not notice this. /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr index ef75b03162d79..f2ddf9ae92e8f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC | LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs index 9cd0a35d36e94..d4a9f076bfdae 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows //@error-in-other-file: the main thread terminated without waiting for all remaining threads // Check that we terminate the program when the main thread terminates. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs index 39b1c3007cb00..d4accdba5d73e 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows //~^ERROR: calling a function with more arguments than it expected //! The thread function must have exactly one argument. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs index fc2ab71dff735..0af3600854ddb 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows //~^ERROR: calling a function with fewer arguments than it requires //! The thread function must have exactly one argument. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs index e89d7a9f02b92..472d07f617ea6 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows // Joining a detached thread is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.stderr index 7238dfb40b723..327737a0b3f07 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to join a detached thread - --> $DIR/libc_pthread_join_detached.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_join_detached.rs:LL:CC | LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread @@ -7,7 +7,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_join_detached.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_join_detached.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs index cbad743ca5633..988c33868a639 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows // Joining an already joined thread is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.stderr index e501a086cca4d..1dd1cb9f73185 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to join an already joined thread - --> $DIR/libc_pthread_join_joined.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_join_joined.rs:LL:CC | LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join an already joined thread @@ -7,7 +7,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_join_joined.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_join_joined.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs index 002498e6c8263..b47c0121a3eee 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows // Joining the main thread is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr index e27e88dda2d71..b04a18561fdfc 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to join a detached thread - --> $DIR/libc_pthread_join_main.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_join_main.rs:LL:CC | LL | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread @@ -7,7 +7,7 @@ LL | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_join_main.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_join_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs index f5b687a623f73..6a49625d75d60 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows // Joining the same thread from multiple threads is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr index 6a7b237e5b306..1ada476811ea0 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to join an already joined thread - --> $DIR/libc_pthread_join_multiple.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_join_multiple.rs:LL:CC | LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join an already joined thread @@ -7,7 +7,7 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_join_multiple.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_join_multiple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs index 4bc1c82a254c5..53760b05a3127 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr index 258c5f26c7a39..6aa85086a83bd 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to join itself - --> $DIR/libc_pthread_join_self.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_join_self.rs:LL:CC | LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join itself @@ -7,7 +7,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_join_self.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_join_self.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs index 0a494c53b4b5c..a79abe65328e0 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows // // Check that if we pass NULL attribute, then we get the default mutex type. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr index 3675ce49f30e4..e9961ed413d0c 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to acquire already locked default mutex - --> $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC | LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex @@ -7,7 +7,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs index 0328115c63759..e3d5da26aeae4 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr index 079c1729b600f..534cacaed593c 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC | LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); | ^ the evaluated program deadlocked | = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_mutex_deadlock.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC @@ -18,7 +18,7 @@ LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` - --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC | LL | / thread::spawn(move || { LL | | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs index 1038b8988f99f..d9293f938b6aa 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs @@ -1,10 +1,11 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows // // Check that if we do not set the mutex type, it is the default. fn main() { unsafe { - let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_init(&mut mutexattr as *mut _), 0); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr index 4d41141b545f8..a57d10753d90d 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to acquire already locked default mutex - --> $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC | LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex @@ -7,7 +7,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs index e474712cfd994..35998c95f6f5c 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { unsafe { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.stderr index ed5e27b607a5d..38f38b4283a27 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: destroyed a locked mutex - --> $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs:LL:CC | LL | libc::pthread_mutex_destroy(&mut mutex as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked mutex @@ -7,7 +7,7 @@ LL | libc::pthread_mutex_destroy(&mut mutex as *mut _); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs index 46f0c5f8d72ee..1792c227e132d 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr index 05b35ee3b30a1..72ad2db75aa20 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC | LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr new file mode 100644 index 0000000000000..15f397d4ac298 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: pthread_mutex_t can't be moved after first use + --> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC + | +LL | libc::pthread_mutex_lock(&mut m2 as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_mutex_t can't be moved after first use + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `check` at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC +note: inside `main` + --> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC + | +LL | check(); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.rs new file mode 100644 index 0000000000000..c12a97a9ca18f --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.rs @@ -0,0 +1,28 @@ +//@ignore-target: windows # No pthreads on Windows +//@revisions: static_initializer init + +fn main() { + check(); +} + +#[cfg(init)] +fn check() { + unsafe { + let mut m: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut m as *mut _, std::ptr::null()), 0); + + let mut m2 = m; // move the mutex + libc::pthread_mutex_lock(&mut m2 as *mut _); //~[init] ERROR: pthread_mutex_t can't be moved after first use + } +} + +#[cfg(static_initializer)] +fn check() { + unsafe { + let mut m: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + libc::pthread_mutex_lock(&mut m as *mut _); + + let mut m2 = m; // move the mutex + libc::pthread_mutex_unlock(&mut m2 as *mut _); //~[static_initializer] ERROR: pthread_mutex_t can't be moved after first use + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr new file mode 100644 index 0000000000000..ebc253bf7a67c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: pthread_mutex_t can't be moved after first use + --> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC + | +LL | libc::pthread_mutex_unlock(&mut m2 as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_mutex_t can't be moved after first use + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `check` at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC +note: inside `main` + --> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC + | +LL | check(); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs index f311934e28bb3..b38582482b88b 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { unsafe { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr index 334c14ebf04f2..4337475963e4a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/libc_pthread_mutex_normal_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC | LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked | = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_mutex_normal_deadlock.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs index 2b5886dc16375..50b5504905000 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { unsafe { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.stderr index d717b4ec56b67..db08496889ed2 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread - --> $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC | LL | libc::pthread_mutex_unlock(&mut mutex as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread @@ -7,7 +7,7 @@ LL | libc::pthread_mutex_unlock(&mut mutex as *mut _); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs index 686a394f7cb9b..84c72fd9ba154 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr index b8ec2d6d01822..97c92e828e6ed 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: unlocked a default mutex that was not locked by the current thread - --> $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs:LL:CC | LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked a default mutex that was not locked by the current thread @@ -7,7 +7,7 @@ LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs index 51f00d62b75b5..3711c1f8dc10c 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr index a8425e6f81d0f..4c39ca003ece9 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC | LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs index fa4575bc1d4d1..f2c19f981034f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.stderr index bb90545c5034a..0a964da82a690 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: destroyed a locked rwlock - --> $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC | LL | libc::pthread_rwlock_destroy(rw.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked rwlock @@ -7,7 +7,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs index e734a62bca8db..200477467af57 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.stderr index 7210c6a742ae5..cfdadbefe4ef1 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: destroyed a locked rwlock - --> $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC | LL | libc::pthread_rwlock_destroy(rw.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked rwlock @@ -7,7 +7,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs index e96f7fc680382..6a31e972e68b8 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr index 5032e98f11619..41c189f3efd56 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC | LL | libc::pthread_rwlock_destroy(&mut lock); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | libc::pthread_rwlock_destroy(&mut lock); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index dffeee2b794ec..5de70cb38a193 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr index 957458a7ba004..5b5d35bf195bd 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC | LL | libc::pthread_rwlock_wrlock(rw.get()); | ^ the evaluated program deadlocked | = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs index 328372b22ef93..d59c94238189b 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr index a964a64284adb..d2fccfcc3f0b4 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread - --> $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC | LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread @@ -7,7 +7,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs index ced6b7a4f613c..ca0444a7b4341 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.stderr index 98b09472904b1..da2a650151dcc 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread - --> $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC | LL | libc::pthread_rwlock_unlock(rw.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread @@ -7,7 +7,7 @@ LL | libc::pthread_rwlock_unlock(rw.get()); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs index 4174751926d85..3a985122e22e0 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr index d03c6402d64ff..ae77d79fcd464 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC | LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); | ^ the evaluated program deadlocked | = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC @@ -18,7 +18,7 @@ LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` - --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC | LL | / thread::spawn(move || { LL | | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index 099b8dcd106ac..708192ddccc5f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr index d6cceaff1660a..24c1a993652a1 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC | LL | libc::pthread_rwlock_rdlock(rw.get()); | ^ the evaluated program deadlocked | = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs index 43b3ab09bb237..6d7bb80d8e6c6 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr index 73c5e77a1bce4..4f463464130dc 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC | LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); | ^ the evaluated program deadlocked | = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC @@ -18,7 +18,7 @@ LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` - --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC | LL | / thread::spawn(move || { LL | | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index 2704ff154413c..c7bacbacd8770 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr index 3ba99e3db4afb..e76ce84e757d1 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC | LL | libc::pthread_rwlock_wrlock(rw.get()); | ^ the evaluated program deadlocked | = note: BACKTRACE: - = note: inside `main` at $DIR/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs index 9a2cd09f083e7..21559e2e58f87 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr index c9c22dea6556c..906311144e8e4 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread - --> $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC | LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread @@ -7,7 +7,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libx_pthread_rwlock_moved.rs b/src/tools/miri/tests/fail-dep/concurrency/libx_pthread_rwlock_moved.rs new file mode 100644 index 0000000000000..540729962a97e --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libx_pthread_rwlock_moved.rs @@ -0,0 +1,14 @@ +//@ignore-target: windows # No pthreads on Windows + +fn main() { + unsafe { + let mut rw = libc::PTHREAD_RWLOCK_INITIALIZER; + + libc::pthread_rwlock_rdlock(&mut rw as *mut _); + + // Move rwlock + let mut rw2 = rw; + + libc::pthread_rwlock_unlock(&mut rw2 as *mut _); //~ ERROR: pthread_rwlock_t can't be moved after first use + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/libx_pthread_rwlock_moved.stderr b/src/tools/miri/tests/fail-dep/concurrency/libx_pthread_rwlock_moved.stderr new file mode 100644 index 0000000000000..ce08fa8159c27 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libx_pthread_rwlock_moved.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pthread_rwlock_t can't be moved after first use + --> tests/fail-dep/concurrency/libx_pthread_rwlock_moved.rs:LL:CC + | +LL | libc::pthread_rwlock_unlock(&mut rw2 as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_rwlock_t can't be moved after first use + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail-dep/concurrency/libx_pthread_rwlock_moved.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.rs index 0e9eb24459c3e..63e7eb113dd4f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.rs @@ -1,4 +1,4 @@ -//@only-target-windows: Uses win32 api functions +//@only-target: windows # Uses win32 api functions //@error-in-other-file: Undefined Behavior: trying to join a detached thread // Joining a detached thread is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr index 19bfe56395e00..947d665b95a19 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr @@ -11,7 +11,7 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle( = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` - --> $DIR/windows_join_detached.rs:LL:CC + --> tests/fail-dep/concurrency/windows_join_detached.rs:LL:CC | LL | thread.join().unwrap(); | ^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs index 532bda201364f..279201df867cf 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs @@ -1,4 +1,4 @@ -//@only-target-windows: Uses win32 api functions +//@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 //@error-in-other-file: deadlock @@ -8,7 +8,7 @@ use std::thread; use windows_sys::Win32::Foundation::{HANDLE, WAIT_OBJECT_0}; -use windows_sys::Win32::System::Threading::{WaitForSingleObject, INFINITE}; +use windows_sys::Win32::System::Threading::{INFINITE, WaitForSingleObject}; // XXX HACK: This is how miri represents the handle for thread 0. // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr index 12f35fdeb02a7..23a9f8f9c288f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr @@ -1,5 +1,5 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/windows_join_main.rs:LL:CC + --> tests/fail-dep/concurrency/windows_join_main.rs:LL:CC | LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked @@ -19,7 +19,7 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle( = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` - --> $DIR/windows_join_main.rs:LL:CC + --> tests/fail-dep/concurrency/windows_join_main.rs:LL:CC | LL | / thread::spawn(|| { LL | | unsafe { diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs index a64265ca0ca5e..eee2979f3cff3 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs @@ -1,4 +1,4 @@ -//@only-target-windows: Uses win32 api functions +//@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 //@error-in-other-file: deadlock @@ -8,7 +8,7 @@ use std::thread; use windows_sys::Win32::Foundation::WAIT_OBJECT_0; -use windows_sys::Win32::System::Threading::{GetCurrentThread, WaitForSingleObject, INFINITE}; +use windows_sys::Win32::System::Threading::{GetCurrentThread, INFINITE, WaitForSingleObject}; fn main() { thread::spawn(|| { diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr index 8d26c35de8ab2..4e640296dbe4a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> $DIR/windows_join_self.rs:LL:CC + --> tests/fail-dep/concurrency/windows_join_self.rs:LL:CC | LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0); | ^ the evaluated program deadlocked | = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/windows_join_self.rs:LL:CC + = note: inside closure at tests/fail-dep/concurrency/windows_join_self.rs:LL:CC error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC @@ -18,7 +18,7 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle( = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` - --> $DIR/windows_join_self.rs:LL:CC + --> tests/fail-dep/concurrency/windows_join_self.rs:LL:CC | LL | / thread::spawn(|| { LL | | unsafe { diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.rs b/src/tools/miri/tests/fail-dep/libc/affinity.rs index c41d1d18018c7..d7d5c59e1bc17 100644 --- a/src/tools/miri/tests/fail-dep/libc/affinity.rs +++ b/src/tools/miri/tests/fail-dep/libc/affinity.rs @@ -1,5 +1,5 @@ -//@ignore-target-windows: only very limited libc on Windows -//@ignore-target-apple: `sched_setaffinity` is not supported on macOS +//@ignore-target: windows # only very limited libc on Windows +//@ignore-target: apple # `sched_setaffinity` is not supported on macOS //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4 fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr index 38414623ccb94..5a226c6a44b8f 100644 --- a/src/tools/miri/tests/fail-dep/libc/affinity.stderr +++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation - --> $DIR/affinity.rs:LL:CC + --> tests/fail-dep/libc/affinity.rs:LL:CC | LL | let err = unsafe { sched_setaffinity(PID, size_of::() + 1, &cpuset) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation @@ -7,12 +7,12 @@ LL | let err = unsafe { sched_setaffinity(PID, size_of::() + 1, & = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/affinity.rs:LL:CC + --> tests/fail-dep/libc/affinity.rs:LL:CC | LL | let cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; | ^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/affinity.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/affinity.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs index 9a33cdccd270e..0caba9059ef52 100644 --- a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs +++ b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Windows does not support the standard C11 aligned_alloc. +//@ignore-target: windows # Windows does not support the standard C11 aligned_alloc. fn main() { // libc doesn't have this function (https://github.com/rust-lang/libc/issues/3689), diff --git a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr index 91c67823320a1..bde7f5b515e35 100644 --- a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr +++ b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr @@ -1,11 +1,11 @@ error: memory leaked: ALLOC (C heap, size: 0, align: 2), allocated here: - --> $DIR/aligned_alloc_size_zero_leak.rs:LL:CC + --> tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs:LL:CC | LL | aligned_alloc(2, 0); | ^^^^^^^^^^^^^^^^^^^ | = note: BACKTRACE: - = note: inside `main` at $DIR/aligned_alloc_size_zero_leak.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs index a1895feb957bc..c7d8bacd37950 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: No libc env support on Windows +//@ignore-target: windows # No libc env support on Windows use std::env; use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr index f85234f562711..904a1677b80eb 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/env-set_var-data-race.rs:LL:CC + --> tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC | LL | libc::getenv(b"TZ/0".as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/env-set_var-data-race.rs:LL:CC + --> tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC | LL | env::set_var("MY_RUST_VAR", "Ferris"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/env-set_var-data-race.rs:LL:CC + = note: inside closure at tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs index 42b7e2b7838cb..7911133f548ff 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc IO on Windows +//@ignore-target: windows # No libc IO on Windows //@compile-flags: -Zmiri-disable-isolation // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) diff --git a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr index e1b1b053bbc65..029eeab404432 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr @@ -1,12 +1,12 @@ error: unsupported operation: cannot close stdout - --> $DIR/close_stdout.rs:LL:CC + --> tests/fail-dep/libc/fs/close_stdout.rs:LL:CC | LL | libc::close(1); | ^^^^^^^^^^^^^^ cannot close stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/close_stdout.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/fs/close_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs index 3c62015a051ad..3ef194c5c7172 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc IO on Windows +//@ignore-target: windows # No libc IO on Windows fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr index 9abe145ea9ef7..bb7e8cef5dcd2 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr @@ -1,5 +1,5 @@ error: unsupported operation: `read` from stdin not available when isolation is enabled - --> $DIR/isolated_stdin.rs:LL:CC + --> tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC | LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled @@ -7,7 +7,7 @@ LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning = note: BACKTRACE: - = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs index 6d951a3a7b387..2c676f12b4f0e 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No mkstemp on Windows +//@ignore-target: windows # No mkstemp on Windows //@compile-flags: -Zmiri-disable-isolation fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr index 7a2757557ef1a..9227bddf5a8d3 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: writing to ALLOC which is read-only - --> $DIR/mkstemp_immutable_arg.rs:LL:CC + --> tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs:LL:CC | LL | let _fd = unsafe { libc::mkstemp(s) }; | ^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only @@ -7,9 +7,9 @@ LL | let _fd = unsafe { libc::mkstemp(s) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `test_mkstemp_immutable_arg` at $DIR/mkstemp_immutable_arg.rs:LL:CC + = note: inside `test_mkstemp_immutable_arg` at tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs:LL:CC note: inside `main` - --> $DIR/mkstemp_immutable_arg.rs:LL:CC + --> tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs:LL:CC | LL | test_mkstemp_immutable_arg(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs index 624f584a0c85e..ff95beb3a9fe3 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@ignore-target-windows: No libc IO on Windows +//@ignore-target: windows # No libc IO on Windows fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; diff --git a/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.stderr index baa6eb5ad6a09..1be2f08dd8c16 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.stderr @@ -1,12 +1,12 @@ error: unsupported operation: cannot read from stdout - --> $DIR/read_from_stdout.rs:LL:CC + --> tests/fail-dep/libc/fs/read_from_stdout.rs:LL:CC | LL | libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot read from stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/read_from_stdout.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/fs/read_from_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs index d783967f95968..b763121080ed4 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc IO on Windows +//@ignore-target: windows # No libc IO on Windows //@compile-flags: -Zmiri-disable-isolation fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr index 0988eefe22237..971a2d7605332 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 - --> $DIR/unix_open_missing_required_mode.rs:LL:CC + --> tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC | LL | ...safe { libc::open(name_ptr, libc::O_CREAT) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 @@ -7,9 +7,9 @@ LL | ...safe { libc::open(name_ptr, libc::O_CREAT) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `test_file_open_missing_needed_mode` at $DIR/unix_open_missing_required_mode.rs:LL:CC + = note: inside `test_file_open_missing_needed_mode` at tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC note: inside `main` - --> $DIR/unix_open_missing_required_mode.rs:LL:CC + --> tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC | LL | test_file_open_missing_needed_mode(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs index 683c55e90e182..81e5034f11740 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc IO on Windows +//@ignore-target: windows # No libc IO on Windows fn main() -> std::io::Result<()> { let bytes = b"hello"; diff --git a/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.stderr index 37323faf560df..9726a1d2a97da 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.stderr @@ -1,12 +1,12 @@ error: unsupported operation: cannot write to stdin - --> $DIR/write_to_stdin.rs:LL:CC + --> tests/fail-dep/libc/fs/write_to_stdin.rs:LL:CC | LL | libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot write to stdin | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/write_to_stdin.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/fs/write_to_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs index 98ef454c88b3f..dd2dd34623166 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs @@ -1,6 +1,6 @@ //! We test that if we requested to read 4 bytes, but actually read 3 bytes, //! then 3 bytes (not 4) will be initialized. -//@ignore-target-windows: no file system support on Windows +//@ignore-target: windows # no file system support on Windows //@compile-flags: -Zmiri-disable-isolation use std::ffi::CString; diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr index e4c7aba07e345..980d9810abc9a 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer - --> $DIR/libc-read-and-uninit-premature-eof.rs:LL:CC + --> tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs:LL:CC | LL | ... buf.assume_init(); | ^^^^^^^^^^^^^^^^^ constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer @@ -7,7 +7,7 @@ LL | ... buf.assume_init(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/libc-read-and-uninit-premature-eof.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs index fb2426f7b66d8..03d4b2d66330e 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs @@ -1,4 +1,4 @@ -//@only-target-linux +//@only-target: linux // This is a test for registering unsupported fd with epoll. // Register epoll fd with epoll is allowed in real system, but we do not support this. diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.stderr b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.stderr index 6f9b988d4ee2d..59797145c2064 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.stderr @@ -1,12 +1,12 @@ error: unsupported operation: epoll: epoll does not support this file description - --> $DIR/libc_epoll_unsupported_fd.rs:LL:CC + --> tests/fail-dep/libc/libc_epoll_unsupported_fd.rs:LL:CC | LL | let res = unsafe { libc::epoll_ctl(epfd0, libc::EPOLL_CTL_ADD, epfd1, &mut ev) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ epoll: epoll does not support this file description | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/libc_epoll_unsupported_fd.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/libc_epoll_unsupported_fd.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs index fb9a23206c604..0212a63bd0fa2 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs @@ -1,4 +1,4 @@ -//@only-target-linux +//@only-target: linux fn main() { // eventfd read will block when EFD_NONBLOCK flag is clear and counter = 0. // This will pass when blocking is implemented. diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr index fdd0b4272cafb..aff30c81ebdb9 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr @@ -1,12 +1,12 @@ error: unsupported operation: eventfd: blocking is unsupported - --> $DIR/libc_eventfd_read_block.rs:LL:CC + --> tests/fail-dep/libc/libc_eventfd_read_block.rs:LL:CC | LL | libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/libc_eventfd_read_block.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/libc_eventfd_read_block.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs index 2037a516dea1c..ed6ad466901bc 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs @@ -1,4 +1,4 @@ -//@only-target-linux +//@only-target: linux fn main() { // eventfd write will block when EFD_NONBLOCK flag is clear // and the addition caused counter to exceed u64::MAX - 1. diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr index f12c0ddfb1717..2b6066057941f 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr @@ -1,12 +1,12 @@ error: unsupported operation: eventfd: blocking is unsupported - --> $DIR/libc_eventfd_write_block.rs:LL:CC + --> tests/fail-dep/libc/libc_eventfd_write_block.rs:LL:CC | LL | libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/libc_eventfd_write_block.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/libc_eventfd_write_block.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr index 6437c9dbeb44a..d6337c059bae3 100644 --- a/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr +++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/malloc_zero_double_free.rs:LL:CC + --> tests/fail-dep/libc/malloc_zero_double_free.rs:LL:CC | LL | libc::free(ptr); | ^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | libc::free(ptr); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/malloc_zero_double_free.rs:LL:CC + --> tests/fail-dep/libc/malloc_zero_double_free.rs:LL:CC | LL | let ptr = libc::malloc(0); | ^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/malloc_zero_double_free.rs:LL:CC + --> tests/fail-dep/libc/malloc_zero_double_free.rs:LL:CC | LL | libc::free(ptr); | ^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/malloc_zero_double_free.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/malloc_zero_double_free.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr index 657262b8d4136..6f3d7fa7a4f22 100644 --- a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr +++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr @@ -1,11 +1,11 @@ error: memory leaked: ALLOC (C heap, size: 0, align: 1), allocated here: - --> $DIR/malloc_zero_memory_leak.rs:LL:CC + --> tests/fail-dep/libc/malloc_zero_memory_leak.rs:LL:CC | LL | let _ptr = libc::malloc(0); | ^^^^^^^^^^^^^^^ | = note: BACKTRACE: - = note: inside `main` at $DIR/malloc_zero_memory_leak.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/malloc_zero_memory_leak.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr index f03ae33ed9f39..6d3ff176c3559 100644 --- a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer - --> $DIR/memchr_null.rs:LL:CC + --> tests/fail-dep/libc/memchr_null.rs:LL:CC | LL | libc::memchr(ptr::null(), 0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer @@ -7,7 +7,7 @@ LL | libc::memchr(ptr::null(), 0, 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/memchr_null.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/memchr_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr index 4bca5a3db0722..a4ca205c37704 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer - --> $DIR/memcmp_null.rs:LL:CC + --> tests/fail-dep/libc/memcmp_null.rs:LL:CC | LL | libc::memcmp(ptr::null(), ptr::null(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer @@ -7,7 +7,7 @@ LL | libc::memcmp(ptr::null(), ptr::null(), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/memcmp_null.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/memcmp_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr index 6adaaeb3dbf1e..d7b046c18235f 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/memcmp_zero.rs:LL:CC + --> tests/fail-dep/libc/memcmp_zero.rs:LL:CC | LL | libc::memcmp(ptr.cast(), ptr.cast(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | libc::memcmp(ptr.cast(), ptr.cast(), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/memcmp_zero.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/memcmp_zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr index b2da332df2149..336113e344088 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/memcpy_zero.rs:LL:CC + --> tests/fail-dep/libc/memcpy_zero.rs:LL:CC | LL | libc::memcpy(to.cast(), from.cast(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | libc::memcpy(to.cast(), from.cast(), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/memcpy_zero.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/memcpy_zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs index 1fe637d6ce7e9..8b34ff4ac2e37 100644 --- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs +++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs @@ -1,5 +1,5 @@ -//@ignore-target-windows: No `memrchr` on Windows -//@ignore-target-apple: No `memrchr` on some apple targets +//@ignore-target: windows # No `memrchr` on Windows +//@ignore-target: apple # No `memrchr` on some apple targets use std::ptr; diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr index a9ed58d61bb35..ce759f3e17a56 100644 --- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer - --> $DIR/memrchr_null.rs:LL:CC + --> tests/fail-dep/libc/memrchr_null.rs:LL:CC | LL | libc::memrchr(ptr::null(), 0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer @@ -7,7 +7,7 @@ LL | libc::memrchr(ptr::null(), 0, 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/memrchr_null.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/memrchr_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs index 9d55a4935547f..53ca14e6e896c 100644 --- a/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs +++ b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@ignore-target-windows: No mmap on Windows +//@ignore-target: windows # No mmap on Windows #![feature(rustc_private)] diff --git a/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.stderr b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.stderr index cec67b6ef8408..193c9f1eccc4c 100644 --- a/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.stderr +++ b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: deallocating ALLOC, which is mmap memory, using C heap deallocation operation - --> $DIR/mmap_invalid_dealloc.rs:LL:CC + --> tests/fail-dep/libc/mmap_invalid_dealloc.rs:LL:CC | LL | libc::free(ptr); | ^^^^^^^^^^^^^^^ deallocating ALLOC, which is mmap memory, using C heap deallocation operation @@ -7,7 +7,7 @@ LL | libc::free(ptr); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/mmap_invalid_dealloc.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/mmap_invalid_dealloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs index 05ac232f5d7b4..6831734a31b61 100644 --- a/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs +++ b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@ignore-target-windows: No mmap on Windows +//@ignore-target: windows # No mmap on Windows #![feature(rustc_private)] diff --git a/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.stderr b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.stderr index 49f2b84baa85e..8404aeb5a7ae8 100644 --- a/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.stderr +++ b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/mmap_use_after_munmap.rs:LL:CC + --> tests/fail-dep/libc/mmap_use_after_munmap.rs:LL:CC | LL | let _x = *(ptr as *mut u8); | ^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,7 +7,7 @@ LL | let _x = *(ptr as *mut u8); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/mmap_use_after_munmap.rs:LL:CC + --> tests/fail-dep/libc/mmap_use_after_munmap.rs:LL:CC | LL | let ptr = libc::mmap( | ___________________^ @@ -19,12 +19,12 @@ LL | | 0, LL | | ); | |_________^ help: ALLOC was deallocated here: - --> $DIR/mmap_use_after_munmap.rs:LL:CC + --> tests/fail-dep/libc/mmap_use_after_munmap.rs:LL:CC | LL | libc::munmap(ptr, 4096); | ^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/mmap_use_after_munmap.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/mmap_use_after_munmap.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/munmap_partial.rs b/src/tools/miri/tests/fail-dep/libc/munmap_partial.rs index 4386dc71af69c..58aab14ef1d40 100644 --- a/src/tools/miri/tests/fail-dep/libc/munmap_partial.rs +++ b/src/tools/miri/tests/fail-dep/libc/munmap_partial.rs @@ -1,7 +1,7 @@ //! The man pages for mmap/munmap suggest that it is possible to partly unmap a previously-mapped //! region of address space, but to LLVM that would be partial deallocation, which LLVM does not //! support. So even though the man pages say this sort of use is possible, we must report UB. -//@ignore-target-windows: No mmap on Windows +//@ignore-target: windows # No mmap on Windows //@normalize-stderr-test: "size [0-9]+ and alignment" -> "size SIZE and alignment" fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/munmap_partial.stderr b/src/tools/miri/tests/fail-dep/libc/munmap_partial.stderr index 39825eb27c083..7b1703a968a08 100644 --- a/src/tools/miri/tests/fail-dep/libc/munmap_partial.stderr +++ b/src/tools/miri/tests/fail-dep/libc/munmap_partial.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size SIZE and alignment ALIGN, but gave size SIZE and alignment ALIGN - --> $DIR/munmap_partial.rs:LL:CC + --> tests/fail-dep/libc/munmap_partial.rs:LL:CC | LL | libc::munmap(ptr, 1); | ^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size SIZE and alignment ALIGN, but gave size SIZE and alignment ALIGN @@ -7,7 +7,7 @@ LL | libc::munmap(ptr, 1); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/munmap_partial.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/munmap_partial.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs index b6b7b007f2b62..be5d372a048f1 100644 --- a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs +++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No posix_memalign on Windows +//@ignore-target: windows # No posix_memalign on Windows use std::ptr; diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.stderr b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.stderr index 3ed117c5a0adb..1d73ec9575415 100644 --- a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.stderr +++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/posix_memalign_size_zero_double_free.rs:LL:CC + --> tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs:LL:CC | LL | libc::free(ptr); | ^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | libc::free(ptr); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/posix_memalign_size_zero_double_free.rs:LL:CC + --> tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs:LL:CC | LL | let _ = libc::posix_memalign(&mut ptr, align, size); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/posix_memalign_size_zero_double_free.rs:LL:CC + --> tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs:LL:CC | LL | libc::free(ptr); | ^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/posix_memalign_size_zero_double_free.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.rs b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.rs index 1a4c9605fe01c..2f990b34ab534 100644 --- a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.rs +++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No posix_memalign on Windows +//@ignore-target: windows # No posix_memalign on Windows use std::ptr; diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr index 2639031f1cc50..4546185b13e4d 100644 --- a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr +++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr @@ -1,11 +1,11 @@ error: memory leaked: ALLOC (C heap, size: 0, align: 64), allocated here: - --> $DIR/posix_memalign_size_zero_leak.rs:LL:CC + --> tests/fail-dep/libc/posix_memalign_size_zero_leak.rs:LL:CC | LL | let _ = unsafe { libc::posix_memalign(&mut ptr, align, size) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: BACKTRACE: - = note: inside `main` at $DIR/posix_memalign_size_zero_leak.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/posix_memalign_size_zero_leak.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/realloc-zero.stderr b/src/tools/miri/tests/fail-dep/libc/realloc-zero.stderr index 749a61f7396e7..6f8095dbba117 100644 --- a/src/tools/miri/tests/fail-dep/libc/realloc-zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/realloc-zero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `realloc` with a size of zero - --> $DIR/realloc-zero.rs:LL:CC + --> tests/fail-dep/libc/realloc-zero.rs:LL:CC | LL | let p2 = libc::realloc(p1, 0); | ^^^^^^^^^^^^^^^^^^^^ `realloc` with a size of zero @@ -7,7 +7,7 @@ LL | let p2 = libc::realloc(p1, 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/realloc-zero.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/realloc-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs index c28a6d966fe55..ffa4e36f0f4b0 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: no libc socketpair on Windows +//@ignore-target: windows # no libc socketpair on Windows // This is temporarily here because blocking on fd is not supported yet. // When blocking is eventually supported, this will be moved to pass-dep/libc/libc-socketpair diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr index b5ed72d9f1b18..dff332f999280 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr @@ -1,12 +1,12 @@ error: unsupported operation: socketpair read: blocking isn't supported yet - --> $DIR/socketpair_read_blocking.rs:LL:CC + --> tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC | LL | let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair read: blocking isn't supported yet | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/socketpair_read_blocking.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs index e2fbc0ae4b426..e83197dfc0f90 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: no libc socketpair on Windows +//@ignore-target: windows # no libc socketpair on Windows // This is temporarily here because blocking on fd is not supported yet. // When blocking is eventually supported, this will be moved to pass-dep/libc/libc-socketpair fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr index 7b3a0d27636de..0dd89a15c7cfc 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr @@ -1,12 +1,12 @@ error: unsupported operation: socketpair write: blocking isn't supported yet - --> $DIR/socketpair_write_blocking.rs:LL:CC + --> tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC | LL | let _ = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair write: blocking isn't supported yet | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/socketpair_write_blocking.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs index cd8422f4afd40..b23b90d6fcd4a 100644 --- a/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs +++ b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs @@ -1,6 +1,6 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. //! The implementation is not complete enough to permit user code to call it. -//@ignore-target-windows: No `libc::signal` on Windows +//@ignore-target: windows # No `libc: #signal` on Windows //@normalize-stderr-test: "OS `.*`" -> "$$OS" fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr index f62622e29bf13..a92a97cef3b34 100644 --- a/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr +++ b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr @@ -1,5 +1,5 @@ error: unsupported operation: can't call foreign function `signal` on $OS - --> $DIR/unsupported_incomplete_function.rs:LL:CC + --> tests/fail-dep/libc/unsupported_incomplete_function.rs:LL:CC | LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function `signal` on $OS @@ -7,7 +7,7 @@ LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); = help: if this is a basic API commonly used on this target, please report an issue with Miri = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases = note: BACKTRACE: - = note: inside `main` at $DIR/unsupported_incomplete_function.rs:LL:CC + = note: inside `main` at tests/fail-dep/libc/unsupported_incomplete_function.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr index d1731a0f4206f..3642f3f28ca2a 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr @@ -13,7 +13,7 @@ LL | ABORT(); = note: inside `std::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` - --> $DIR/alloc_error_handler.rs:LL:CC + --> tests/fail/alloc/alloc_error_handler.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); | ^ diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr index 5d9c2e2fb4c38..d12e119bce3dd 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr @@ -1,14 +1,14 @@ custom alloc error handler: Layout { size: 4, align: 4 (1 << 2) } error: abnormal termination: the program aborted execution - --> $DIR/alloc_error_handler_custom.rs:LL:CC + --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC | LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution | = note: BACKTRACE: - = note: inside `alloc_error_handler` at $DIR/alloc_error_handler_custom.rs:LL:CC + = note: inside `alloc_error_handler` at tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC note: inside `_::__rg_oom` - --> $DIR/alloc_error_handler_custom.rs:LL:CC + --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC | LL | #[alloc_error_handler] | ---------------------- in this procedural macro expansion @@ -17,7 +17,7 @@ LL | fn alloc_error_handler(layout: Layout) -> ! { = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `start` - --> $DIR/alloc_error_handler_custom.rs:LL:CC + --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr index 6b98f6f75d853..f495d65a8b017 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr @@ -2,18 +2,18 @@ custom panic handler called! panicked at RUSTLIB/alloc/src/alloc.rs:LL:CC: memory allocation of 4 bytes failed error: abnormal termination: the program aborted execution - --> $DIR/alloc_error_handler_no_std.rs:LL:CC + --> tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC | LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_handler` at $DIR/alloc_error_handler_no_std.rs:LL:CC + = note: inside `panic_handler` at tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC = note: inside `alloc::alloc::__alloc_error_handler::__rdl_oom` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `start` - --> $DIR/alloc_error_handler_no_std.rs:LL:CC + --> tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.rs b/src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.rs index e8ba824db717c..f04927beb1632 100644 --- a/src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.rs +++ b/src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.rs @@ -1,10 +1,8 @@ -use std::alloc::{alloc, dealloc, Layout}; - -//@error-in-other-file: has size 1 and alignment 1, but gave size 1 and alignment 2 +use std::alloc::{Layout, alloc, dealloc}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); - dealloc(x, Layout::from_size_align_unchecked(1, 2)); + dealloc(x, Layout::from_size_align_unchecked(1, 2)); //~ERROR: has size 1 and alignment 1, but gave size 1 and alignment 2 } } diff --git a/src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.stderr b/src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.stderr index 40ed093198d30..f07db3c62c91d 100644 --- a/src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.stderr +++ b/src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> tests/fail/alloc/deallocate-bad-alignment.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN +LL | dealloc(x, Layout::from_size_align_unchecked(1, 2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `main` - --> $DIR/deallocate-bad-alignment.rs:LL:CC - | -LL | dealloc(x, Layout::from_size_align_unchecked(1, 2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at tests/fail/alloc/deallocate-bad-alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/deallocate-bad-size.rs b/src/tools/miri/tests/fail/alloc/deallocate-bad-size.rs index e3f9a20ac3bcb..d818f3a9304ee 100644 --- a/src/tools/miri/tests/fail/alloc/deallocate-bad-size.rs +++ b/src/tools/miri/tests/fail/alloc/deallocate-bad-size.rs @@ -1,10 +1,8 @@ -use std::alloc::{alloc, dealloc, Layout}; - -//@error-in-other-file: has size 1 and alignment 1, but gave size 2 and alignment 1 +use std::alloc::{Layout, alloc, dealloc}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); - dealloc(x, Layout::from_size_align_unchecked(2, 1)); + dealloc(x, Layout::from_size_align_unchecked(2, 1)); //~ERROR: has size 1 and alignment 1, but gave size 2 and alignment 1 } } diff --git a/src/tools/miri/tests/fail/alloc/deallocate-bad-size.stderr b/src/tools/miri/tests/fail/alloc/deallocate-bad-size.stderr index e9b935d2c83b2..c913bde04cc91 100644 --- a/src/tools/miri/tests/fail/alloc/deallocate-bad-size.stderr +++ b/src/tools/miri/tests/fail/alloc/deallocate-bad-size.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> tests/fail/alloc/deallocate-bad-size.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN +LL | dealloc(x, Layout::from_size_align_unchecked(2, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `main` - --> $DIR/deallocate-bad-size.rs:LL:CC - | -LL | dealloc(x, Layout::from_size_align_unchecked(2, 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at tests/fail/alloc/deallocate-bad-size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/deallocate-twice.rs b/src/tools/miri/tests/fail/alloc/deallocate-twice.rs index 7a3ff84b2cb13..340ca1f75ef90 100644 --- a/src/tools/miri/tests/fail/alloc/deallocate-twice.rs +++ b/src/tools/miri/tests/fail/alloc/deallocate-twice.rs @@ -1,11 +1,9 @@ -use std::alloc::{alloc, dealloc, Layout}; - -//@error-in-other-file: has been freed +use std::alloc::{Layout, alloc, dealloc}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); dealloc(x, Layout::from_size_align_unchecked(1, 1)); - dealloc(x, Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 1)); //~ERROR: has been freed } } diff --git a/src/tools/miri/tests/fail/alloc/deallocate-twice.stderr b/src/tools/miri/tests/fail/alloc/deallocate-twice.stderr index 76abd96e24afb..9e6ce3d45a726 100644 --- a/src/tools/miri/tests/fail/alloc/deallocate-twice.stderr +++ b/src/tools/miri/tests/fail/alloc/deallocate-twice.stderr @@ -1,28 +1,23 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> tests/fail/alloc/deallocate-twice.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling +LL | dealloc(x, Layout::from_size_align_unchecked(1, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/deallocate-twice.rs:LL:CC + --> tests/fail/alloc/deallocate-twice.rs:LL:CC | LL | let x = alloc(Layout::from_size_align_unchecked(1, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/deallocate-twice.rs:LL:CC + --> tests/fail/alloc/deallocate-twice.rs:LL:CC | LL | dealloc(x, Layout::from_size_align_unchecked(1, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `main` - --> $DIR/deallocate-twice.rs:LL:CC - | -LL | dealloc(x, Layout::from_size_align_unchecked(1, 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at tests/fail/alloc/deallocate-twice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr b/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr index 287a1f1a3e396..4c355c511ef45 100644 --- a/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr +++ b/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr @@ -10,7 +10,7 @@ LL | FREE(); = note: inside `std::sys::alloc::PLATFORM::::dealloc` at RUSTLIB/std/src/sys/alloc/PLATFORM.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC note: inside `main` - --> $DIR/global_system_mixup.rs:LL:CC + --> tests/fail/alloc/global_system_mixup.rs:LL:CC | LL | unsafe { System.deallocate(ptr, l) }; | ^ diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr index 82bcb48cbe6ac..e08a747f7fafc 100644 --- a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr +++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr @@ -1,5 +1,5 @@ error: unsupported operation: can't call foreign function `__rust_alloc` on $OS - --> $DIR/no_global_allocator.rs:LL:CC + --> tests/fail/alloc/no_global_allocator.rs:LL:CC | LL | __rust_alloc(1, 1); | ^^^^^^^^^^^^^^^^^^ can't call foreign function `__rust_alloc` on $OS @@ -7,7 +7,7 @@ LL | __rust_alloc(1, 1); = help: if this is a basic API commonly used on this target, please report an issue with Miri = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases = note: BACKTRACE: - = note: inside `start` at $DIR/no_global_allocator.rs:LL:CC + = note: inside `start` at tests/fail/alloc/no_global_allocator.rs:LL:CC error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/alloc/reallocate-bad-size.rs b/src/tools/miri/tests/fail/alloc/reallocate-bad-size.rs index 49b2c62d7e4f7..7b9ef1d9121c5 100644 --- a/src/tools/miri/tests/fail/alloc/reallocate-bad-size.rs +++ b/src/tools/miri/tests/fail/alloc/reallocate-bad-size.rs @@ -1,10 +1,8 @@ -use std::alloc::{alloc, realloc, Layout}; - -//@error-in-other-file: has size 1 and alignment 1, but gave size 2 and alignment 1 +use std::alloc::{Layout, alloc, realloc}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); - let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1); + let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1); //~ERROR: has size 1 and alignment 1, but gave size 2 and alignment 1 } } diff --git a/src/tools/miri/tests/fail/alloc/reallocate-bad-size.stderr b/src/tools/miri/tests/fail/alloc/reallocate-bad-size.stderr index 5347e7a95ac4d..6f6c8850603d4 100644 --- a/src/tools/miri/tests/fail/alloc/reallocate-bad-size.stderr +++ b/src/tools/miri/tests/fail/alloc/reallocate-bad-size.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> tests/fail/alloc/reallocate-bad-size.rs:LL:CC | -LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN +LL | let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `main` - --> $DIR/reallocate-bad-size.rs:LL:CC - | -LL | let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at tests/fail/alloc/reallocate-bad-size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.rs b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.rs index ecdd3ae5fee75..9f9921b1817d9 100644 --- a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.rs +++ b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, realloc, Layout}; +use std::alloc::{Layout, alloc, realloc}; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr index fb3b035b11611..17b40fbdcdcdc 100644 --- a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr +++ b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/reallocate-change-alloc.rs:LL:CC + --> tests/fail/alloc/reallocate-change-alloc.rs:LL:CC | LL | let _z = *x; | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | let _z = *x; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/reallocate-change-alloc.rs:LL:CC + --> tests/fail/alloc/reallocate-change-alloc.rs:LL:CC | LL | let x = alloc(Layout::from_size_align_unchecked(1, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/reallocate-change-alloc.rs:LL:CC + --> tests/fail/alloc/reallocate-change-alloc.rs:LL:CC | LL | let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/reallocate-change-alloc.rs:LL:CC + = note: inside `main` at tests/fail/alloc/reallocate-change-alloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/reallocate-dangling.rs b/src/tools/miri/tests/fail/alloc/reallocate-dangling.rs index 622348ad190d1..97357c629af63 100644 --- a/src/tools/miri/tests/fail/alloc/reallocate-dangling.rs +++ b/src/tools/miri/tests/fail/alloc/reallocate-dangling.rs @@ -1,11 +1,9 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; - -//@error-in-other-file: has been freed +use std::alloc::{Layout, alloc, dealloc, realloc}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); dealloc(x, Layout::from_size_align_unchecked(1, 1)); - let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); //~ERROR: has been freed } } diff --git a/src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr b/src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr index 9b8a892620162..06960380f6c94 100644 --- a/src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr +++ b/src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr @@ -1,28 +1,23 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> tests/fail/alloc/reallocate-dangling.rs:LL:CC | -LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling +LL | let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/reallocate-dangling.rs:LL:CC + --> tests/fail/alloc/reallocate-dangling.rs:LL:CC | LL | let x = alloc(Layout::from_size_align_unchecked(1, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/reallocate-dangling.rs:LL:CC + --> tests/fail/alloc/reallocate-dangling.rs:LL:CC | LL | dealloc(x, Layout::from_size_align_unchecked(1, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `main` - --> $DIR/reallocate-dangling.rs:LL:CC - | -LL | let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at tests/fail/alloc/reallocate-dangling.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/stack_free.stderr b/src/tools/miri/tests/fail/alloc/stack_free.stderr index 2adec68c0dd84..7d7cee133c653 100644 --- a/src/tools/miri/tests/fail/alloc/stack_free.stderr +++ b/src/tools/miri/tests/fail/alloc/stack_free.stderr @@ -1,19 +1,17 @@ error: Undefined Behavior: deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> RUSTLIB/alloc/src/boxed.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation +LL | self.1.deallocate(From::from(ptr.cast()), layout); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `main` - --> $DIR/stack_free.rs:LL:CC + --> tests/fail/alloc/stack_free.rs:LL:CC | LL | drop(bad_box); | ^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/alloc/too_large.stderr b/src/tools/miri/tests/fail/alloc/too_large.stderr index 77dcf91d843f9..03e54088e3b50 100644 --- a/src/tools/miri/tests/fail/alloc/too_large.stderr +++ b/src/tools/miri/tests/fail/alloc/too_large.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: creating an allocation larger than half the address space - --> $DIR/too_large.rs:LL:CC + --> tests/fail/alloc/too_large.rs:LL:CC | LL | __rust_alloc(bytes, 1); | ^^^^^^^^^^^^^^^^^^^^^^ creating an allocation larger than half the address space @@ -7,7 +7,7 @@ LL | __rust_alloc(bytes, 1); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/too_large.rs:LL:CC + = note: inside `main` at tests/fail/alloc/too_large.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/unsupported_big_alignment.stderr b/src/tools/miri/tests/fail/alloc/unsupported_big_alignment.stderr index 4c783b866c877..8eb71f5ce8459 100644 --- a/src/tools/miri/tests/fail/alloc/unsupported_big_alignment.stderr +++ b/src/tools/miri/tests/fail/alloc/unsupported_big_alignment.stderr @@ -1,12 +1,12 @@ error: unsupported operation: creating allocation with alignment ALIGN exceeding rustc's maximum supported value - --> $DIR/unsupported_big_alignment.rs:LL:CC + --> tests/fail/alloc/unsupported_big_alignment.rs:LL:CC | LL | __rust_alloc(1, 1 << 30); | ^^^^^^^^^^^^^^^^^^^^^^^^ creating allocation with alignment ALIGN exceeding rustc's maximum supported value | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/unsupported_big_alignment.rs:LL:CC + = note: inside `main` at tests/fail/alloc/unsupported_big_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/unsupported_non_power_two_alignment.stderr b/src/tools/miri/tests/fail/alloc/unsupported_non_power_two_alignment.stderr index 69a6c375f47f0..0a36d3d58b616 100644 --- a/src/tools/miri/tests/fail/alloc/unsupported_non_power_two_alignment.stderr +++ b/src/tools/miri/tests/fail/alloc/unsupported_non_power_two_alignment.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: creating allocation with non-power-of-two alignment ALIGN - --> $DIR/unsupported_non_power_two_alignment.rs:LL:CC + --> tests/fail/alloc/unsupported_non_power_two_alignment.rs:LL:CC | LL | __rust_alloc(1, 3); | ^^^^^^^^^^^^^^^^^^ creating allocation with non-power-of-two alignment ALIGN @@ -7,7 +7,7 @@ LL | __rust_alloc(1, 3); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unsupported_non_power_two_alignment.rs:LL:CC + = note: inside `main` at tests/fail/alloc/unsupported_non_power_two_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.stack.stderr b/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.stack.stderr index 6903a52f304c7..d7e7c2bc03933 100644 --- a/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/alias_through_mutation.rs:LL:CC + --> tests/fail/both_borrows/alias_through_mutation.rs:LL:CC | LL | let _val = *target_alias; | ^^^^^^^^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *target_alias; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/alias_through_mutation.rs:LL:CC + --> tests/fail/both_borrows/alias_through_mutation.rs:LL:CC | LL | *x = &mut *(target as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/alias_through_mutation.rs:LL:CC + --> tests/fail/both_borrows/alias_through_mutation.rs:LL:CC | LL | *target = 13; | ^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/alias_through_mutation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.tree.stderr index 0bd196eab1b83..c146658d31035 100644 --- a/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden - --> $DIR/alias_through_mutation.rs:LL:CC + --> tests/fail/both_borrows/alias_through_mutation.rs:LL:CC | LL | let _val = *target_alias; | ^^^^^^^^^^^^^ read access through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | let _val = *target_alias; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child read access help: the accessed tag was created here, in the initial state Frozen - --> $DIR/alias_through_mutation.rs:LL:CC + --> tests/fail/both_borrows/alias_through_mutation.rs:LL:CC | LL | *x = &mut *(target as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/alias_through_mutation.rs:LL:CC + --> tests/fail/both_borrows/alias_through_mutation.rs:LL:CC | LL | *target = 13; | ^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/alias_through_mutation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr index 4f9e6222db266..170027d9f904f 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/aliasing_mut1.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | pub fn safe(x: &mut i32, y: &mut i32) { | ^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,19 +7,19 @@ LL | pub fn safe(x: &mut i32, y: &mut i32) { = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/aliasing_mut1.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; | ^^^^^^ help: is this argument - --> $DIR/aliasing_mut1.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | pub fn safe(x: &mut i32, y: &mut i32) { | ^ = note: BACKTRACE (of the first span): - = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC + = note: inside `safe` at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC note: inside `main` - --> $DIR/aliasing_mut1.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | safe_raw(xraw, xraw); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr index 3aff0a41de231..62ab1c4f87285 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/aliasing_mut1.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | *x = 1; | ^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,20 +7,20 @@ LL | *x = 1; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Reserved (conflicted) which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/aliasing_mut1.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | pub fn safe(x: &mut i32, y: &mut i32) { | ^ help: the accessed tag later transitioned to Reserved (conflicted) due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4] - --> $DIR/aliasing_mut1.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | pub fn safe(x: &mut i32, y: &mut i32) { | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit = note: BACKTRACE (of the first span): - = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC + = note: inside `safe` at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC note: inside `main` - --> $DIR/aliasing_mut1.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | safe_raw(xraw, xraw); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr index 54679d177da0f..274dc22a7e175 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is strongly protected - --> $DIR/aliasing_mut2.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | pub fn safe(x: &i32, y: &mut i32) { | ^ not granting access to tag because that would remove [SharedReadOnly for ] which is strongly protected @@ -7,19 +7,19 @@ LL | pub fn safe(x: &i32, y: &mut i32) { = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/aliasing_mut2.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | let xref = &mut x; | ^^^^^^ help: is this argument - --> $DIR/aliasing_mut2.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | pub fn safe(x: &i32, y: &mut i32) { | ^ = note: BACKTRACE (of the first span): - = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC + = note: inside `safe` at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC note: inside `main` - --> $DIR/aliasing_mut2.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | safe_raw(xshr, xraw); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr index d8602a54c6408..f3d7a0168255e 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/aliasing_mut2.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | *y = 2; | ^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,20 +7,20 @@ LL | *y = 2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Reserved (conflicted) which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/aliasing_mut2.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | pub fn safe(x: &i32, y: &mut i32) { | ^ help: the accessed tag later transitioned to Reserved (conflicted) due to a foreign read access at offsets [0x0..0x4] - --> $DIR/aliasing_mut2.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | let _v = *x; | ^^ = help: this transition corresponds to a temporary loss of write permissions until function exit = note: BACKTRACE (of the first span): - = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC + = note: inside `safe` at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC note: inside `main` - --> $DIR/aliasing_mut2.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | safe_raw(xshr, xraw); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr index b04139f3bd9cb..a89baa50ff397 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/aliasing_mut3.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | pub fn safe(x: &mut i32, y: &i32) { | ^ @@ -10,19 +10,19 @@ LL | pub fn safe(x: &mut i32, y: &i32) { = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/aliasing_mut3.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); | ^^^^ help: was later invalidated at offsets [0x0..0x4] by a Unique function-entry retag inside this call - --> $DIR/aliasing_mut3.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); | ^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC + = note: inside `safe` at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC note: inside `main` - --> $DIR/aliasing_mut3.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr index 83191962a3f87..ba9197a50d6d1 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/aliasing_mut3.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | *x = 1; | ^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,20 +7,20 @@ LL | *x = 1; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Reserved (conflicted) which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/aliasing_mut3.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | pub fn safe(x: &mut i32, y: &i32) { | ^ help: the accessed tag later transitioned to Reserved (conflicted) due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4] - --> $DIR/aliasing_mut3.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | pub fn safe(x: &mut i32, y: &i32) { | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit = note: BACKTRACE (of the first span): - = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC + = note: inside `safe` at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC note: inside `main` - --> $DIR/aliasing_mut3.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr index b3e97c92f1a29..bdda7139490ae 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is strongly protected - --> $DIR/aliasing_mut4.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | pub fn safe(x: &i32, y: &mut Cell) { | ^ not granting access to tag because that would remove [SharedReadOnly for ] which is strongly protected @@ -7,19 +7,19 @@ LL | pub fn safe(x: &i32, y: &mut Cell) { = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/aliasing_mut4.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | let xref = &mut x; | ^^^^^^ help: is this argument - --> $DIR/aliasing_mut4.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | pub fn safe(x: &i32, y: &mut Cell) { | ^ = note: BACKTRACE (of the first span): - = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC + = note: inside `safe` at tests/fail/both_borrows/aliasing_mut4.rs:LL:CC note: inside `main` - --> $DIR/aliasing_mut4.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | safe_raw(xshr, xraw as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr index b1f1e231e5ab8..5162368b51fc1 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr @@ -9,12 +9,12 @@ LL | ptr::write(dest, src); = help: this foreign write access would cause the protected tag (currently Frozen) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/aliasing_mut4.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | y.set(1); | ^^^^^^^^ help: the protected tag was created here, in the initial state Frozen - --> $DIR/aliasing_mut4.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | pub fn safe(x: &i32, y: &mut Cell) { | ^ @@ -23,12 +23,12 @@ LL | pub fn safe(x: &i32, y: &mut Cell) { = note: inside `std::cell::Cell::::replace` at RUSTLIB/core/src/cell.rs:LL:CC = note: inside `std::cell::Cell::::set` at RUSTLIB/core/src/cell.rs:LL:CC note: inside `safe` - --> $DIR/aliasing_mut4.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | y.set(1); | ^^^^^^^^ note: inside `main` - --> $DIR/aliasing_mut4.rs:LL:CC + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | safe_raw(xshr, xraw as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr index bed0b880c3a39..0cffdcd21c43f 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | *LEAK = 7; | ^^^^^^^^^ @@ -10,24 +10,24 @@ LL | *LEAK = 7; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | LEAK = x as *const _ as *mut _; | ^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | *our = 5; | ^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC + = note: inside `unknown_code_2` at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC note: inside `demo_box_advanced_unique` - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); | ^^^^^^^^^^^^^^^^ note: inside `main` - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | demo_box_advanced_unique(Box::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr index 27d987feb574d..075df9982c627 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | *LEAK = 7; | ^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,25 +7,25 @@ LL | *LEAK = 7; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Frozen - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | fn unknown_code_1(x: &i32) { | ^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | *our = 5; | ^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC + = note: inside `unknown_code_2` at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC note: inside `demo_box_advanced_unique` - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); | ^^^^^^^^^^^^^^^^ note: inside `main` - --> $DIR/box_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | demo_box_advanced_unique(Box::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr index a9ea7a9e9c401..3dc3f8c6619d5 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is weakly protected - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | *y | ^^ not granting access to tag because that would remove [Unique for ] which is weakly protected @@ -7,19 +7,19 @@ LL | *y = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | let ptr = &mut v as *mut i32; | ^^^^^^ help: is this argument - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `test` at $DIR/box_noalias_violation.rs:LL:CC + = note: inside `test` at tests/fail/both_borrows/box_noalias_violation.rs:LL:CC note: inside `main` - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | test(Box::from_raw(ptr), ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr index 95cf37c812394..c788e455c8d23 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | *y | ^^ read access through at ALLOC[0x0] is forbidden @@ -9,25 +9,25 @@ LL | *y = help: this foreign read access would cause the protected tag (currently Active) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | let ptr = &mut v as *mut i32; | ^^^^^^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { | ^^^^^ help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | *x = 5; | ^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: BACKTRACE (of the first span): - = note: inside `test` at $DIR/box_noalias_violation.rs:LL:CC + = note: inside `test` at tests/fail/both_borrows/box_noalias_violation.rs:LL:CC note: inside `main` - --> $DIR/box_noalias_violation.rs:LL:CC + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | test(Box::from_raw(ptr), ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.stack.stderr b/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.stack.stderr index d2bf4c6a59c42..4e5355f5653f2 100644 --- a/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - --> $DIR/buggy_as_mut_slice.rs:LL:CC + --> tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC | LL | v1[1] = 5; | ^^^^^^^^^ @@ -10,17 +10,17 @@ LL | v1[1] = 5; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0xc] - --> $DIR/buggy_as_mut_slice.rs:LL:CC + --> tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC | LL | let v1 = safe::as_mut_slice(&v); | ^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0xc] by a Unique retag - --> $DIR/buggy_as_mut_slice.rs:LL:CC + --> tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC | LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.tree.stderr b/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.tree.stderr index 16e87c4d4ebc2..bad42343c00ef 100644 --- a/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x4] is forbidden - --> $DIR/buggy_as_mut_slice.rs:LL:CC + --> tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC | LL | v2[1] = 7; | ^^^^^^^^^ write access through at ALLOC[0x4] is forbidden @@ -7,18 +7,18 @@ LL | v2[1] = 7; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/buggy_as_mut_slice.rs:LL:CC + --> tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC | LL | let v2 = safe::as_mut_slice(&v); | ^^^^^^^^^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8] - --> $DIR/buggy_as_mut_slice.rs:LL:CC + --> tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC | LL | v1[1] = 5; | ^^^^^^^^^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr index 71d962a5523f1..28be7607aa3ca 100644 --- a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/buggy_split_at_mut.rs:LL:CC + --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC | LL | / ( LL | | from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" @@ -14,19 +14,19 @@ LL | | ) = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x10] - --> $DIR/buggy_split_at_mut.rs:LL:CC + --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC | LL | from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x10] by a Unique retag - --> $DIR/buggy_split_at_mut.rs:LL:CC + --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `safe::split_at_mut::` at $DIR/buggy_split_at_mut.rs:LL:CC + = note: inside `safe::split_at_mut::` at tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC note: inside `main` - --> $DIR/buggy_split_at_mut.rs:LL:CC + --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC | LL | let (a, b) = safe::split_at_mut(&mut array, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.tree.stderr b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.tree.stderr index aaf7c2256a78a..c734f257a4047 100644 --- a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x4] is forbidden - --> $DIR/buggy_split_at_mut.rs:LL:CC + --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC | LL | b[1] = 6; | ^^^^^^^^ write access through at ALLOC[0x4] is forbidden @@ -7,18 +7,18 @@ LL | b[1] = 6; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/buggy_split_at_mut.rs:LL:CC + --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC | LL | let (a, b) = safe::split_at_mut(&mut array, 0); | ^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8] - --> $DIR/buggy_split_at_mut.rs:LL:CC + --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC | LL | a[1] = 5; | ^^^^^^^^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write1.stack.stderr index 3a9faeb80eed5..9df441cb9564f 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write1.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - --> $DIR/illegal_write1.rs:LL:CC + --> tests/fail/both_borrows/illegal_write1.rs:LL:CC | LL | unsafe { *x = 42 }; | ^^^^^^^ @@ -10,12 +10,12 @@ LL | unsafe { *x = 42 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/illegal_write1.rs:LL:CC + --> tests/fail/both_borrows/illegal_write1.rs:LL:CC | LL | let x: *mut u32 = xref as *const _ as *mut _; | ^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_write1.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write1.tree.stderr index 6241c9db0d206..cd415ad6de9f0 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write1.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/illegal_write1.rs:LL:CC + --> tests/fail/both_borrows/illegal_write1.rs:LL:CC | LL | unsafe { *x = 42 }; | ^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,12 +7,12 @@ LL | unsafe { *x = 42 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Frozen which forbids this child write access help: the accessed tag was created here, in the initial state Frozen - --> $DIR/illegal_write1.rs:LL:CC + --> tests/fail/both_borrows/illegal_write1.rs:LL:CC | LL | let xref = &*target; | ^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_write1.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write5.stack.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write5.stack.stderr index 16f8a3cbd02af..2a517941de5b5 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write5.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write5.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_write5.rs:LL:CC + --> tests/fail/both_borrows/illegal_write5.rs:LL:CC | LL | let _val = *xref; | ^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *xref; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/illegal_write5.rs:LL:CC + --> tests/fail/both_borrows/illegal_write5.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/illegal_write5.rs:LL:CC + --> tests/fail/both_borrows/illegal_write5.rs:LL:CC | LL | unsafe { *xraw = 15 }; | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_write5.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/illegal_write5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write5.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write5.tree.stderr index dec2bb6880f87..38bc957cc33ee 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write5.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write5.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden - --> $DIR/illegal_write5.rs:LL:CC + --> tests/fail/both_borrows/illegal_write5.rs:LL:CC | LL | let _val = *xref; | ^^^^^ read access through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | let _val = *xref; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child read access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/illegal_write5.rs:LL:CC + --> tests/fail/both_borrows/illegal_write5.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/illegal_write5.rs:LL:CC + --> tests/fail/both_borrows/illegal_write5.rs:LL:CC | LL | unsafe { *xraw = 15 }; | ^^^^^^^^^^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_write5.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/illegal_write5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr index b5484745c41db..e75334508ffd8 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; | ^^^^^^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,19 +7,19 @@ LL | unsafe { *y = 2 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | let p = x as *mut u32; | ^ help: is this argument - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { | ^ = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC + = note: inside `foo` at tests/fail/both_borrows/illegal_write6.rs:LL:CC note: inside `main` - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | foo(x, p); | ^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr index 2e161ceea88db..31599a767cfac 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; | ^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -9,25 +9,25 @@ LL | unsafe { *y = 2 }; = help: this foreign write access would cause the protected tag (currently Active) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | let x = &mut 0u32; | ^^^^^^^^^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { | ^ help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | *a = 1; | ^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC + = note: inside `foo` at tests/fail/both_borrows/illegal_write6.rs:LL:CC note: inside `main` - --> $DIR/illegal_write6.rs:LL:CC + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | foo(x, p); | ^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr index 11edbc3270c96..b5df165328909 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is strongly protected - --> $DIR/invalidate_against_protector2.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | unsafe { *x = 0 }; | ^^^^^^ not granting access to tag because that would remove [SharedReadOnly for ] which is strongly protected @@ -7,19 +7,19 @@ LL | unsafe { *x = 0 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/invalidate_against_protector2.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ help: is this argument - --> $DIR/invalidate_against_protector2.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ = note: BACKTRACE (of the first span): - = note: inside `inner` at $DIR/invalidate_against_protector2.rs:LL:CC + = note: inside `inner` at tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC note: inside `main` - --> $DIR/invalidate_against_protector2.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | inner(xraw, xref); | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr index 9fa52262f7ea8..c3b836a8aa73b 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/invalidate_against_protector2.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | unsafe { *x = 0 }; | ^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -9,19 +9,19 @@ LL | unsafe { *x = 0 }; = help: this foreign write access would cause the protected tag (currently Frozen) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/invalidate_against_protector2.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ help: the protected tag was created here, in the initial state Frozen - --> $DIR/invalidate_against_protector2.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ = note: BACKTRACE (of the first span): - = note: inside `inner` at $DIR/invalidate_against_protector2.rs:LL:CC + = note: inside `inner` at tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC note: inside `main` - --> $DIR/invalidate_against_protector2.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | inner(xraw, xref); | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.rs b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.rs index 170bcf9590a76..44ec4129d6093 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.rs +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.rs @@ -1,7 +1,7 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -use std::alloc::{alloc, Layout}; +use std::alloc::{Layout, alloc}; fn inner(x: *mut i32, _y: &i32) { // If `x` and `y` alias, retagging is fine with this... but we really diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr index c6666ceac2b33..0010ce0e4ed63 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is strongly protected - --> $DIR/invalidate_against_protector3.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | unsafe { *x = 0 }; | ^^^^^^ not granting access to tag because that would remove [SharedReadOnly for ] which is strongly protected @@ -7,19 +7,19 @@ LL | unsafe { *x = 0 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created here, as the root tag for ALLOC - --> $DIR/invalidate_against_protector3.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | let ptr = alloc(Layout::for_value(&0i32)) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: is this argument - --> $DIR/invalidate_against_protector3.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ = note: BACKTRACE (of the first span): - = note: inside `inner` at $DIR/invalidate_against_protector3.rs:LL:CC + = note: inside `inner` at tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC note: inside `main` - --> $DIR/invalidate_against_protector3.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | inner(ptr, &*ptr); | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr index 2cf476c837c57..b47fb81f5f4e6 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through (root of the allocation) at ALLOC[0x0] is forbidden - --> $DIR/invalidate_against_protector3.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | unsafe { *x = 0 }; | ^^^^^^ write access through (root of the allocation) at ALLOC[0x0] is forbidden @@ -9,19 +9,19 @@ LL | unsafe { *x = 0 }; = help: this foreign write access would cause the protected tag (currently Frozen) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/invalidate_against_protector3.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | let ptr = alloc(Layout::for_value(&0i32)) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the protected tag was created here, in the initial state Frozen - --> $DIR/invalidate_against_protector3.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ = note: BACKTRACE (of the first span): - = note: inside `inner` at $DIR/invalidate_against_protector3.rs:LL:CC + = note: inside `inner` at tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC note: inside `main` - --> $DIR/invalidate_against_protector3.rs:LL:CC + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | inner(ptr, &*ptr); | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr index 64bbbfcd848b6..cd27bb818e766 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr @@ -7,7 +7,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/issue-miri-1050-1.rs:LL:CC + --> tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC | LL | let ptr = Box::into_raw(Box::new(0u16)); | ^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | let ptr = Box::into_raw(Box::new(0u16)); = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` - --> $DIR/issue-miri-1050-1.rs:LL:CC + --> tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC | LL | drop(Box::from_raw(ptr as *mut u32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr index 64bbbfcd848b6..cd27bb818e766 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr @@ -7,7 +7,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/issue-miri-1050-1.rs:LL:CC + --> tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC | LL | let ptr = Box::into_raw(Box::new(0u16)); | ^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | let ptr = Box::into_raw(Box::new(0u16)); = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` - --> $DIR/issue-miri-1050-1.rs:LL:CC + --> tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC | LL | drop(Box::from_raw(ptr as *mut u32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr index 04494b5256172..04e5765371e7f 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr @@ -10,7 +10,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` - --> $DIR/issue-miri-1050-2.rs:LL:CC + --> tests/fail/both_borrows/issue-miri-1050-2.rs:LL:CC | LL | drop(Box::from_raw(ptr.as_ptr())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr index 04494b5256172..04e5765371e7f 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr @@ -10,7 +10,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` - --> $DIR/issue-miri-1050-2.rs:LL:CC + --> tests/fail/both_borrows/issue-miri-1050-2.rs:LL:CC | LL | drop(Box::from_raw(ptr.as_ptr())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.stack.stderr b/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.stack.stderr index e78807ec1c8de..ffc73ee43de95 100644 --- a/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/load_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/load_invalid_shr.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *xref_in_mem; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/load_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/load_invalid_shr.rs:LL:CC | LL | let xref_in_mem = Box::new(xref); | ^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/load_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/load_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/load_invalid_shr.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/load_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.tree.stderr index 0fcfc20e43696..4610739739c5d 100644 --- a/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x0] is forbidden - --> $DIR/load_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/load_invalid_shr.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ reborrow through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | let _val = *xref_in_mem; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Frozen - --> $DIR/load_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/load_invalid_shr.rs:LL:CC | LL | let xref_in_mem = Box::new(xref); | ^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/load_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/load_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/load_invalid_shr.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/load_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr index 264503f2f2fca..92df9bcbe384f 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | *LEAK = 7; | ^^^^^^^^^ @@ -10,24 +10,24 @@ LL | *LEAK = 7; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | LEAK = x as *const _ as *mut _; | ^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | *our = 5; | ^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC + = note: inside `unknown_code_2` at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); | ^^^^^^^^^^^^^^^^ note: inside `main` - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | demo_mut_advanced_unique(&mut 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr index 5b4ee4a891302..46660d312953e 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | *LEAK = 7; | ^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,25 +7,25 @@ LL | *LEAK = 7; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Frozen - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | fn unknown_code_1(x: &i32) { | ^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | *our = 5; | ^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC + = note: inside `unknown_code_2` at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); | ^^^^^^^^^^^^^^^^ note: inside `main` - --> $DIR/mut_exclusive_violation1.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | demo_mut_advanced_unique(&mut 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.stack.stderr index 35d418f574c9a..42e30cf10c986 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/mut_exclusive_violation2.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC | LL | let _val = *raw1; | ^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *raw1; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/mut_exclusive_violation2.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC | LL | let raw1 = ptr1.as_mut(); | ^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a Unique retag - --> $DIR/mut_exclusive_violation2.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC | LL | let raw2 = ptr2.as_mut(); | ^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.tree.stderr index d3bc54b7ef3c9..a9b1b49e3852d 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/mut_exclusive_violation2.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC | LL | *raw1 = 3; | ^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | *raw1 = 3; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/mut_exclusive_violation2.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC | LL | let raw1 = ptr1.as_mut(); | ^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/mut_exclusive_violation2.rs:LL:CC + --> tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC | LL | *raw2 = 2; | ^^^^^^^^^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr index 9f545e5687e7f..f428447230a85 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr @@ -7,12 +7,12 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | let ptr = Box::into_raw(Box::new(0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: is this argument - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ @@ -20,17 +20,17 @@ LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside closure - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ -note: inside `dealloc_while_running::<{closure@$DIR/newtype_pair_retagging.rs:LL:CC}>` - --> $DIR/newtype_pair_retagging.rs:LL:CC +note: inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC}>` + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | dealloc(); | ^^^^^^^^^ note: inside `main` - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | / dealloc_while_running( LL | | Newtype(&mut *ptr, 0), diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr index 0a54f14bb5e19..ef1aa74ddf4ba 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr @@ -1,47 +1,45 @@ error: Undefined Behavior: deallocation through at ALLOC[0x0] is forbidden - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> RUSTLIB/alloc/src/boxed.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocation through at ALLOC[0x0] is forbidden +LL | self.1.deallocate(From::from(ptr.cast()), layout); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocation through at ALLOC[0x0] is forbidden | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag is foreign to the protected tag (i.e., it is not a child) = help: this deallocation (acting as a foreign write access) would cause the protected tag (currently Reserved (conflicted)) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^^^^^^^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ help: the protected tag later transitioned to Reserved (conflicted) due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4] - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit = note: BACKTRACE (of the first span): - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `dealloc_while_running::<{closure@$DIR/newtype_pair_retagging.rs:LL:CC}>` - --> $DIR/newtype_pair_retagging.rs:LL:CC +note: inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC}>` + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | dealloc(); | ^^^^^^^^^ note: inside `main` - --> $DIR/newtype_pair_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | / dealloc_while_running( LL | | Newtype(&mut *ptr, 0), diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr index a4111f6f5cc2f..0410c2488db02 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr @@ -7,12 +7,12 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | let ptr = Box::into_raw(Box::new(0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: is this argument - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ @@ -20,17 +20,17 @@ LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside closure - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ -note: inside `dealloc_while_running::<{closure@$DIR/newtype_retagging.rs:LL:CC}>` - --> $DIR/newtype_retagging.rs:LL:CC +note: inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_retagging.rs:LL:CC}>` + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | dealloc(); | ^^^^^^^^^ note: inside `main` - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | / dealloc_while_running( LL | | Newtype(&mut *ptr), diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr index 05f1d8822c81f..28fcd1411f962 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr @@ -1,47 +1,45 @@ error: Undefined Behavior: deallocation through at ALLOC[0x0] is forbidden - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> RUSTLIB/alloc/src/boxed.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocation through at ALLOC[0x0] is forbidden +LL | self.1.deallocate(From::from(ptr.cast()), layout); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocation through at ALLOC[0x0] is forbidden | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag is foreign to the protected tag (i.e., it is not a child) = help: this deallocation (acting as a foreign write access) would cause the protected tag (currently Reserved (conflicted)) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^^^^^^^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ help: the protected tag later transitioned to Reserved (conflicted) due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4] - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit = note: BACKTRACE (of the first span): - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `dealloc_while_running::<{closure@$DIR/newtype_retagging.rs:LL:CC}>` - --> $DIR/newtype_retagging.rs:LL:CC +note: inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_retagging.rs:LL:CC}>` + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | dealloc(); | ^^^^^^^^^ note: inside `main` - --> $DIR/newtype_retagging.rs:LL:CC + --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | / dealloc_while_running( LL | | Newtype(&mut *ptr), diff --git a/src/tools/miri/tests/fail/both_borrows/outdated_local.stack.stderr b/src/tools/miri/tests/fail/both_borrows/outdated_local.stack.stderr index 9717dd16b5b14..79d3538e920ba 100644 --- a/src/tools/miri/tests/fail/both_borrows/outdated_local.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/outdated_local.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/outdated_local.rs:LL:CC + --> tests/fail/both_borrows/outdated_local.rs:LL:CC | LL | assert_eq!(unsafe { *y }, 1); | ^^ @@ -10,17 +10,17 @@ LL | assert_eq!(unsafe { *y }, 1); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/outdated_local.rs:LL:CC + --> tests/fail/both_borrows/outdated_local.rs:LL:CC | LL | let y: *const i32 = &x; | ^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/outdated_local.rs:LL:CC + --> tests/fail/both_borrows/outdated_local.rs:LL:CC | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/outdated_local.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/outdated_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/outdated_local.tree.stderr b/src/tools/miri/tests/fail/both_borrows/outdated_local.tree.stderr index 60de8417c1026..fffa83a9628bd 100644 --- a/src/tools/miri/tests/fail/both_borrows/outdated_local.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/outdated_local.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden - --> $DIR/outdated_local.rs:LL:CC + --> tests/fail/both_borrows/outdated_local.rs:LL:CC | LL | assert_eq!(unsafe { *y }, 1); | ^^ read access through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | assert_eq!(unsafe { *y }, 1); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child read access help: the accessed tag was created here, in the initial state Frozen - --> $DIR/outdated_local.rs:LL:CC + --> tests/fail/both_borrows/outdated_local.rs:LL:CC | LL | let y: *const i32 = &x; | ^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/outdated_local.rs:LL:CC + --> tests/fail/both_borrows/outdated_local.rs:LL:CC | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local | ^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/outdated_local.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/outdated_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.stack.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.stack.stderr index 57c4a756cf725..108c78abef506 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/pass_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC | LL | foo(xref); | ^^^^ @@ -10,17 +10,17 @@ LL | foo(xref); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/pass_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC | LL | let xref = unsafe { &*xraw }; | ^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/pass_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/pass_invalid_shr.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.tree.stderr index 97a6efa9f6a6c..59750d5647090 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x0] is forbidden - --> $DIR/pass_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC | LL | foo(xref); | ^^^^ reborrow through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | foo(xref); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Frozen - --> $DIR/pass_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC | LL | let xref = unsafe { &*xraw }; | ^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/pass_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/pass_invalid_shr.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.stack.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.stack.stderr index dfc99ff7cd233..5aca026cb7632 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/pass_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC | LL | foo(some_xref); | ^^^^^^^^^ @@ -11,17 +11,17 @@ LL | foo(some_xref); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/pass_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC | LL | let some_xref = unsafe { Some(&*xraw) }; | ^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/pass_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/pass_invalid_shr_option.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.tree.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.tree.stderr index f687b3f867fc3..de63c9609a6e6 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x0] is forbidden - --> $DIR/pass_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC | LL | foo(some_xref); | ^^^^^^^^^ reborrow through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | foo(some_xref); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Frozen - --> $DIR/pass_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC | LL | let some_xref = unsafe { Some(&*xraw) }; | ^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/pass_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/pass_invalid_shr_option.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.stack.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.stack.stderr index e4ebe22b60e2b..16c2af081ad7d 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/pass_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC | LL | foo(pair_xref); | ^^^^^^^^^ @@ -11,17 +11,17 @@ LL | foo(pair_xref); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/pass_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC | LL | let pair_xref = unsafe { (&*xraw0, &*xraw1) }; | ^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/pass_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC | LL | unsafe { *xraw0 = 42 }; // unfreeze | ^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/pass_invalid_shr_tuple.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.tree.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.tree.stderr index 845838f93d57d..d2a727a920d60 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x0] is forbidden - --> $DIR/pass_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC | LL | foo(pair_xref); | ^^^^^^^^^ reborrow through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | foo(pair_xref); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Frozen - --> $DIR/pass_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC | LL | let pair_xref = unsafe { (&*xraw0, &*xraw1) }; | ^^^^^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/pass_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC | LL | unsafe { *xraw0 = 42 }; // unfreeze | ^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/pass_invalid_shr_tuple.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr index 6f4b52fb88718..6bc66f2419272 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Data race detected between (1) retag write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/retag_data_race_write.rs:LL:CC + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | *p = 5; | ^^^^^^ Data race detected between (1) retag write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/retag_data_race_write.rs:LL:CC + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | let _r = &mut *p; | ^^^^^^^ @@ -15,9 +15,9 @@ LL | let _r = &mut *p; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `thread_2` at $DIR/retag_data_race_write.rs:LL:CC + = note: inside `thread_2` at tests/fail/both_borrows/retag_data_race_write.rs:LL:CC note: inside closure - --> $DIR/retag_data_race_write.rs:LL:CC + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); | ^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr index fa0012f9b26cf..510e592539fe8 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/retag_data_race_write.rs:LL:CC + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | *p = 5; | ^^^^^^ Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/retag_data_race_write.rs:LL:CC + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | let _r = &mut *p; | ^^^^^^^ @@ -15,9 +15,9 @@ LL | let _r = &mut *p; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `thread_2` at $DIR/retag_data_race_write.rs:LL:CC + = note: inside `thread_2` at tests/fail/both_borrows/retag_data_race_write.rs:LL:CC note: inside closure - --> $DIR/retag_data_race_write.rs:LL:CC + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); | ^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr index 858afa6fb3c60..0ac3ed9db356f 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - --> $DIR/return_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | ret | ^^^ @@ -10,19 +10,19 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x4..0x8] - --> $DIR/return_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | let ret = unsafe { &(*xraw).1 }; | ^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x8] by a write access - --> $DIR/return_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC + = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | foo(&mut (1, 2)); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr index 0d19681f637da..cc51f4c77ee1b 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x4] is forbidden - --> $DIR/return_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | ret | ^^^ reborrow through at ALLOC[0x4] is forbidden @@ -7,20 +7,20 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Frozen - --> $DIR/return_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | let ret = unsafe { &(*xraw).1 }; | ^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8] - --> $DIR/return_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC + = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_shr.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | foo(&mut (1, 2)); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr index ab67bb516ffe3..d8e0f52ff02df 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - --> $DIR/return_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | ret | ^^^ @@ -11,19 +11,19 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x4..0x8] - --> $DIR/return_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | let ret = Some(unsafe { &(*xraw).1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x8] by a write access - --> $DIR/return_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_shr_option.rs:LL:CC + = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | match foo(&mut (1, 2)) { | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr index e770372925130..7a7d8f20fa889 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x4] is forbidden - --> $DIR/return_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | ret | ^^^ reborrow through at ALLOC[0x4] is forbidden @@ -7,20 +7,20 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Frozen - --> $DIR/return_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | let ret = Some(unsafe { &(*xraw).1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8] - --> $DIR/return_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_shr_option.rs:LL:CC + = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_shr_option.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | match foo(&mut (1, 2)) { | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr index 22a55f0d37cd6..38b8758964b1c 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - --> $DIR/return_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | ret | ^^^ @@ -11,19 +11,19 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x4..0x8] - --> $DIR/return_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | let ret = (unsafe { &(*xraw).1 },); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x8] by a write access - --> $DIR/return_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_shr_tuple.rs:LL:CC + = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr index a5c6be3f13aa8..57b4f5fbe2d1b 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x4] is forbidden - --> $DIR/return_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | ret | ^^^ reborrow through at ALLOC[0x4] is forbidden @@ -7,20 +7,20 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Frozen - --> $DIR/return_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | let ret = (unsafe { &(*xraw).1 },); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8] - --> $DIR/return_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_shr_tuple.rs:LL:CC + = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_shr_tuple.rs:LL:CC + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr index 52ac2184d4948..22efda1efae6c 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - --> $DIR/shr_frozen_violation1.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -10,19 +10,19 @@ LL | *(x as *const i32 as *mut i32) = 7; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/shr_frozen_violation1.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; | ^ = note: BACKTRACE (of the first span): - = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC + = note: inside `unknown_code` at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC note: inside `foo` - --> $DIR/shr_frozen_violation1.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | unknown_code(&*x); | ^^^^^^^^^^^^^^^^^ note: inside `main` - --> $DIR/shr_frozen_violation1.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | println!("{}", foo(&mut 0)); | ^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr index 45b3bceb7287e..2e544583cb210 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/shr_frozen_violation1.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,19 +7,19 @@ LL | *(x as *const i32 as *mut i32) = 7; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Frozen which forbids this child write access help: the accessed tag was created here, in the initial state Frozen - --> $DIR/shr_frozen_violation1.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | fn unknown_code(x: &i32) { | ^ = note: BACKTRACE (of the first span): - = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC + = note: inside `unknown_code` at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC note: inside `foo` - --> $DIR/shr_frozen_violation1.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | unknown_code(&*x); | ^^^^^^^^^^^^^^^^^ note: inside `main` - --> $DIR/shr_frozen_violation1.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | println!("{}", foo(&mut 0)); | ^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.stack.stderr index e05ffb3d35e18..7e6d057a4b6b7 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/shr_frozen_violation2.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC | LL | let _val = *frozen; | ^^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *frozen; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/shr_frozen_violation2.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC | LL | let frozen = &*ptr; | ^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/shr_frozen_violation2.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC | LL | x = 1; | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/shr_frozen_violation2.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.tree.stderr index 96c2e39edd20a..17c4542e19510 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden - --> $DIR/shr_frozen_violation2.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC | LL | let _val = *frozen; | ^^^^^^^ read access through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | let _val = *frozen; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child read access help: the accessed tag was created here, in the initial state Frozen - --> $DIR/shr_frozen_violation2.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC | LL | let frozen = &*ptr; | ^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] - --> $DIR/shr_frozen_violation2.rs:LL:CC + --> tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC | LL | x = 1; | ^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/shr_frozen_violation2.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs index aed5cb1125817..df9a73a444eda 100644 --- a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs +++ b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs @@ -1,13 +1,12 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -//@[tree]error-in-other-file: /deallocation .* is forbidden/ -use std::alloc::{alloc, dealloc, Layout}; +use std::alloc::{Layout, alloc, dealloc}; // `x` is strongly protected but covers zero bytes. // Let's see if deallocating the allocation x points to is UB: // in TB, it is UB, but in SB it is not. fn test(_x: &mut (), ptr: *mut u8, l: Layout) { - unsafe { dealloc(ptr, l) }; + unsafe { dealloc(ptr, l) }; //~[tree] ERROR: /deallocation .* is forbidden/ } fn main() { diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr index 672682ff29401..c01fa2a86c218 100644 --- a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/zero-sized-protected.rs:LL:CC + --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC | LL | unsafe { std::hint::unreachable_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code @@ -7,7 +7,7 @@ LL | unsafe { std::hint::unreachable_unchecked() }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/zero-sized-protected.rs:LL:CC + = note: inside `main` at tests/fail/both_borrows/zero-sized-protected.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr index ef981038e5540..18d1fb6939540 100644 --- a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr @@ -1,31 +1,26 @@ error: Undefined Behavior: deallocation through (root of the allocation) at ALLOC[0x0] is forbidden - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocation through (root of the allocation) at ALLOC[0x0] is forbidden +LL | unsafe { dealloc(ptr, l) }; + | ^^^^^^^^^^^^^^^ deallocation through (root of the allocation) at ALLOC[0x0] is forbidden | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the allocation of the accessed tag (root of the allocation) also contains the strongly protected tag = help: the strongly protected tag disallows deallocations help: the accessed tag was created here - --> $DIR/zero-sized-protected.rs:LL:CC + --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC | LL | let ptr = unsafe { alloc(l) }; | ^^^^^^^^ help: the strongly protected tag was created here, in the initial state Reserved - --> $DIR/zero-sized-protected.rs:LL:CC + --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC | LL | fn test(_x: &mut (), ptr: *mut u8, l: Layout) { | ^^ = note: BACKTRACE (of the first span): - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `test` - --> $DIR/zero-sized-protected.rs:LL:CC - | -LL | unsafe { dealloc(ptr, l) }; - | ^^^^^^^^^^^^^^^ + = note: inside `test` at tests/fail/both_borrows/zero-sized-protected.rs:LL:CC note: inside `main` - --> $DIR/zero-sized-protected.rs:LL:CC + --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC | LL | unsafe { test(&mut *ptr.cast::<()>(), ptr, l) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/box-cell-alias.stderr b/src/tools/miri/tests/fail/box-cell-alias.stderr index 697cee52d137e..f9cc6003dc688 100644 --- a/src/tools/miri/tests/fail/box-cell-alias.stderr +++ b/src/tools/miri/tests/fail/box-cell-alias.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/box-cell-alias.rs:LL:CC + --> tests/fail/box-cell-alias.rs:LL:CC | LL | unsafe { (*ptr).set(20) }; | ^^^^^^ @@ -10,19 +10,19 @@ LL | unsafe { (*ptr).set(20) }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x1] - --> $DIR/box-cell-alias.rs:LL:CC + --> tests/fail/box-cell-alias.rs:LL:CC | LL | let ptr: *const Cell = &*val; | ^^^^^ help: was later invalidated at offsets [0x0..0x1] by a Unique retag - --> $DIR/box-cell-alias.rs:LL:CC + --> tests/fail/box-cell-alias.rs:LL:CC | LL | let res = helper(val, ptr); | ^^^ = note: BACKTRACE (of the first span): - = note: inside `helper` at $DIR/box-cell-alias.rs:LL:CC + = note: inside `helper` at tests/fail/box-cell-alias.rs:LL:CC note: inside `main` - --> $DIR/box-cell-alias.rs:LL:CC + --> tests/fail/box-cell-alias.rs:LL:CC | LL | let res = helper(val, ptr); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/branchless-select-i128-pointer.stderr b/src/tools/miri/tests/fail/branchless-select-i128-pointer.stderr index 655e682636ead..d9de23dc91221 100644 --- a/src/tools/miri/tests/fail/branchless-select-i128-pointer.stderr +++ b/src/tools/miri/tests/fail/branchless-select-i128-pointer.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) - --> $DIR/branchless-select-i128-pointer.rs:LL:CC + --> tests/fail/branchless-select-i128-pointer.rs:LL:CC | LL | / transmute::<_, &str>( LL | | @@ -11,7 +11,7 @@ LL | | ) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/branchless-select-i128-pointer.rs:LL:CC + = note: inside `main` at tests/fail/branchless-select-i128-pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/breakpoint.stderr b/src/tools/miri/tests/fail/breakpoint.stderr index a5666d52a2f2b..ca98e81f1f4ed 100644 --- a/src/tools/miri/tests/fail/breakpoint.stderr +++ b/src/tools/miri/tests/fail/breakpoint.stderr @@ -1,11 +1,11 @@ error: abnormal termination: trace/breakpoint trap - --> $DIR/breakpoint.rs:LL:CC + --> tests/fail/breakpoint.rs:LL:CC | LL | core::intrinsics::breakpoint() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trace/breakpoint trap | = note: BACKTRACE: - = note: inside `main` at $DIR/breakpoint.rs:LL:CC + = note: inside `main` at tests/fail/breakpoint.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr b/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr index f3e1796f3c9af..62ade0a6793b0 100644 --- a/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr +++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr @@ -1,6 +1,6 @@ error: Undefined Behavior: atomic store and read-modify-write operations cannot be performed on read-only memory see for more information - --> $DIR/read_only_atomic_cmpxchg.rs:LL:CC + --> tests/fail/concurrency/read_only_atomic_cmpxchg.rs:LL:CC | LL | x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ atomic store and read-modify-write operations cannot be performed on read-only memory @@ -9,7 +9,7 @@ see for more information - --> $DIR/read_only_atomic_load_acquire.rs:LL:CC + --> tests/fail/concurrency/read_only_atomic_load_acquire.rs:LL:CC | LL | x.load(Ordering::Acquire); | ^^^^^^^^^^^^^^^^^^^^^^^^^ non-relaxed atomic load operations cannot be performed on read-only memory @@ -11,7 +11,7 @@ see for more information - --> $DIR/read_only_atomic_load_large.rs:LL:CC + --> tests/fail/concurrency/read_only_atomic_load_large.rs:LL:CC | LL | x.load(Ordering::Relaxed); | ^^^^^^^^^^^^^^^^^^^^^^^^^ large atomic load operations cannot be performed on read-only memory @@ -11,7 +11,7 @@ see $DIR/const-ub-checks.rs:LL:CC + --> tests/fail/const-ub-checks.rs:LL:CC | LL | ptr.read(); | ^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required note: erroneous constant encountered - --> $DIR/const-ub-checks.rs:LL:CC + --> tests/fail/const-ub-checks.rs:LL:CC | LL | let _x = UNALIGNED_READ; | ^^^^^^^^^^^^^^ note: erroneous constant encountered - --> $DIR/const-ub-checks.rs:LL:CC + --> tests/fail/const-ub-checks.rs:LL:CC | LL | let _x = UNALIGNED_READ; | ^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr index b5b0cbb04e017..c2c6ce987e555 100644 --- a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr +++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/coroutine-pinned-moved.rs:LL:CC + --> tests/fail/coroutine-pinned-moved.rs:LL:CC | LL | *num += 1; | ^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,25 +7,25 @@ LL | *num += 1; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/coroutine-pinned-moved.rs:LL:CC + --> tests/fail/coroutine-pinned-moved.rs:LL:CC | LL | let mut coroutine_iterator = Box::new(CoroutineIteratorAdapter(firstn())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/coroutine-pinned-moved.rs:LL:CC + --> tests/fail/coroutine-pinned-moved.rs:LL:CC | LL | }; // *deallocate* coroutine_iterator | ^ = note: BACKTRACE (of the first span): - = note: inside closure at $DIR/coroutine-pinned-moved.rs:LL:CC -note: inside ` as std::iter::Iterator>::next` - --> $DIR/coroutine-pinned-moved.rs:LL:CC + = note: inside closure at tests/fail/coroutine-pinned-moved.rs:LL:CC +note: inside ` as std::iter::Iterator>::next` + --> tests/fail/coroutine-pinned-moved.rs:LL:CC | LL | match me.resume(()) { | ^^^^^^^^^^^^^ - = note: inside `> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` - --> $DIR/coroutine-pinned-moved.rs:LL:CC + --> tests/fail/coroutine-pinned-moved.rs:LL:CC | LL | coroutine_iterator_2.next(); // and use moved value | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr index d7fa84e0ca1da..7613552b4b0e8 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/dangling_pointer_deref.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | let x = unsafe { *p }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dangling_pointer_deref.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_deref.rs:LL:CC | LL | let b = Box::new(42); | ^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/dangling_pointer_deref.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_deref.rs:LL:CC | LL | }; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/dangling_pointer_deref.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/dangling_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.stderr index 7d38a5649a5da..032cbccaf9bd0 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/dangling_pointer_deref_match_never.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs:LL:CC | LL | match *p {} | ^^ entering unreachable code @@ -7,7 +7,7 @@ LL | match *p {} = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dangling_pointer_deref_match_never.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr index b9fbadb1f898d..076d688046186 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling - --> $DIR/dangling_pointer_offset.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_offset.rs:LL:CC | LL | let x = unsafe { p.offset(42) }; | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | let x = unsafe { p.offset(42) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dangling_pointer_offset.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_offset.rs:LL:CC | LL | let b = Box::new(42); | ^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/dangling_pointer_offset.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_offset.rs:LL:CC | LL | }; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/dangling_pointer_offset.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/dangling_pointer_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr index 05e8c95166c85..ffb525e398142 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling - --> $DIR/dangling_pointer_project_underscore_let.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs:LL:CC | LL | let _ = (*p).1; | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | let _ = (*p).1; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dangling_pointer_project_underscore_let.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs:LL:CC | LL | let b = Box::new(42); | ^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/dangling_pointer_project_underscore_let.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs:LL:CC | LL | }; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/dangling_pointer_project_underscore_let.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr index 8f7ba156a937b..14dfa43b2d687 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling - --> $DIR/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC | LL | let _: u8 = (*p).1; | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | let _: u8 = (*p).1; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC | LL | let b = Box::new(42); | ^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC | LL | }; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr index c2b5d7b23cbc8..ff39e1475738f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling - --> $DIR/dangling_pointer_project_underscore_match.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs:LL:CC | LL | match (*p).1 { | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | match (*p).1 { = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dangling_pointer_project_underscore_match.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs:LL:CC | LL | let b = Box::new(42); | ^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/dangling_pointer_project_underscore_match.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs:LL:CC | LL | }; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/dangling_pointer_project_underscore_match.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr index a5c031b949643..99194d6e07256 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC | LL | unsafe { &(*x).0 as *const i32 } | ^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) @@ -7,9 +7,9 @@ LL | unsafe { &(*x).0 as *const i32 } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `via_ref` at $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC + = note: inside `via_ref` at tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC note: inside `main` - --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC | LL | via_ref(ptr); // this is not | ^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr index ee02c1040c704..2d7456c15b96b 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/dangling_primitive.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_primitive.rs:LL:CC | LL | dbg!(*ptr); | ^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,12 +7,12 @@ LL | dbg!(*ptr); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dangling_primitive.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_primitive.rs:LL:CC | LL | let x = 0usize; // This line should appear in the helps | ^ help: ALLOC was deallocated here: - --> $DIR/dangling_primitive.rs:LL:CC + --> tests/fail/dangling_pointers/dangling_primitive.rs:LL:CC | LL | }; | ^ diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index d989bff4516f2..09a201983b1f3 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/deref-invalid-ptr.rs:LL:CC + --> tests/fail/dangling_pointers/deref-invalid-ptr.rs:LL:CC | LL | let _y = unsafe { &*x as *const u32 }; | ^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let _y = unsafe { &*x as *const u32 }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/deref-invalid-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr index eb4482f5caea8..82802f02b992b 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling box (0x18[noalloc] has no provenance) - --> $DIR/deref_dangling_box.rs:LL:CC + --> tests/fail/dangling_pointers/deref_dangling_box.rs:LL:CC | LL | let _val = unsafe { addr_of_mut!(**outer) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x18[noalloc] has no provenance) diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr index c0d989dc1a0cd..364d193b0c5f1 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling reference (0x18[noalloc] has no provenance) - --> $DIR/deref_dangling_ref.rs:LL:CC + --> tests/fail/dangling_pointers/deref_dangling_ref.rs:LL:CC | LL | let _val = unsafe { addr_of_mut!(**outer) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x18[noalloc] has no provenance) diff --git a/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr b/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr index 7d43857b9bfb4..f3596347f61b8 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) - --> $DIR/dyn_size.rs:LL:CC + --> tests/fail/dangling_pointers/dyn_size.rs:LL:CC | LL | let _ptr = unsafe { &*ptr }; | ^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -7,7 +7,7 @@ LL | let _ptr = unsafe { &*ptr }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dyn_size.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/dyn_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr index 1b97265eb32f6..d87a8bc59e951 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer - --> $DIR/null_pointer_deref.rs:LL:CC + --> tests/fail/dangling_pointers/null_pointer_deref.rs:LL:CC | LL | let x: i32 = unsafe { *std::ptr::null() }; | ^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer @@ -7,7 +7,7 @@ LL | let x: i32 = unsafe { *std::ptr::null() }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/null_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr index 3d75e7a0254b6..39d861a63882b 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer - --> $DIR/null_pointer_write.rs:LL:CC + --> tests/fail/dangling_pointers/null_pointer_write.rs:LL:CC | LL | unsafe { *std::ptr::null_mut() = 0i32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer @@ -7,7 +7,7 @@ LL | unsafe { *std::ptr::null_mut() = 0i32 }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/null_pointer_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr index 4bfac8f96578d..27a437c7483d0 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation - --> $DIR/out_of_bounds_project.rs:LL:CC + --> tests/fail/dangling_pointers/out_of_bounds_project.rs:LL:CC | LL | let _field = addr_of!((*ptr).2); | ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation @@ -7,7 +7,7 @@ LL | let _field = addr_of!((*ptr).2); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/out_of_bounds_project.rs:LL:CC + --> tests/fail/dangling_pointers/out_of_bounds_project.rs:LL:CC | LL | let v = 0u32; | ^ diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr index 8a774c21bb7c1..813bcef54f12c 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes - --> $DIR/out_of_bounds_read.rs:LL:CC + --> tests/fail/dangling_pointers/out_of_bounds_read.rs:LL:CC | LL | let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes @@ -7,12 +7,12 @@ LL | let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/out_of_bounds_read.rs:LL:CC + --> tests/fail/dangling_pointers/out_of_bounds_read.rs:LL:CC | LL | let v: Vec = vec![1, 2]; | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/out_of_bounds_read.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/out_of_bounds_read.rs:LL:CC = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr index 6ae9f05d17381..1056a739a436f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes - --> $DIR/out_of_bounds_write.rs:LL:CC + --> tests/fail/dangling_pointers/out_of_bounds_write.rs:LL:CC | LL | unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes @@ -7,12 +7,12 @@ LL | unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/out_of_bounds_write.rs:LL:CC + --> tests/fail/dangling_pointers/out_of_bounds_write.rs:LL:CC | LL | let mut v: Vec = vec![1, 2]; | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/out_of_bounds_write.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/out_of_bounds_write.rs:LL:CC = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr index d5c53e4ad6476..c617dfdb3a632 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/stack_temporary.rs:LL:CC + --> tests/fail/dangling_pointers/stack_temporary.rs:LL:CC | LL | let val = *x; | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | let val = *x; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/stack_temporary.rs:LL:CC + --> tests/fail/dangling_pointers/stack_temporary.rs:LL:CC | LL | let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"! | ^ help: ALLOC was deallocated here: - --> $DIR/stack_temporary.rs:LL:CC + --> tests/fail/dangling_pointers/stack_temporary.rs:LL:CC | LL | let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"! | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/stack_temporary.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/stack_temporary.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 2d4fbafd8b7f6..9061121494d0e 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/storage_dead_dangling.rs:LL:CC + --> tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC | LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) @@ -7,9 +7,9 @@ LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC + = note: inside `evil` at tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC note: inside `main` - --> $DIR/storage_dead_dangling.rs:LL:CC + --> tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC | LL | evil(); | ^^^^^^ diff --git a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 1d8eed3d30a7c..3e7aac4724dcc 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/wild_pointer_deref.rs:LL:CC + --> tests/fail/dangling_pointers/wild_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; | ^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let x = unsafe { *p }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC + = note: inside `main` at tests/fail/dangling_pointers/wild_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr index 59ed5fe9cf2c4..e6ee9ce81fd98 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) creating a new allocation on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/alloc_read_race.rs:LL:CC + --> tests/fail/data_race/alloc_read_race.rs:LL:CC | LL | *pointer.load(Ordering::Relaxed) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) creating a new allocation on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/alloc_read_race.rs:LL:CC + --> tests/fail/data_race/alloc_read_race.rs:LL:CC | LL | pointer.store(Box::into_raw(Box::new_uninit()), Ordering::Relaxed); | ^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/alloc_read_race.rs:LL:CC + = note: inside closure at tests/fail/data_race/alloc_read_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr index 9770684fc52d2..97b54609aded8 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) creating a new allocation on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/alloc_write_race.rs:LL:CC + --> tests/fail/data_race/alloc_write_race.rs:LL:CC | LL | *pointer.load(Ordering::Relaxed) = 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) creating a new allocation on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/alloc_write_race.rs:LL:CC + --> tests/fail/data_race/alloc_write_race.rs:LL:CC | LL | .store(Box::into_raw(Box::::new_uninit()) as *mut usize, Ordering::Relaxed); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/alloc_write_race.rs:LL:CC + = note: inside closure at tests/fail/data_race/alloc_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr index a1132ed20679c..d3d6ed2e31139 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/atomic_read_na_write_race1.rs:LL:CC + --> tests/fail/data_race/atomic_read_na_write_race1.rs:LL:CC | LL | (&*c.0).load(Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/atomic_read_na_write_race1.rs:LL:CC + --> tests/fail/data_race/atomic_read_na_write_race1.rs:LL:CC | LL | *(c.0 as *mut usize) = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/atomic_read_na_write_race1.rs:LL:CC + = note: inside closure at tests/fail/data_race/atomic_read_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr index 865357cb0ef4b..ea535ddac4fff 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/atomic_read_na_write_race2.rs:LL:CC + --> tests/fail/data_race/atomic_read_na_write_race2.rs:LL:CC | LL | *atomic_ref.get_mut() = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/atomic_read_na_write_race2.rs:LL:CC + --> tests/fail/data_race/atomic_read_na_write_race2.rs:LL:CC | LL | atomic_ref.load(Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/atomic_read_na_write_race2.rs:LL:CC + = note: inside closure at tests/fail/data_race/atomic_read_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr index 355ea48f11716..fe65eca4bc69e 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) atomic store on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/atomic_write_na_read_race1.rs:LL:CC + --> tests/fail/data_race/atomic_write_na_read_race1.rs:LL:CC | LL | *atomic_ref.get_mut() | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) atomic store on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/atomic_write_na_read_race1.rs:LL:CC + --> tests/fail/data_race/atomic_write_na_read_race1.rs:LL:CC | LL | atomic_ref.store(32, Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/atomic_write_na_read_race1.rs:LL:CC + = note: inside closure at tests/fail/data_race/atomic_write_na_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr index 500cd09a33307..4393cc3c09301 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/atomic_write_na_read_race2.rs:LL:CC + --> tests/fail/data_race/atomic_write_na_read_race2.rs:LL:CC | LL | (&*c.0).store(32, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/atomic_write_na_read_race2.rs:LL:CC + --> tests/fail/data_race/atomic_write_na_read_race2.rs:LL:CC | LL | let _val = *(c.0 as *mut usize); | ^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/atomic_write_na_read_race2.rs:LL:CC + = note: inside closure at tests/fail/data_race/atomic_write_na_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr index 0b870f13bb2b9..5a7f90447f0e3 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/atomic_write_na_write_race1.rs:LL:CC + --> tests/fail/data_race/atomic_write_na_write_race1.rs:LL:CC | LL | (&*c.0).store(64, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/atomic_write_na_write_race1.rs:LL:CC + --> tests/fail/data_race/atomic_write_na_write_race1.rs:LL:CC | LL | *(c.0 as *mut usize) = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/atomic_write_na_write_race1.rs:LL:CC + = note: inside closure at tests/fail/data_race/atomic_write_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr index dbbf6bf1ef573..9ee4f16d0d5c4 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) atomic store on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/atomic_write_na_write_race2.rs:LL:CC + --> tests/fail/data_race/atomic_write_na_write_race2.rs:LL:CC | LL | *atomic_ref.get_mut() = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) atomic store on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/atomic_write_na_write_race2.rs:LL:CC + --> tests/fail/data_race/atomic_write_na_write_race2.rs:LL:CC | LL | atomic_ref.store(64, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/atomic_write_na_write_race2.rs:LL:CC + = note: inside closure at tests/fail/data_race/atomic_write_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr index 1b02880b99861..1051a1c51f21a 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/dangling_thread_async_race.rs:LL:CC + --> tests/fail/data_race/dangling_thread_async_race.rs:LL:CC | LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/dangling_thread_async_race.rs:LL:CC + --> tests/fail/data_race/dangling_thread_async_race.rs:LL:CC | LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/dangling_thread_async_race.rs:LL:CC + = note: inside closure at tests/fail/data_race/dangling_thread_async_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr b/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr index 7f6ba5ee04088..23a99ff6c8ac5 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `main` at ALLOC. (2) just happened here - --> $DIR/dangling_thread_race.rs:LL:CC + --> tests/fail/data_race/dangling_thread_race.rs:LL:CC | LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `main` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/dangling_thread_race.rs:LL:CC + --> tests/fail/data_race/dangling_thread_race.rs:LL:CC | LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/dangling_thread_race.rs:LL:CC + = note: inside `main` at tests/fail/data_race/dangling_thread_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr index a4a22a8d71e94..8eb4ebbcf729d 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/dealloc_read_race1.rs:LL:CC + --> tests/fail/data_race/dealloc_read_race1.rs:LL:CC | LL | / __rust_dealloc( LL | | @@ -10,14 +10,14 @@ LL | | ); | |_____________^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/dealloc_read_race1.rs:LL:CC + --> tests/fail/data_race/dealloc_read_race1.rs:LL:CC | LL | let _val = *ptr.0; | ^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/dealloc_read_race1.rs:LL:CC + = note: inside closure at tests/fail/data_race/dealloc_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr index dbf9acd23b6e0..1a2b048572a5c 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/dealloc_read_race2.rs:LL:CC + --> tests/fail/data_race/dealloc_read_race2.rs:LL:CC | LL | *ptr.0 | ^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,12 +7,12 @@ LL | *ptr.0 = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dealloc_read_race2.rs:LL:CC + --> tests/fail/data_race/dealloc_read_race2.rs:LL:CC | LL | let pointer: *mut usize = Box::into_raw(Box::new(0usize)); | ^^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/dealloc_read_race2.rs:LL:CC + --> tests/fail/data_race/dealloc_read_race2.rs:LL:CC | LL | / __rust_dealloc( LL | | ptr.0 as *mut _, @@ -21,7 +21,7 @@ LL | | std::mem::align_of::(), LL | | ) | |_____________^ = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/dealloc_read_race2.rs:LL:CC + = note: inside closure at tests/fail/data_race/dealloc_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr index e36376d0c75b2..ce9719b1d4632 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/dealloc_read_race_stack.rs:LL:CC + --> tests/fail/data_race/dealloc_read_race_stack.rs:LL:CC | LL | } | ^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/dealloc_read_race_stack.rs:LL:CC + --> tests/fail/data_race/dealloc_read_race_stack.rs:LL:CC | LL | *pointer.load(Ordering::Acquire) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/dealloc_read_race_stack.rs:LL:CC + = note: inside closure at tests/fail/data_race/dealloc_read_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr index 0c6cd9bbd932e..48d974241aada 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) deallocation on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/dealloc_write_race1.rs:LL:CC + --> tests/fail/data_race/dealloc_write_race1.rs:LL:CC | LL | / __rust_dealloc( LL | | @@ -10,14 +10,14 @@ LL | | ); | |_____________^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) deallocation on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/dealloc_write_race1.rs:LL:CC + --> tests/fail/data_race/dealloc_write_race1.rs:LL:CC | LL | *ptr.0 = 2; | ^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/dealloc_write_race1.rs:LL:CC + = note: inside closure at tests/fail/data_race/dealloc_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr index 3009373531356..077d458826623 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/dealloc_write_race2.rs:LL:CC + --> tests/fail/data_race/dealloc_write_race2.rs:LL:CC | LL | *ptr.0 = 2; | ^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,12 +7,12 @@ LL | *ptr.0 = 2; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dealloc_write_race2.rs:LL:CC + --> tests/fail/data_race/dealloc_write_race2.rs:LL:CC | LL | let pointer: *mut usize = Box::into_raw(Box::new(0usize)); | ^^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/dealloc_write_race2.rs:LL:CC + --> tests/fail/data_race/dealloc_write_race2.rs:LL:CC | LL | / __rust_dealloc( LL | | ptr.0 as *mut _, @@ -21,7 +21,7 @@ LL | | std::mem::align_of::(), LL | | ); | |_____________^ = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/dealloc_write_race2.rs:LL:CC + = note: inside closure at tests/fail/data_race/dealloc_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr index 4c16162fa1f16..2b531b6440c43 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) deallocation on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/dealloc_write_race_stack.rs:LL:CC + --> tests/fail/data_race/dealloc_write_race_stack.rs:LL:CC | LL | } | ^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) deallocation on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/dealloc_write_race_stack.rs:LL:CC + --> tests/fail/data_race/dealloc_write_race_stack.rs:LL:CC | LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/dealloc_write_race_stack.rs:LL:CC + = note: inside closure at tests/fail/data_race/dealloc_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr index 686d9b48e5312..5d5d1c8cc6861 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/enable_after_join_to_main.rs:LL:CC + --> tests/fail/data_race/enable_after_join_to_main.rs:LL:CC | LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/enable_after_join_to_main.rs:LL:CC + --> tests/fail/data_race/enable_after_join_to_main.rs:LL:CC | LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/enable_after_join_to_main.rs:LL:CC + = note: inside closure at tests/fail/data_race/enable_after_join_to_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.rs b/src/tools/miri/tests/fail/data_race/fence_after_load.rs index 92cb4ccccf530..5dfb260c20bdc 100644 --- a/src/tools/miri/tests/fail/data_race/fence_after_load.rs +++ b/src/tools/miri/tests/fail/data_race/fence_after_load.rs @@ -3,8 +3,8 @@ // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 -use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering, fence}; use std::thread; use std::time::Duration; diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.stderr b/src/tools/miri/tests/fail/data_race/fence_after_load.stderr index 776cf7c17b95a..03b3c6f8f0b02 100644 --- a/src/tools/miri/tests/fail/data_race/fence_after_load.stderr +++ b/src/tools/miri/tests/fail/data_race/fence_after_load.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `main` at ALLOC. (2) just happened here - --> $DIR/fence_after_load.rs:LL:CC + --> tests/fail/data_race/fence_after_load.rs:LL:CC | LL | unsafe { V = 2 } | ^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `main` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/fence_after_load.rs:LL:CC + --> tests/fail/data_race/fence_after_load.rs:LL:CC | LL | unsafe { V = 1 } | ^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/fence_after_load.rs:LL:CC + = note: inside `main` at tests/fail/data_race/fence_after_load.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs new file mode 100644 index 0000000000000..751a308a39998 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs @@ -0,0 +1,57 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +use std::intrinsics::mir::*; +use std::sync::atomic::Ordering::*; +use std::sync::atomic::*; +use std::thread::JoinHandle; + +static P: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); + +fn spawn_thread() -> JoinHandle<()> { + std::thread::spawn(|| { + while P.load(Relaxed).is_null() { + std::hint::spin_loop(); + } + unsafe { + // Initialize `*P`. + let ptr = P.load(Relaxed); + *ptr = 127; + //~^ ERROR: Data race detected between (1) creating a new allocation on thread `main` and (2) non-atomic write on thread `unnamed-1` + } + }) +} + +fn finish(t: JoinHandle<()>, val_ptr: *mut u8) { + P.store(val_ptr, Relaxed); + + // Wait for the thread to be done. + t.join().unwrap(); + + // Read initialized value. + assert_eq!(unsafe { *val_ptr }, 127); +} + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + mir! { + let t; + let val; + let val_ptr; + let _ret; + { + Call(t = spawn_thread(), ReturnTo(after_spawn), UnwindContinue()) + } + after_spawn = { + // This races with the write in the other thread. + StorageLive(val); + + val_ptr = &raw mut val; + Call(_ret = finish(t, val_ptr), ReturnTo(done), UnwindContinue()) + } + done = { + Return() + } + } +} diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr new file mode 100644 index 0000000000000..51a4c5cea30d5 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Data race detected between (1) creating a new allocation on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here + --> tests/fail/data_race/local_variable_alloc_race.rs:LL:CC + | +LL | *ptr = 127; + | ^^^^^^^^^^ Data race detected between (1) creating a new allocation on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail/data_race/local_variable_alloc_race.rs:LL:CC + | +LL | StorageLive(val); + | ^^^^^^^^^^^^^^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at tests/fail/data_race/local_variable_alloc_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs new file mode 100644 index 0000000000000..16a23f595ee47 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs @@ -0,0 +1,38 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +use std::sync::atomic::Ordering::*; +use std::sync::atomic::*; + +static P: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); + +fn main() { + // Create the local variable, and initialize it. + let mut val: u8 = 0; + + let t1 = std::thread::spawn(|| { + while P.load(Relaxed).is_null() { + std::hint::spin_loop(); + } + unsafe { + // Initialize `*P`. + let ptr = P.load(Relaxed); + *ptr = 127; + //~^ ERROR: Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-1` + } + }); + + // This read is not ordered with the store above, and thus should be reported as a race. + let _val = val; + + // Actually generate memory for the local variable. + // This is the time its value is actually written to memory. + // If we just "pre-date" the write to the beginning of time (since we don't know + // when it actually happened), we'd miss the UB in this test. + // Also, the UB error should point at the write above, not the addr-of here. + P.store(std::ptr::addr_of_mut!(val), Relaxed); + + // Wait for the thread to be done. + t1.join().unwrap(); + + // Read initialized value. + assert_eq!(val, 127); +} diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr new file mode 100644 index 0000000000000..3faffd4131e31 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here + --> tests/fail/data_race/local_variable_read_race.rs:LL:CC + | +LL | *ptr = 127; + | ^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail/data_race/local_variable_read_race.rs:LL:CC + | +LL | let _val = val; + | ^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at tests/fail/data_race/local_variable_read_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs new file mode 100644 index 0000000000000..7e00573146c25 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs @@ -0,0 +1,37 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +use std::sync::atomic::Ordering::*; +use std::sync::atomic::*; + +static P: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); + +fn main() { + let t1 = std::thread::spawn(|| { + while P.load(Relaxed).is_null() { + std::hint::spin_loop(); + } + unsafe { + // Initialize `*P`. + let ptr = P.load(Relaxed); + *ptr = 127; + //~^ ERROR: Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic write on thread `unnamed-1` + } + }); + + // Create the local variable, and initialize it. + // This is not ordered with the store above, so it's definitely UB + // for that thread to access this variable. + let mut val: u8 = 0; + + // Actually generate memory for the local variable. + // This is the time its value is actually written to memory. + // If we just "pre-date" the write to the beginning of time (since we don't know + // when it actually happened), we'd miss the UB in this test. + // Also, the UB error should point at the write above, not the addr-of here. + P.store(std::ptr::addr_of_mut!(val), Relaxed); + + // Wait for the thread to be done. + t1.join().unwrap(); + + // Read initialized value. + assert_eq!(val, 127); +} diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr new file mode 100644 index 0000000000000..24bbe227f9e83 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here + --> tests/fail/data_race/local_variable_write_race.rs:LL:CC + | +LL | *ptr = 127; + | ^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail/data_race/local_variable_write_race.rs:LL:CC + | +LL | let mut val: u8 = 0; + | ^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at tests/fail/data_race/local_variable_write_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs index 61af972b3dca8..828b47f0a6576 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs @@ -2,7 +2,7 @@ // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 -use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; +use std::sync::atomic::{AtomicU8, AtomicU16, Ordering}; use std::thread; fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr index 5b25c666f4199..31a798a89b133 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Race condition detected between (1) 2-byte atomic load on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/mixed_size_read.rs:LL:CC + --> tests/fail/data_race/mixed_size_read.rs:LL:CC | LL | a8[0].load(Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic load on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/mixed_size_read.rs:LL:CC + --> tests/fail/data_race/mixed_size_read.rs:LL:CC | LL | a16.load(Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | a16.load(Ordering::SeqCst); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/mixed_size_read.rs:LL:CC + = note: inside closure at tests/fail/data_race/mixed_size_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write.rs index 12e51bb94296a..89afda2fff5c2 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write.rs @@ -2,7 +2,7 @@ // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 -use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; +use std::sync::atomic::{AtomicU8, AtomicU16, Ordering}; use std::thread; fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr index c6157b87b387c..c30b48c1f32b0 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/mixed_size_write.rs:LL:CC + --> tests/fail/data_race/mixed_size_write.rs:LL:CC | LL | a8[0].store(1, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/mixed_size_write.rs:LL:CC + --> tests/fail/data_race/mixed_size_write.rs:LL:CC | LL | a16.store(1, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | a16.store(1, Ordering::SeqCst); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/mixed_size_write.rs:LL:CC + = note: inside closure at tests/fail/data_race/mixed_size_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr index 37ef46335d414..e97c4a4fdcb37 100644 --- a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/read_read_race1.rs:LL:CC + --> tests/fail/data_race/read_read_race1.rs:LL:CC | LL | a.load(Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/read_read_race1.rs:LL:CC + --> tests/fail/data_race/read_read_race1.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | unsafe { ptr.read() }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/read_read_race1.rs:LL:CC + = note: inside closure at tests/fail/data_race/read_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr index e0cabf62a2504..d64032db7b32c 100644 --- a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/read_read_race2.rs:LL:CC + --> tests/fail/data_race/read_read_race2.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/read_read_race2.rs:LL:CC + --> tests/fail/data_race/read_read_race2.rs:LL:CC | LL | a.load(Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | a.load(Ordering::SeqCst); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/read_read_race2.rs:LL:CC + = note: inside closure at tests/fail/data_race/read_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.stderr b/src/tools/miri/tests/fail/data_race/read_write_race.stderr index 8558db4bfdc8c..eac5a0c8a6cbe 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/read_write_race.rs:LL:CC + --> tests/fail/data_race/read_write_race.rs:LL:CC | LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/read_write_race.rs:LL:CC + --> tests/fail/data_race/read_write_race.rs:LL:CC | LL | let _val = *c.0; | ^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/read_write_race.rs:LL:CC + = note: inside closure at tests/fail/data_race/read_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr index 7ca249a917b27..9af78bc79a300 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/read_write_race_stack.rs:LL:CC + --> tests/fail/data_race/read_write_race_stack.rs:LL:CC | LL | stack_var | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/read_write_race_stack.rs:LL:CC + --> tests/fail/data_race/read_write_race_stack.rs:LL:CC | LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/read_write_race_stack.rs:LL:CC + = note: inside closure at tests/fail/data_race/read_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr index b5e6895302f30..a358d8da364e5 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/relax_acquire_race.rs:LL:CC + --> tests/fail/data_race/relax_acquire_race.rs:LL:CC | LL | *c.0 | ^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/relax_acquire_race.rs:LL:CC + --> tests/fail/data_race/relax_acquire_race.rs:LL:CC | LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/relax_acquire_race.rs:LL:CC + = note: inside closure at tests/fail/data_race/relax_acquire_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr index e031c55ecb17f..f47e463dd6322 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/release_seq_race.rs:LL:CC + --> tests/fail/data_race/release_seq_race.rs:LL:CC | LL | *c.0 | ^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/release_seq_race.rs:LL:CC + --> tests/fail/data_race/release_seq_race.rs:LL:CC | LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/release_seq_race.rs:LL:CC + = note: inside closure at tests/fail/data_race/release_seq_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr index 86183e1e43f7a..2d26d4cf68a26 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/release_seq_race_same_thread.rs:LL:CC + --> tests/fail/data_race/release_seq_race_same_thread.rs:LL:CC | LL | *c.0 | ^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/release_seq_race_same_thread.rs:LL:CC + --> tests/fail/data_race/release_seq_race_same_thread.rs:LL:CC | LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/release_seq_race_same_thread.rs:LL:CC + = note: inside closure at tests/fail/data_race/release_seq_race_same_thread.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.stderr b/src/tools/miri/tests/fail/data_race/rmw_race.stderr index 2aa27cc8c7f2e..4a991db32d610 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.stderr +++ b/src/tools/miri/tests/fail/data_race/rmw_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/rmw_race.rs:LL:CC + --> tests/fail/data_race/rmw_race.rs:LL:CC | LL | *c.0 | ^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/rmw_race.rs:LL:CC + --> tests/fail/data_race/rmw_race.rs:LL:CC | LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/rmw_race.rs:LL:CC + = note: inside closure at tests/fail/data_race/rmw_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr index 683acc1abd252..643426aba99eb 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr @@ -1,20 +1,20 @@ error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `main` at ALLOC. (2) just happened here - --> $DIR/stack_pop_race.rs:LL:CC + --> tests/fail/data_race/stack_pop_race.rs:LL:CC | LL | } | ^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `main` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/stack_pop_race.rs:LL:CC + --> tests/fail/data_race/stack_pop_race.rs:LL:CC | LL | let _val = unsafe { *ptr.0 }; | ^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): - = note: inside `race` at $DIR/stack_pop_race.rs:LL:CC + = note: inside `race` at tests/fail/data_race/stack_pop_race.rs:LL:CC note: inside `main` - --> $DIR/stack_pop_race.rs:LL:CC + --> tests/fail/data_race/stack_pop_race.rs:LL:CC | LL | race(0); | ^^^^^^^ diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.stderr b/src/tools/miri/tests/fail/data_race/write_write_race.stderr index 37b758ab2a5cd..2ea54421b89c7 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/write_write_race.rs:LL:CC + --> tests/fail/data_race/write_write_race.rs:LL:CC | LL | *c.0 = 64; | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/write_write_race.rs:LL:CC + --> tests/fail/data_race/write_write_race.rs:LL:CC | LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/write_write_race.rs:LL:CC + = note: inside closure at tests/fail/data_race/write_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr index 2503a4f4ba870..0cd9de1131808 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr @@ -1,18 +1,18 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/write_write_race_stack.rs:LL:CC + --> tests/fail/data_race/write_write_race_stack.rs:LL:CC | LL | stack_var = 1usize; | ^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/write_write_race_stack.rs:LL:CC + --> tests/fail/data_race/write_write_race_stack.rs:LL:CC | LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/write_write_race_stack.rs:LL:CC + = note: inside closure at tests/fail/data_race/write_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/deny_lint.stderr b/src/tools/miri/tests/fail/deny_lint.stderr index d1c9b4818071a..fe96edf934612 100644 --- a/src/tools/miri/tests/fail/deny_lint.stderr +++ b/src/tools/miri/tests/fail/deny_lint.stderr @@ -1,11 +1,11 @@ error: struct `Foo` is never constructed - --> $DIR/deny_lint.rs:LL:CC + --> tests/fail/deny_lint.rs:LL:CC | LL | struct Foo; | ^^^ | note: the lint level is defined here - --> $DIR/deny_lint.rs:LL:CC + --> tests/fail/deny_lint.rs:LL:CC | LL | #![deny(warnings, unused)] | ^^^^^^ diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs index 982d57b737202..7ac619e09abf6 100644 --- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs @@ -16,5 +16,5 @@ impl T1 for i32 { fn main() { let r = Box::new(0) as Box; let r2: Box = unsafe { std::mem::transmute(r) }; - r2.method2(); //~ERROR: using vtable for trait `T1` but trait `T2` was expected + r2.method2(); //~ERROR: using vtable for `T1` but `T2` was expected } diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr index 019a55bcdcb1a..37d102c87134d 100644 --- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr +++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr @@ -1,13 +1,13 @@ -error: Undefined Behavior: using vtable for trait `T1` but trait `T2` was expected - --> $DIR/dyn-call-trait-mismatch.rs:LL:CC +error: Undefined Behavior: using vtable for `T1` but `T2` was expected + --> tests/fail/dyn-call-trait-mismatch.rs:LL:CC | LL | r2.method2(); - | ^^^^^^^^^^^^ using vtable for trait `T1` but trait `T2` was expected + | ^^^^^^^^^^^^ using vtable for `T1` but `T2` was expected | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dyn-call-trait-mismatch.rs:LL:CC + = note: inside `main` at tests/fail/dyn-call-trait-mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr index 4165d5ea15d97..54d9d385e9623 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr +++ b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display` - --> $DIR/dyn-upcast-nop-wrong-trait.rs:LL:CC + --> tests/fail/dyn-upcast-nop-wrong-trait.rs:LL:CC | LL | let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display` @@ -7,7 +7,7 @@ LL | let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::tra = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dyn-upcast-nop-wrong-trait.rs:LL:CC + = note: inside `main` at tests/fail/dyn-upcast-nop-wrong-trait.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs index 85d7582d112ae..f450e7e652c51 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs @@ -63,6 +63,6 @@ fn main() { let baz: &dyn Baz = &1; let baz_fake: *const dyn Bar = std::mem::transmute(baz); let _err = baz_fake as *const dyn Foo; - //~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected + //~^ERROR: using vtable for `Baz` but `Bar` was expected } } diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr index 87b1361c3e504..d0fd0e6fcc144 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -1,13 +1,13 @@ -error: Undefined Behavior: using vtable for trait `Baz` but trait `Bar` was expected - --> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC +error: Undefined Behavior: using vtable for `Baz` but `Bar` was expected + --> tests/fail/dyn-upcast-trait-mismatch.rs:LL:CC | LL | let _err = baz_fake as *const dyn Foo; - | ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ using vtable for `Baz` but `Bar` was expected | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dyn-upcast-trait-mismatch.rs:LL:CC + = note: inside `main` at tests/fail/dyn-upcast-trait-mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr index a48a0a993daa1..4e2b9c03eae19 100644 --- a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr +++ b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to set discriminant of a Option> to the niched variant, but the value does not match - --> $DIR/enum-set-discriminant-niche-variant-wrong.rs:LL:CC + --> tests/fail/enum-set-discriminant-niche-variant-wrong.rs:LL:CC | LL | SetDiscriminant(*ptr, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^ trying to set discriminant of a Option> to the niched variant, but the value does not match @@ -7,9 +7,9 @@ LL | SetDiscriminant(*ptr, 1); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `set_discriminant` at $DIR/enum-set-discriminant-niche-variant-wrong.rs:LL:CC + = note: inside `set_discriminant` at tests/fail/enum-set-discriminant-niche-variant-wrong.rs:LL:CC note: inside `main` - --> $DIR/enum-set-discriminant-niche-variant-wrong.rs:LL:CC + --> tests/fail/enum-set-discriminant-niche-variant-wrong.rs:LL:CC | LL | set_discriminant(&mut v); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/environ-gets-deallocated.rs b/src/tools/miri/tests/fail/environ-gets-deallocated.rs index 5391a9176d0dd..84618abc6dbba 100644 --- a/src/tools/miri/tests/fail/environ-gets-deallocated.rs +++ b/src/tools/miri/tests/fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Windows does not have a global environ list that the program can access directly +//@ignore-target: windows # Windows does not have a global environ list that the program can access directly fn get_environ() -> *const *const u8 { extern "C" { diff --git a/src/tools/miri/tests/fail/environ-gets-deallocated.stderr b/src/tools/miri/tests/fail/environ-gets-deallocated.stderr index c9bda00493e06..bb3fe1cec73df 100644 --- a/src/tools/miri/tests/fail/environ-gets-deallocated.stderr +++ b/src/tools/miri/tests/fail/environ-gets-deallocated.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/environ-gets-deallocated.rs:LL:CC + --> tests/fail/environ-gets-deallocated.rs:LL:CC | LL | let _y = unsafe { *pointer }; | ^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,7 +7,7 @@ LL | let _y = unsafe { *pointer }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/environ-gets-deallocated.rs:LL:CC + = note: inside `main` at tests/fail/environ-gets-deallocated.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/erroneous_const.stderr b/src/tools/miri/tests/fail/erroneous_const.stderr index ab036247a314b..3528620cb6a83 100644 --- a/src/tools/miri/tests/fail/erroneous_const.stderr +++ b/src/tools/miri/tests/fail/erroneous_const.stderr @@ -1,13 +1,13 @@ error[E0080]: evaluation of `PrintName::::VOID` failed - --> $DIR/erroneous_const.rs:LL:CC + --> tests/fail/erroneous_const.rs:LL:CC | LL | const VOID: ! = panic!(); - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/erroneous_const.rs:LL:CC + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', tests/fail/erroneous_const.rs:LL:CC | = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $DIR/erroneous_const.rs:LL:CC + --> tests/fail/erroneous_const.rs:LL:CC | LL | let _ = PrintName::::VOID; | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/erroneous_const2.stderr b/src/tools/miri/tests/fail/erroneous_const2.stderr index 2227436707482..76f8cbcd2893c 100644 --- a/src/tools/miri/tests/fail/erroneous_const2.stderr +++ b/src/tools/miri/tests/fail/erroneous_const2.stderr @@ -1,17 +1,17 @@ error[E0080]: evaluation of constant value failed - --> $DIR/erroneous_const2.rs:LL:CC + --> tests/fail/erroneous_const2.rs:LL:CC | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; | ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow note: erroneous constant encountered - --> $DIR/erroneous_const2.rs:LL:CC + --> tests/fail/erroneous_const2.rs:LL:CC | LL | println!("{}", FOO); | ^^^ note: erroneous constant encountered - --> $DIR/erroneous_const2.rs:LL:CC + --> tests/fail/erroneous_const2.rs:LL:CC | LL | println!("{}", FOO); | ^^^ @@ -19,7 +19,7 @@ LL | println!("{}", FOO); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: erroneous constant encountered - --> $DIR/erroneous_const2.rs:LL:CC + --> tests/fail/erroneous_const2.rs:LL:CC | LL | println!("{}", FOO); | ^^^ diff --git a/src/tools/miri/tests/fail/extern-type-field-offset.stderr b/src/tools/miri/tests/fail/extern-type-field-offset.stderr index c07b63e0c0384..1ed440c7a33b2 100644 --- a/src/tools/miri/tests/fail/extern-type-field-offset.stderr +++ b/src/tools/miri/tests/fail/extern-type-field-offset.stderr @@ -1,5 +1,5 @@ warning: reborrow of reference to `extern type` - --> $DIR/extern-type-field-offset.rs:LL:CC + --> tests/fail/extern-type-field-offset.rs:LL:CC | LL | let x: &Newtype = unsafe { &*(&buf as *const _ as *const Newtype) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow of a reference to `extern type` is not properly supported @@ -7,17 +7,17 @@ LL | let x: &Newtype = unsafe { &*(&buf as *const _ as *const Newtype) }; = help: `extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code = help: try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead = note: BACKTRACE: - = note: inside `main` at $DIR/extern-type-field-offset.rs:LL:CC + = note: inside `main` at tests/fail/extern-type-field-offset.rs:LL:CC error: unsupported operation: `extern type` field does not have a known offset - --> $DIR/extern-type-field-offset.rs:LL:CC + --> tests/fail/extern-type-field-offset.rs:LL:CC | LL | let _field = &x.a; | ^^^^ `extern type` field does not have a known offset | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/extern-type-field-offset.rs:LL:CC + = note: inside `main` at tests/fail/extern-type-field-offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/extern_static.stderr b/src/tools/miri/tests/fail/extern_static.stderr index c7ab128e2fe97..c0bedbbcbf957 100644 --- a/src/tools/miri/tests/fail/extern_static.stderr +++ b/src/tools/miri/tests/fail/extern_static.stderr @@ -1,12 +1,12 @@ error: unsupported operation: extern static `FOO` is not supported by Miri - --> $DIR/extern_static.rs:LL:CC + --> tests/fail/extern_static.rs:LL:CC | LL | let _val = std::ptr::addr_of!(FOO); | ^^^ extern static `FOO` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/extern_static.rs:LL:CC + = note: inside `main` at tests/fail/extern_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/extern_static_in_const.stderr b/src/tools/miri/tests/fail/extern_static_in_const.stderr index aa524c064694e..067a2a2b643ba 100644 --- a/src/tools/miri/tests/fail/extern_static_in_const.stderr +++ b/src/tools/miri/tests/fail/extern_static_in_const.stderr @@ -1,12 +1,12 @@ error: unsupported operation: extern static `E` is not supported by Miri - --> $DIR/extern_static_in_const.rs:LL:CC + --> tests/fail/extern_static_in_const.rs:LL:CC | LL | let _val = X; | ^ extern static `E` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/extern_static_in_const.rs:LL:CC + = note: inside `main` at tests/fail/extern_static_in_const.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/extern_static_wrong_size.rs b/src/tools/miri/tests/fail/extern_static_wrong_size.rs index fee3c38c25e5e..56c3ddd351612 100644 --- a/src/tools/miri/tests/fail/extern_static_wrong_size.rs +++ b/src/tools/miri/tests/fail/extern_static_wrong_size.rs @@ -1,4 +1,4 @@ -//@ only-target-linux: we need a specific extern supported on this target +//@only-target: linux # we need a specific extern supported on this target //@normalize-stderr-test: "[48] bytes" -> "N bytes" extern "C" { diff --git a/src/tools/miri/tests/fail/extern_static_wrong_size.stderr b/src/tools/miri/tests/fail/extern_static_wrong_size.stderr index 3c013a5d15d05..1af84e23682d5 100644 --- a/src/tools/miri/tests/fail/extern_static_wrong_size.stderr +++ b/src/tools/miri/tests/fail/extern_static_wrong_size.stderr @@ -1,12 +1,12 @@ error: unsupported operation: extern static `environ` has been declared as `extern_static_wrong_size::environ` with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes - --> $DIR/extern_static_wrong_size.rs:LL:CC + --> tests/fail/extern_static_wrong_size.rs:LL:CC | LL | let _val = unsafe { environ }; | ^^^^^^^ extern static `environ` has been declared as `extern_static_wrong_size::environ` with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/extern_static_wrong_size.rs:LL:CC + = note: inside `main` at tests/fail/extern_static_wrong_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr index 609426bb28916..d9ab782986fbe 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(S(0)) }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | / mir! { LL | | let _unit: (); @@ -18,14 +18,14 @@ LL | | } LL | | } | |_____^ help: is this argument - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `callee` at $DIR/arg_inplace_mutate.rs:LL:CC + = note: inside `callee` at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC note: inside `main` - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index c187d24e5e893..677952b39da10 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through (root of the allocation) at ALLOC[0x0] is forbidden - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^ write access through (root of the allocation) at ALLOC[0x0] is forbidden @@ -9,7 +9,7 @@ LL | unsafe { ptr.write(S(0)) }; = help: this foreign write access would cause the protected tag (currently Active) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | / mir! { LL | | let _unit: (); @@ -20,20 +20,20 @@ LL | | } LL | | } | |_____^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: BACKTRACE (of the first span): - = note: inside `callee` at $DIR/arg_inplace_mutate.rs:LL:CC + = note: inside `callee` at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC note: inside `main` - --> $DIR/arg_inplace_mutate.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr index 2cd9966bbf59e..7fd71c6084719 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/arg_inplace_observe_after.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_after.rs:LL:CC | LL | _observe = non_copy.0; | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | _observe = non_copy.0; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/arg_inplace_observe_after.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/arg_inplace_observe_after.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr index 1c73577f5cd5d..032bbfa8f18cc 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,9 +7,9 @@ LL | unsafe { ptr.read() }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `change_arg` at $DIR/arg_inplace_observe_during.rs:LL:CC + = note: inside `change_arg` at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC note: inside `main` - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr index 68b7c0307c846..efdd6129d7443 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,7 +7,7 @@ LL | unsafe { ptr.read() }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | / mir! { LL | | let _unit: (); @@ -18,14 +18,14 @@ LL | | LL | | } | |_____^ help: is this argument - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | x.0 = 0; | ^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `change_arg` at $DIR/arg_inplace_observe_during.rs:LL:CC + = note: inside `change_arg` at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC note: inside `main` - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index 64888cce6135c..5746ad1e13d1a 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: read access through (root of the allocation) at ALLOC[0x0] is forbidden - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ read access through (root of the allocation) at ALLOC[0x0] is forbidden @@ -9,7 +9,7 @@ LL | unsafe { ptr.read() }; = help: this foreign read access would cause the protected tag (currently Active) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | / mir! { LL | | let _unit: (); @@ -20,20 +20,20 @@ LL | | LL | | } | |_____^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | x.0 = 0; | ^^^^^^^ help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | x.0 = 0; | ^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: BACKTRACE (of the first span): - = note: inside `change_arg` at $DIR/arg_inplace_observe_during.rs:LL:CC + = note: inside `change_arg` at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC note: inside `main` - --> $DIR/arg_inplace_observe_during.rs:LL:CC + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr index 2f24425ed1d64..bf1fbb7721f1f 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with ABI C using caller ABI Rust - --> $DIR/check_arg_abi.rs:LL:CC + --> tests/fail/function_calls/check_arg_abi.rs:LL:CC | LL | let _ = malloc(0); | ^^^^^^^^^ calling a function with ABI C using caller ABI Rust @@ -7,7 +7,7 @@ LL | let _ = malloc(0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/check_arg_abi.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/check_arg_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.stderr index d475801f41cd0..687d0538b3c70 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: incorrect number of arguments: got 1, expected 0 - --> $DIR/check_arg_count_abort.rs:LL:CC + --> tests/fail/function_calls/check_arg_count_abort.rs:LL:CC | LL | abort(1); | ^^^^^^^^ incorrect number of arguments: got 1, expected 0 @@ -7,7 +7,7 @@ LL | abort(1); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/check_arg_count_abort.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/check_arg_count_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.stderr index ad952804ecc96..d778eae64fa4b 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: incorrect number of arguments: got 0, expected 1 - --> $DIR/check_arg_count_too_few_args.rs:LL:CC + --> tests/fail/function_calls/check_arg_count_too_few_args.rs:LL:CC | LL | let _ = malloc(); | ^^^^^^^^ incorrect number of arguments: got 0, expected 1 @@ -7,7 +7,7 @@ LL | let _ = malloc(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/check_arg_count_too_few_args.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/check_arg_count_too_few_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.stderr index 3b1df8a9d4202..dfec2a8628706 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: incorrect number of arguments: got 2, expected 1 - --> $DIR/check_arg_count_too_many_args.rs:LL:CC + --> tests/fail/function_calls/check_arg_count_too_many_args.rs:LL:CC | LL | let _ = malloc(1, 2); | ^^^^^^^^^^^^ incorrect number of arguments: got 2, expected 1 @@ -7,7 +7,7 @@ LL | let _ = malloc(1, 2); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/check_arg_count_too_many_args.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/check_arg_count_too_many_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr index 890fed09e4819..6b0692e1c6e8d 100644 --- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with calling convention C using calling convention Rust - --> $DIR/check_callback_abi.rs:LL:CC + --> tests/fail/function_calls/check_callback_abi.rs:LL:CC | LL | / std::intrinsics::catch_unwind( LL | | @@ -12,7 +12,7 @@ LL | | ); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/check_callback_abi.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/check_callback_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index 2feba7d8e3480..e4302ad1d3a53 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C - --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | foo(); | ^^^^^ calling a function with calling convention Rust using calling convention C @@ -7,7 +7,7 @@ LL | foo(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index 0537508babd9f..9f40c48b338e3 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C - --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | std::mem::transmute::(foo)(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C @@ -7,7 +7,7 @@ LL | std::mem::transmute::(foo)(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index 2feba7d8e3480..e4302ad1d3a53 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C - --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | foo(); | ^^^^^ calling a function with calling convention Rust using calling convention C @@ -7,7 +7,7 @@ LL | foo(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr index a11a2b95689bb..5f306cc8ab1f9 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/exported_symbol_bad_unwind1.rs:LL:CC: +thread 'main' panicked at tests/fail/function_calls/exported_symbol_bad_unwind1.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding - --> $DIR/exported_symbol_bad_unwind1.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_bad_unwind1.rs:LL:CC | LL | unsafe { unwind() } | ^^^^^^^^ unwinding past a stack frame that does not allow unwinding @@ -11,7 +11,7 @@ LL | unsafe { unwind() } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exported_symbol_bad_unwind1.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_bad_unwind1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 12425cc48927b..aef45042e8bd5 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC: +thread 'main' panicked at tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect @@ -21,14 +21,14 @@ LL | ABORT(); = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `nounwind` - --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { LL | | panic!(); LL | | } | |_^ note: inside `main` - --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } | ^ diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 12425cc48927b..aef45042e8bd5 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC: +thread 'main' panicked at tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect @@ -21,14 +21,14 @@ LL | ABORT(); = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `nounwind` - --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { LL | | panic!(); LL | | } | |_^ note: inside `main` - --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } | ^ diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr index f9e299bf5d2e4..a81e8226e5ac4 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC: +thread 'main' panicked at tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding - --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } | ^ unwinding past a stack frame that does not allow unwinding @@ -11,7 +11,7 @@ LL | unsafe { nounwind() } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_clashing.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_clashing.stderr index 2f561ed88e3f1..e9e580ffc86f7 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_clashing.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_clashing.stderr @@ -1,21 +1,21 @@ error: multiple definitions of symbol `foo` - --> $DIR/exported_symbol_clashing.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_clashing.rs:LL:CC | LL | unsafe { foo() } | ^^^^^ multiple definitions of symbol `foo` | help: it's first defined here, in crate `exported_symbol_clashing` - --> $DIR/exported_symbol_clashing.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_clashing.rs:LL:CC | LL | fn foo() {} | ^^^^^^^^ help: then it's defined here again, in crate `exported_symbol_clashing` - --> $DIR/exported_symbol_clashing.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_clashing.rs:LL:CC | LL | fn bar() {} | ^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/exported_symbol_clashing.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_shim_clashing.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_shim_clashing.stderr index d51156b3c3360..fb9cc47c7a8ca 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_shim_clashing.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_shim_clashing.stderr @@ -1,11 +1,11 @@ error: found `malloc` symbol definition that clashes with a built-in shim - --> $DIR/exported_symbol_shim_clashing.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_shim_clashing.rs:LL:CC | LL | malloc(0); | ^^^^^^^^^ found `malloc` symbol definition that clashes with a built-in shim | help: the `malloc` symbol is defined here - --> $DIR/exported_symbol_shim_clashing.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_shim_clashing.rs:LL:CC | LL | / extern "C" fn malloc(_: usize) -> *mut std::ffi::c_void { LL | | @@ -13,7 +13,7 @@ LL | | unreachable!() LL | | } | |_^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/exported_symbol_shim_clashing.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_shim_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr index 69b710b3d3b16..1ff9aa36f1ee8 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with more arguments than it expected - --> $DIR/exported_symbol_wrong_arguments.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC | LL | unsafe { foo(1) } | ^^^^^^ calling a function with more arguments than it expected @@ -7,7 +7,7 @@ LL | unsafe { foo(1) } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exported_symbol_wrong_arguments.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_type.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_type.stderr index 96b483059b0e3..29c87e8c4377c 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_type.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_type.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempt to call an exported symbol that is not defined as a function - --> $DIR/exported_symbol_wrong_type.rs:LL:CC + --> tests/fail/function_calls/exported_symbol_wrong_type.rs:LL:CC | LL | unsafe { FOO() } | ^^^^^ attempt to call an exported symbol that is not defined as a function @@ -7,7 +7,7 @@ LL | unsafe { FOO() } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exported_symbol_wrong_type.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/exported_symbol_wrong_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr index e8b766d0b0e28..9da2c3589da88 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,9 +7,9 @@ LL | unsafe { ptr.read() }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `myfun` at $DIR/return_pointer_aliasing_read.rs:LL:CC + = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC note: inside `main` - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr index 941470e92959e..b009b0901c416 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,7 +7,7 @@ LL | unsafe { ptr.read() }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | / mir! { LL | | { @@ -18,14 +18,14 @@ LL | | } LL | | } | |_____^ help: is this argument - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `myfun` at $DIR/return_pointer_aliasing_read.rs:LL:CC + = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC note: inside `main` - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index 715ee33061994..6d2cbe9b7cd68 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: read access through (root of the allocation) at ALLOC[0x0] is forbidden - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ read access through (root of the allocation) at ALLOC[0x0] is forbidden @@ -9,7 +9,7 @@ LL | unsafe { ptr.read() }; = help: this foreign read access would cause the protected tag (currently Active) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | / mir! { LL | | { @@ -20,20 +20,20 @@ LL | | } LL | | } | |_____^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: BACKTRACE (of the first span): - = note: inside `myfun` at $DIR/return_pointer_aliasing_read.rs:LL:CC + = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC note: inside `main` - --> $DIR/return_pointer_aliasing_read.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr index 51cb270dd2ecb..54f9a7aebd604 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(0) }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | / mir! { LL | | { @@ -18,14 +18,14 @@ LL | | } LL | | } | |_____^ help: is this argument - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `myfun` at $DIR/return_pointer_aliasing_write.rs:LL:CC + = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC note: inside `main` - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index 66ca1027edce2..693534be2e00d 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through (root of the allocation) at ALLOC[0x0] is forbidden - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^ write access through (root of the allocation) at ALLOC[0x0] is forbidden @@ -9,7 +9,7 @@ LL | unsafe { ptr.write(0) }; = help: this foreign write access would cause the protected tag (currently Active) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | / mir! { LL | | { @@ -20,20 +20,20 @@ LL | | } LL | | } | |_____^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: BACKTRACE (of the first span): - = note: inside `myfun` at $DIR/return_pointer_aliasing_write.rs:LL:CC + = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC note: inside `main` - --> $DIR/return_pointer_aliasing_write.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr index 7e527a440d128..520937beaeb8c 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(0) }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | / mir! { LL | | { @@ -18,14 +18,14 @@ LL | | } LL | | } | |_____^ help: is this argument - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `myfun2` at $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + = note: inside `myfun2` at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC note: inside `main` - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index b1f2cab031e4d..a879189d0c139 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through (root of the allocation) at ALLOC[0x0] is forbidden - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^ write access through (root of the allocation) at ALLOC[0x0] is forbidden @@ -9,7 +9,7 @@ LL | unsafe { ptr.write(0) }; = help: this foreign write access would cause the protected tag (currently Active) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | / mir! { LL | | { @@ -20,20 +20,20 @@ LL | | } LL | | } | |_____^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: BACKTRACE (of the first span): - = note: inside `myfun2` at $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + = note: inside `myfun2` at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC note: inside `main` - --> $DIR/return_pointer_aliasing_write_tail_call.rs:LL:CC + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr index 83efc9974e895..db876cb5ce6db 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/return_pointer_on_unwind.rs:LL:CC: +thread 'main' panicked at tests/fail/function_calls/return_pointer_on_unwind.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/return_pointer_on_unwind.rs:LL:CC + --> tests/fail/function_calls/return_pointer_on_unwind.rs:LL:CC | LL | dbg!(x.0); | ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.rs b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.rs index e98a3abadf59b..200f1062a3e80 100644 --- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.rs +++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.rs @@ -1,4 +1,4 @@ -//@only-target-x86_64 +//@only-target: x86_64 #![allow(improper_ctypes_definitions)] use std::arch::x86_64::*; use std::mem::transmute; diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr index 2544421c7e8c7..1d5b331be6c5e 100644 --- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr +++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function that requires unavailable target features: avx - --> $DIR/simd_feature_flag_difference.rs:LL:CC + --> tests/fail/function_calls/simd_feature_flag_difference.rs:LL:CC | LL | unsafe { foo(0.0, x) } | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx @@ -7,9 +7,9 @@ LL | unsafe { foo(0.0, x) } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `bar` at $DIR/simd_feature_flag_difference.rs:LL:CC + = note: inside `bar` at tests/fail/function_calls/simd_feature_flag_difference.rs:LL:CC note: inside `main` - --> $DIR/simd_feature_flag_difference.rs:LL:CC + --> tests/fail/function_calls/simd_feature_flag_difference.rs:LL:CC | LL | let copy = bar(input); | ^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.rs b/src/tools/miri/tests/fail/function_calls/target_feature.rs index 84e01eb4803fe..32207ffae4865 100644 --- a/src/tools/miri/tests/fail/function_calls/target_feature.rs +++ b/src/tools/miri/tests/fail/function_calls/target_feature.rs @@ -1,5 +1,5 @@ -//@only-target-x86_64: uses x86 target features -//@ignore-target-x86_64-apple-darwin: that target actually has ssse3 +//@only-target: x86_64 # uses x86 target features +//@ignore-target: x86_64-apple-darwin # that target actually has ssse3 fn main() { assert!(!is_x86_feature_detected!("ssse3")); diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.stderr b/src/tools/miri/tests/fail/function_calls/target_feature.stderr index 4d3cf6e9d3bc0..937bd4a5951f6 100644 --- a/src/tools/miri/tests/fail/function_calls/target_feature.stderr +++ b/src/tools/miri/tests/fail/function_calls/target_feature.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function that requires unavailable target features: ssse3 - --> $DIR/target_feature.rs:LL:CC + --> tests/fail/function_calls/target_feature.rs:LL:CC | LL | ssse3_fn(); | ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3 @@ -7,7 +7,7 @@ LL | ssse3_fn(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/target_feature.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/target_feature.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/target_feature_wasm.rs b/src/tools/miri/tests/fail/function_calls/target_feature_wasm.rs index bd400e8824ac3..28d3d4a60548a 100644 --- a/src/tools/miri/tests/fail/function_calls/target_feature_wasm.rs +++ b/src/tools/miri/tests/fail/function_calls/target_feature_wasm.rs @@ -1,4 +1,4 @@ -//@only-target-wasm: tests WASM-specific behavior +//@only-target: wasm # tests WASM-specific behavior //@compile-flags: -C target-feature=-simd128 fn main() { diff --git a/src/tools/miri/tests/fail/function_calls/target_feature_wasm.stderr b/src/tools/miri/tests/fail/function_calls/target_feature_wasm.stderr index dc0aca77f9eb5..9cc8154653121 100644 --- a/src/tools/miri/tests/fail/function_calls/target_feature_wasm.stderr +++ b/src/tools/miri/tests/fail/function_calls/target_feature_wasm.stderr @@ -1,11 +1,11 @@ error: abnormal termination: calling a function that requires unavailable target features: simd128 - --> $DIR/target_feature_wasm.rs:LL:CC + --> tests/fail/function_calls/target_feature_wasm.rs:LL:CC | LL | simd128_fn(); | ^^^^^^^^^^^^ calling a function that requires unavailable target features: simd128 | = note: BACKTRACE: - = note: inside `main` at $DIR/target_feature_wasm.rs:LL:CC + = note: inside `main` at tests/fail/function_calls/target_feature_wasm.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr index 2b2a898ce73bb..521cececc3750 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type S passing data of type [i32; 4] - --> $DIR/abi_mismatch_array_vs_struct.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC | LL | g(Default::default()) | ^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type S passing data of type [i32; 4] @@ -9,7 +9,7 @@ LL | g(Default::default()) = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_array_vs_struct.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr index 752e17116d12f..20704299257a0 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type f32 passing data of type i32 - --> $DIR/abi_mismatch_int_vs_float.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC | LL | g(42) | ^^^^^ calling a function with argument of type f32 passing data of type i32 @@ -9,7 +9,7 @@ LL | g(42) = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_int_vs_float.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr index 907a8e50c411d..3e3d07e1484e9 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type *const [i32] passing data of type *const i32 - --> $DIR/abi_mismatch_raw_pointer.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC | LL | g(&42 as *const i32) | ^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type *const [i32] passing data of type *const i32 @@ -9,7 +9,7 @@ LL | g(&42 as *const i32) = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_raw_pointer.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr index 8ec19db813adf..6b92824494ac8 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type S2 passing data of type S1 - --> $DIR/abi_mismatch_repr_C.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC | LL | fnptr(S1(NonZero::new(1).unwrap())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type S2 passing data of type S1 @@ -9,7 +9,7 @@ LL | fnptr(S1(NonZero::new(1).unwrap())); = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_repr_C.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr index 3793590f84237..51539b078aec2 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with return type u32 passing return place of type () - --> $DIR/abi_mismatch_return_type.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC | LL | g() | ^^^ calling a function with return type u32 passing return place of type () @@ -9,7 +9,7 @@ LL | g() = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_return_type.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr index 0c533c14173da..16a83b8e3425a 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type (i32, i32) passing data of type i32 - --> $DIR/abi_mismatch_simple.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC | LL | g(42) | ^^^^^ calling a function with argument of type (i32, i32) passing data of type i32 @@ -9,7 +9,7 @@ LL | g(42) = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_simple.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr index 2e50d054e771f..760826805c7f1 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with fewer arguments than it requires - --> $DIR/abi_mismatch_too_few_args.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC | LL | g() | ^^^ calling a function with fewer arguments than it requires @@ -7,7 +7,7 @@ LL | g() = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_too_few_args.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr index facfe9d31f2d8..9552250546bb8 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with more arguments than it expected - --> $DIR/abi_mismatch_too_many_args.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC | LL | g(42) | ^^^^^ calling a function with more arguments than it expected @@ -7,7 +7,7 @@ LL | g(42) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_too_many_args.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr index ef4b60b83b1ff..021be890d25df 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type std::simd::Simd passing data of type std::simd::Simd - --> $DIR/abi_mismatch_vector.rs:LL:CC + --> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC | LL | g(Default::default()) | ^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type std::simd::Simd passing data of type std::simd::Simd @@ -9,7 +9,7 @@ LL | g(Default::default()) = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: - = note: inside `main` at $DIR/abi_mismatch_vector.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr index f95a62535d893..6112e92c93949 100644 --- a/src/tools/miri/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using ALLOC as function pointer but it does not point to a function - --> $DIR/cast_box_int_to_fn_ptr.rs:LL:CC + --> tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs:LL:CC | LL | (*g)(42) | ^^^^^^^^ using ALLOC as function pointer but it does not point to a function @@ -7,7 +7,7 @@ LL | (*g)(42) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_box_int_to_fn_ptr.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index 347afa77053ee..f2d9933188d7b 100644 --- a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/cast_int_to_fn_ptr.rs:LL:CC + --> tests/fail/function_pointers/cast_int_to_fn_ptr.rs:LL:CC | LL | g(42) | ^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | g(42) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_int_to_fn_ptr.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/cast_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.stderr index b5cee95d66de3..f7cc82b80df7a 100644 --- a/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing ALLOC which contains a function - --> $DIR/deref_fn_ptr.rs:LL:CC + --> tests/fail/function_pointers/deref_fn_ptr.rs:LL:CC | LL | *std::mem::transmute::(f) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing ALLOC which contains a function @@ -7,7 +7,7 @@ LL | *std::mem::transmute::(f) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/deref_fn_ptr.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/deref_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/execute_memory.stderr b/src/tools/miri/tests/fail/function_pointers/execute_memory.stderr index 4370e6d6a295c..e057318428298 100644 --- a/src/tools/miri/tests/fail/function_pointers/execute_memory.stderr +++ b/src/tools/miri/tests/fail/function_pointers/execute_memory.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using ALLOC as function pointer but it does not point to a function - --> $DIR/execute_memory.rs:LL:CC + --> tests/fail/function_pointers/execute_memory.rs:LL:CC | LL | f() | ^^^ using ALLOC as function pointer but it does not point to a function @@ -7,7 +7,7 @@ LL | f() = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/execute_memory.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/execute_memory.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/fn_ptr_offset.stderr b/src/tools/miri/tests/fail/function_pointers/fn_ptr_offset.stderr index e66ab681860c2..4ed09683c6301 100644 --- a/src/tools/miri/tests/fail/function_pointers/fn_ptr_offset.stderr +++ b/src/tools/miri/tests/fail/function_pointers/fn_ptr_offset.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using ALLOC+0x1 as function pointer but it does not point to a function - --> $DIR/fn_ptr_offset.rs:LL:CC + --> tests/fail/function_pointers/fn_ptr_offset.rs:LL:CC | LL | x(); | ^^^ using ALLOC+0x1 as function pointer but it does not point to a function @@ -7,7 +7,7 @@ LL | x(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/fn_ptr_offset.rs:LL:CC + = note: inside `main` at tests/fail/function_pointers/fn_ptr_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.stderr b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.stderr index db3941a32a56a..a36b0fca8023b 100644 --- a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.stderr +++ b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.stderr @@ -1,12 +1,12 @@ error: unsupported operation: Miri can only use intrinsic fallback bodies that exactly reflect the specification: they fully check for UB and are as non-deterministic as possible. After verifying that `ptr_guaranteed_cmp` does so, add the `#[miri::intrinsic_fallback_is_spec]` attribute to it; also ping @rust-lang/miri when you do that - --> $DIR/intrinsic_fallback_is_spec.rs:LL:CC + --> tests/fail/intrinsic_fallback_is_spec.rs:LL:CC | LL | ptr_guaranteed_cmp::<()>(std::ptr::null(), std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Miri can only use intrinsic fallback bodies that exactly reflect the specification: they fully check for UB and are as non-deterministic as possible. After verifying that `ptr_guaranteed_cmp` does so, add the `#[miri::intrinsic_fallback_is_spec]` attribute to it; also ping @rust-lang/miri when you do that | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/intrinsic_fallback_is_spec.rs:LL:CC + = note: inside `main` at tests/fail/intrinsic_fallback_is_spec.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/assume.stderr b/src/tools/miri/tests/fail/intrinsics/assume.stderr index 7fa6f7b5bfcf5..eadbd2c0d58c9 100644 --- a/src/tools/miri/tests/fail/intrinsics/assume.stderr +++ b/src/tools/miri/tests/fail/intrinsics/assume.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `assume` called with `false` - --> $DIR/assume.rs:LL:CC + --> tests/fail/intrinsics/assume.rs:LL:CC | LL | std::intrinsics::assume(x > 42); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` called with `false` @@ -7,7 +7,7 @@ LL | std::intrinsics::assume(x > 42); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/assume.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/assume.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overflow.stderr b/src/tools/miri/tests/fail/intrinsics/copy_overflow.stderr index b7c92cf4a57a8..c50c7c1ef4317 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_overflow.stderr +++ b/src/tools/miri/tests/fail/intrinsics/copy_overflow.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflow computing total size of `copy` - --> $DIR/copy_overflow.rs:LL:CC + --> tests/fail/intrinsics/copy_overflow.rs:LL:CC | LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` @@ -7,7 +7,7 @@ LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of:: = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/copy_overflow.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/copy_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr index e9ea262caf743..fef5a0a82a07d 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr +++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges - --> $DIR/copy_overlapping.rs:LL:CC + --> tests/fail/intrinsics/copy_overlapping.rs:LL:CC | LL | copy_nonoverlapping(a, b, 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges @@ -7,7 +7,7 @@ LL | copy_nonoverlapping(a, b, 2); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/copy_overlapping.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/copy_overlapping.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr index d190f3de6b884..2d0edd4e6cbe7 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr +++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required - --> $DIR/copy_unaligned.rs:LL:CC + --> tests/fail/intrinsics/copy_unaligned.rs:LL:CC | LL | copy_nonoverlapping(&data[5], ptr, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | copy_nonoverlapping(&data[5], ptr, 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/copy_unaligned.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/copy_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.stderr b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.stderr index 9889daaa85133..5ad3b8ad2a8bf 100644 --- a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `ctlz_nonzero` called on 0 - --> $DIR/ctlz_nonzero.rs:LL:CC + --> tests/fail/intrinsics/ctlz_nonzero.rs:LL:CC | LL | ctlz_nonzero(0u8); | ^^^^^^^^^^^^^^^^^ `ctlz_nonzero` called on 0 @@ -7,7 +7,7 @@ LL | ctlz_nonzero(0u8); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ctlz_nonzero.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ctlz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.stderr b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.stderr index 0f75657e170ab..d0263ac1e45ac 100644 --- a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.stderr +++ b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `cttz_nonzero` called on 0 - --> $DIR/cttz_nonzero.rs:LL:CC + --> tests/fail/intrinsics/cttz_nonzero.rs:LL:CC | LL | cttz_nonzero(0u8); | ^^^^^^^^^^^^^^^^^ `cttz_nonzero` called on 0 @@ -7,7 +7,7 @@ LL | cttz_nonzero(0u8); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cttz_nonzero.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/cttz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/div-by-zero.stderr b/src/tools/miri/tests/fail/intrinsics/div-by-zero.stderr index 9f66e63ca5cfa..e276874ba2559 100644 --- a/src/tools/miri/tests/fail/intrinsics/div-by-zero.stderr +++ b/src/tools/miri/tests/fail/intrinsics/div-by-zero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: dividing by zero - --> $DIR/div-by-zero.rs:LL:CC + --> tests/fail/intrinsics/div-by-zero.rs:LL:CC | LL | let _n = unchecked_div(1i64, 0); | ^^^^^^^^^^^^^^^^^^^^^^ dividing by zero @@ -7,7 +7,7 @@ LL | let _n = unchecked_div(1i64, 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/div-by-zero.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/exact_div1.stderr b/src/tools/miri/tests/fail/intrinsics/exact_div1.stderr index ca6125ab899f8..f133baecfa20d 100644 --- a/src/tools/miri/tests/fail/intrinsics/exact_div1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/exact_div1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero - --> $DIR/exact_div1.rs:LL:CC + --> tests/fail/intrinsics/exact_div1.rs:LL:CC | LL | unsafe { std::intrinsics::exact_div(2, 0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero @@ -7,7 +7,7 @@ LL | unsafe { std::intrinsics::exact_div(2, 0) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exact_div1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/exact_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/exact_div2.stderr b/src/tools/miri/tests/fail/intrinsics/exact_div2.stderr index 306e9bdc23828..315417fe8dfe5 100644 --- a/src/tools/miri/tests/fail/intrinsics/exact_div2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/exact_div2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: exact_div: 2_u16 cannot be divided by 3_u16 without remainder - --> $DIR/exact_div2.rs:LL:CC + --> tests/fail/intrinsics/exact_div2.rs:LL:CC | LL | unsafe { std::intrinsics::exact_div(2u16, 3) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder @@ -7,7 +7,7 @@ LL | unsafe { std::intrinsics::exact_div(2u16, 3) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exact_div2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/exact_div2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/exact_div3.stderr b/src/tools/miri/tests/fail/intrinsics/exact_div3.stderr index cbcb093a4e6cf..42f52540a4c5a 100644 --- a/src/tools/miri/tests/fail/intrinsics/exact_div3.stderr +++ b/src/tools/miri/tests/fail/intrinsics/exact_div3.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: exact_div: -19_i8 cannot be divided by 2_i8 without remainder - --> $DIR/exact_div3.rs:LL:CC + --> tests/fail/intrinsics/exact_div3.rs:LL:CC | LL | unsafe { std::intrinsics::exact_div(-19i8, 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder @@ -7,7 +7,7 @@ LL | unsafe { std::intrinsics::exact_div(-19i8, 2) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exact_div3.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/exact_div3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/exact_div4.stderr b/src/tools/miri/tests/fail/intrinsics/exact_div4.stderr index 1b903bc97aedb..723ed4e49ed8b 100644 --- a/src/tools/miri/tests/fail/intrinsics/exact_div4.stderr +++ b/src/tools/miri/tests/fail/intrinsics/exact_div4.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflow in signed remainder (dividing MIN by -1) - --> $DIR/exact_div4.rs:LL:CC + --> tests/fail/intrinsics/exact_div4.rs:LL:CC | LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) @@ -7,7 +7,7 @@ LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exact_div4.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/exact_div4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/fast_math_both.stderr b/src/tools/miri/tests/fail/intrinsics/fast_math_both.stderr index feba0c5991cf7..7579a81e3e1fc 100644 --- a/src/tools/miri/tests/fail/intrinsics/fast_math_both.stderr +++ b/src/tools/miri/tests/fail/intrinsics/fast_math_both.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `fsub_fast` intrinsic called with non-finite value as both parameters - --> $DIR/fast_math_both.rs:LL:CC + --> tests/fail/intrinsics/fast_math_both.rs:LL:CC | LL | ...: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fsub_fast` intrinsic called with non-finite value as both parameters @@ -7,7 +7,7 @@ LL | ...: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/fast_math_both.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/fast_math_both.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/fast_math_first.stderr b/src/tools/miri/tests/fail/intrinsics/fast_math_first.stderr index b26b5a3721594..8295ec1089fb0 100644 --- a/src/tools/miri/tests/fail/intrinsics/fast_math_first.stderr +++ b/src/tools/miri/tests/fail/intrinsics/fast_math_first.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `frem_fast` intrinsic called with non-finite value as first parameter - --> $DIR/fast_math_first.rs:LL:CC + --> tests/fail/intrinsics/fast_math_first.rs:LL:CC | LL | ... let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `frem_fast` intrinsic called with non-finite value as first parameter @@ -7,7 +7,7 @@ LL | ... let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/fast_math_first.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/fast_math_first.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/fast_math_result.stderr b/src/tools/miri/tests/fail/intrinsics/fast_math_result.stderr index 5b24d2250266d..8ddbd4cc19e99 100644 --- a/src/tools/miri/tests/fail/intrinsics/fast_math_result.stderr +++ b/src/tools/miri/tests/fail/intrinsics/fast_math_result.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `fdiv_fast` intrinsic produced non-finite value as result - --> $DIR/fast_math_result.rs:LL:CC + --> tests/fail/intrinsics/fast_math_result.rs:LL:CC | LL | let _x: f32 = core::intrinsics::fdiv_fast(1.0, 0.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fdiv_fast` intrinsic produced non-finite value as result @@ -7,7 +7,7 @@ LL | let _x: f32 = core::intrinsics::fdiv_fast(1.0, 0.0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/fast_math_result.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/fast_math_result.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/fast_math_second.stderr b/src/tools/miri/tests/fail/intrinsics/fast_math_second.stderr index cb46aa97a8de9..0fde006b3bd33 100644 --- a/src/tools/miri/tests/fail/intrinsics/fast_math_second.stderr +++ b/src/tools/miri/tests/fail/intrinsics/fast_math_second.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `fmul_fast` intrinsic called with non-finite value as second parameter - --> $DIR/fast_math_second.rs:LL:CC + --> tests/fail/intrinsics/fast_math_second.rs:LL:CC | LL | ...f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fmul_fast` intrinsic called with non-finite value as second parameter @@ -7,7 +7,7 @@ LL | ...f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/fast_math_second.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/fast_math_second.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr index 2de8f3420b7d9..bcc8ff667ff58 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf_f32 which cannot be represented in target type `i32` - --> $DIR/float_to_int_32_inf1.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_32_inf1.rs:LL:CC | LL | float_to_int_unchecked::(f32::INFINITY); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf_f32 which cannot be represented in target type `i32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f32::INFINITY); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_32_inf1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_32_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr index 53ed208bdee73..9ac910c8d2f46 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f32 which cannot be represented in target type `i32` - --> $DIR/float_to_int_32_infneg1.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_32_infneg1.rs:LL:CC | LL | float_to_int_unchecked::(f32::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f32 which cannot be represented in target type `i32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f32::NEG_INFINITY); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_32_infneg1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_32_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr index afda7124c114f..b377b701361c9 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32` - --> $DIR/float_to_int_32_nan.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_32_nan.rs:LL:CC | LL | float_to_int_unchecked::(f32::NAN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f32::NAN); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_32_nan.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_32_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr index 8ba46de8641d7..2a0dcdfaeef49 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32` - --> $DIR/float_to_int_32_nanneg.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_32_nanneg.rs:LL:CC | LL | float_to_int_unchecked::(-f32::NAN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(-f32::NAN); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_32_nanneg.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_32_nanneg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr index 9f4b2af2167bc..45be75e2f0261 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1f32 which cannot be represented in target type `u32` - --> $DIR/float_to_int_32_neg.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_32_neg.rs:LL:CC | LL | float_to_int_unchecked::(-1.000000001f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1f32 which cannot be represented in target type `u32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(-1.000000001f32); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_32_neg.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_32_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr index a8e56ddb59b90..8597dc0b072ad 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9f32 which cannot be represented in target type `i32` - --> $DIR/float_to_int_32_too_big1.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_32_too_big1.rs:LL:CC | LL | float_to_int_unchecked::(2147483648.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9f32 which cannot be represented in target type `i32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(2147483648.0f32); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_32_too_big1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_32_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr index a966e2e639c98..d79004e64294f 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9f32 which cannot be represented in target type `u32` - --> $DIR/float_to_int_32_too_big2.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_32_too_big2.rs:LL:CC | LL | float_to_int_unchecked::((u32::MAX - 127) as f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9f32 which cannot be represented in target type `u32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::((u32::MAX - 127) as f32); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_32_too_big2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_32_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr index 6115b381ebec5..6a1d48f48079a 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9f32 which cannot be represented in target type `i32` - --> $DIR/float_to_int_32_too_small1.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_32_too_small1.rs:LL:CC | LL | float_to_int_unchecked::(-2147483904.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9f32 which cannot be represented in target type `i32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(-2147483904.0f32); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_32_too_small1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_32_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr index 5db9fb1417cbc..d77544cb37f19 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf_f64 which cannot be represented in target type `u128` - --> $DIR/float_to_int_64_inf1.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_inf1.rs:LL:CC | LL | float_to_int_unchecked::(f64::INFINITY); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf_f64 which cannot be represented in target type `u128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f64::INFINITY); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_inf1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr index 3e8dadb79e4d1..c6f9eb41138a1 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `u128` - --> $DIR/float_to_int_64_infneg1.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_infneg1.rs:LL:CC | LL | float_to_int_unchecked::(f64::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `u128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_infneg1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr index cb59974bf454f..fc80f1679ceca 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `i128` - --> $DIR/float_to_int_64_infneg2.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_infneg2.rs:LL:CC | LL | float_to_int_unchecked::(f64::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `i128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_infneg2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_infneg2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr index 686970605154e..01059ed5a7382 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f64 which cannot be represented in target type `u32` - --> $DIR/float_to_int_64_nan.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_nan.rs:LL:CC | LL | float_to_int_unchecked::(f64::NAN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f64 which cannot be represented in target type `u32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f64::NAN); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_nan.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr index 505a6463cd348..f17d502d51cf4 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.0000000000000999f64 which cannot be represented in target type `u128` - --> $DIR/float_to_int_64_neg.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_neg.rs:LL:CC | LL | float_to_int_unchecked::(-1.0000000000001f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.0000000000000999f64 which cannot be represented in target type `u128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(-1.0000000000001f64); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_neg.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr index bcfd394686b1e..9379be3f82faa 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648f64 which cannot be represented in target type `i32` - --> $DIR/float_to_int_64_too_big1.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_big1.rs:LL:CC | LL | float_to_int_unchecked::(2147483648.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648f64 which cannot be represented in target type `i32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(2147483648.0f64); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_big1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr index ac6139d7e7dff..1c0a0e0e88bfe 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18f64 which cannot be represented in target type `i64` - --> $DIR/float_to_int_64_too_big2.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_big2.rs:LL:CC | LL | float_to_int_unchecked::(9223372036854775808.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18f64 which cannot be represented in target type `i64` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(9223372036854775808.0f64); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_big2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr index e289b4c0fc070..54ff73d596151 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19f64 which cannot be represented in target type `u64` - --> $DIR/float_to_int_64_too_big3.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_big3.rs:LL:CC | LL | float_to_int_unchecked::(18446744073709551616.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19f64 which cannot be represented in target type `u64` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(18446744073709551616.0f64); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_big3.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_big3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr index 657c72daa6f4b..b622867c097e7 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38f64 which cannot be represented in target type `u128` - --> $DIR/float_to_int_64_too_big4.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_big4.rs:LL:CC | LL | float_to_int_unchecked::(u128::MAX as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38f64 which cannot be represented in target type `u128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(u128::MAX as f64); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_big4.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_big4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr index 2a61b5fe15fe7..ffb8b0d1743fe 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38f64 which cannot be represented in target type `i128` - --> $DIR/float_to_int_64_too_big5.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_big5.rs:LL:CC | LL | float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38f64 which cannot be represented in target type `i128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(2402823669209384634633746074317 = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_big5.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_big5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr index 1b4b76ced18bb..8c5d81e01c22d 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308f64 which cannot be represented in target type `u128` - --> $DIR/float_to_int_64_too_big6.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_big6.rs:LL:CC | LL | float_to_int_unchecked::(f64::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308f64 which cannot be represented in target type `u128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f64::MAX); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_big6.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_big6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr index 47df8d90c062d..237540e2a6459 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308f64 which cannot be represented in target type `i128` - --> $DIR/float_to_int_64_too_big7.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_big7.rs:LL:CC | LL | float_to_int_unchecked::(f64::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308f64 which cannot be represented in target type `i128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(f64::MIN); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_big7.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_big7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr index c5eb405ee95c5..d1b9076d14b06 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649f64 which cannot be represented in target type `i32` - --> $DIR/float_to_int_64_too_small1.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_small1.rs:LL:CC | LL | float_to_int_unchecked::(-2147483649.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649f64 which cannot be represented in target type `i32` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(-2147483649.0f64); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_small1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr index e7d12a18a2a48..bc167cd06931e 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18f64 which cannot be represented in target type `i64` - --> $DIR/float_to_int_64_too_small2.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_small2.rs:LL:CC | LL | float_to_int_unchecked::(-9223372036854777856.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18f64 which cannot be represented in target type `i64` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(-9223372036854777856.0f64); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_small2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_small2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr index 3d8366c725b2a..60c637b02debe 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38f64 which cannot be represented in target type `i128` - --> $DIR/float_to_int_64_too_small3.rs:LL:CC + --> tests/fail/intrinsics/float_to_int_64_too_small3.rs:LL:CC | LL | float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38f64 which cannot be represented in target type `i128` @@ -7,7 +7,7 @@ LL | float_to_int_unchecked::(-240282366920938463463374607431 = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/float_to_int_64_too_small3.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/float_to_int_64_too_small3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.rs b/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.rs index eb5a16360fff8..947af681bb478 100644 --- a/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.rs +++ b/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.rs @@ -2,12 +2,7 @@ // Any new targets that are added to CI should be ignored here. // We cannot use `cfg`-based tricks here since the output would be // different for non-x86 targets. -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +//@only-target: x86_64 i686 // Explicitly disable SSE4.1 because it is enabled by default on macOS //@compile-flags: -C target-feature=-sse4.1 diff --git a/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.stderr b/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.stderr index 8e83d20854faf..a846fc5dec3ba 100644 --- a/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.stderr +++ b/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempted to call intrinsic `llvm.x86.sse41.dpps` that requires missing target feature sse4.1 - --> $DIR/intrinsic_target_feature.rs:LL:CC + --> tests/fail/intrinsics/intrinsic_target_feature.rs:LL:CC | LL | dpps(_mm_setzero_ps(), _mm_setzero_ps(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to call intrinsic `llvm.x86.sse41.dpps` that requires missing target feature sse4.1 @@ -7,7 +7,7 @@ LL | dpps(_mm_setzero_ps(), _mm_setzero_ps(), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/intrinsic_target_feature.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/intrinsic_target_feature.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr index 6478dcc2507fa..16708ec275e28 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC + --> tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC | LL | RET = PtrMetadata(*p); | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,9 +7,9 @@ LL | RET = PtrMetadata(*p); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC + = note: inside `deref_meta` at tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC note: inside `main` - --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC + --> tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC | LL | let _meta = deref_meta(p.as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index 84023cf793713..ed7acfaa1e0d4 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -1,5 +1,5 @@ warning: integer-to-pointer cast - --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC | LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast @@ -10,10 +10,10 @@ LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics = help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC | LL | RET = PtrMetadata(*p); | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -21,9 +21,9 @@ LL | RET = PtrMetadata(*p); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + = note: inside `deref_meta` at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC note: inside `main` - --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC | LL | let _meta = deref_meta(p.as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr index 0e218de0eeb5f..4e0b8d9a42991 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC + --> tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC | LL | RET = PtrMetadata(*p); | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,9 +7,9 @@ LL | RET = PtrMetadata(*p); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_thin.rs:LL:CC + = note: inside `deref_meta` at tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC note: inside `main` - --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC + --> tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC | LL | let _meta = deref_meta(p.as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr index bf36c54ac781c..7ef66390fcda0 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/ptr_offset_from_different_ints.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_from_different_ints.rs:LL:CC | LL | let _ = p1.byte_offset_from(p2); | ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let _ = p1.byte_offset_from(p2); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_offset_from_different_ints.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ptr_offset_from_different_ints.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr index e436f9029d50e..a0a8e97e7fa95 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `ptr_offset_from_unsigned` called when first pointer has smaller address than second: $ADDR < $ADDR - --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs:LL:CC | LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; | ^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller address than second: $ADDR < $ADDR @@ -7,7 +7,7 @@ LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index 8d37da6506133..c87ce321784b5 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/ptr_offset_int_plus_int.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_int_plus_int.rs:LL:CC | LL | let _val = (1 as *mut u8).offset(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let _val = (1 as *mut u8).offset(1); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ptr_offset_int_plus_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 2cd02bee2ca18..78239d501378f 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs:LL:CC | LL | let _val = (1 as *mut u8).offset(ptr as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let _val = (1 as *mut u8).offset(ptr as isize); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr index c4548200f0596..4f6b45b897b45 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation - --> $DIR/ptr_offset_out_of_bounds.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_out_of_bounds.rs:LL:CC | LL | let x = unsafe { x.offset(5) }; | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation @@ -7,12 +7,12 @@ LL | let x = unsafe { x.offset(5) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/ptr_offset_out_of_bounds.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_out_of_bounds.rs:LL:CC | LL | let v = [0i8; 4]; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/ptr_offset_out_of_bounds.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ptr_offset_out_of_bounds.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr index 8041e1542c68d..2dd4c943e864d 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation - --> $DIR/ptr_offset_out_of_bounds_neg.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs:LL:CC | LL | let x = unsafe { x.offset(-1) }; | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation @@ -7,12 +7,12 @@ LL | let x = unsafe { x.offset(-1) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/ptr_offset_out_of_bounds_neg.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs:LL:CC | LL | let v = [0i8; 4]; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/ptr_offset_out_of_bounds_neg.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr index ee5aebc6eaeef..d03c9f870e24a 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation - --> $DIR/ptr_offset_overflow.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_overflow.rs:LL:CC | LL | let x = unsafe { x.offset(isize::MIN) }; | ^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation @@ -7,12 +7,12 @@ LL | let x = unsafe { x.offset(isize::MIN) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/ptr_offset_overflow.rs:LL:CC + --> tests/fail/intrinsics/ptr_offset_overflow.rs:LL:CC | LL | let v = [0i8; 4]; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/ptr_offset_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_unsigned_overflow.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_unsigned_overflow.rs new file mode 100644 index 0000000000000..a0fa49d3d6f6b --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_unsigned_overflow.rs @@ -0,0 +1,8 @@ +fn main() { + let x = &[0i32; 2]; + let x = x.as_ptr().wrapping_add(1); + // If `usize::MAX` is interpreted as `isize`, it is just `-1` and hence harmless. + let _ = unsafe { x.byte_offset(usize::MAX as isize) }; + // However, `byte_add` uses unsigned arithmetic, so really this is `usize::MAX` and hence UB. + let _ = unsafe { x.byte_add(usize::MAX) }; //~ERROR: does not fit in an `isize` +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_unsigned_overflow.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_unsigned_overflow.stderr new file mode 100644 index 0000000000000..e03bdfdb85d47 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_unsigned_overflow.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` + --> tests/fail/intrinsics/ptr_offset_unsigned_overflow.rs:LL:CC + | +LL | let _ = unsafe { x.byte_add(usize::MAX) }; + | ^^^^^^^^^^^^^^^^^^^^^^ overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/intrinsics/ptr_offset_unsigned_overflow.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/rem-by-zero.stderr b/src/tools/miri/tests/fail/intrinsics/rem-by-zero.stderr index 9b9fe4da13998..cb5ddc80ddacf 100644 --- a/src/tools/miri/tests/fail/intrinsics/rem-by-zero.stderr +++ b/src/tools/miri/tests/fail/intrinsics/rem-by-zero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero - --> $DIR/rem-by-zero.rs:LL:CC + --> tests/fail/intrinsics/rem-by-zero.rs:LL:CC | LL | let _n = unchecked_rem(3u32, 0); | ^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero @@ -7,7 +7,7 @@ LL | let _n = unchecked_rem(3u32, 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/rem-by-zero.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs b/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs index ba474332b811c..57a9b66d8ecde 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs @@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_div; #[repr(simd)] #[allow(non_camel_case_types)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(1, 0); + let x = i32x2([1, 1]); + let y = i32x2([1, 0]); simd_div(x, y); //~ERROR: Undefined Behavior: dividing by zero } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.stderr b/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.stderr index 44d3749d68265..b3579758f8fb9 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: dividing by zero - --> $DIR/simd-div-by-zero.rs:LL:CC + --> tests/fail/intrinsics/simd-div-by-zero.rs:LL:CC | LL | simd_div(x, y); | ^^^^^^^^^^^^^^ dividing by zero @@ -7,7 +7,7 @@ LL | simd_div(x, y); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-div-by-zero.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs b/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs index d01e41de0e4be..8ffc2669828c4 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs @@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_div; #[repr(simd)] #[allow(non_camel_case_types)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); fn main() { unsafe { - let x = i32x2(1, i32::MIN); - let y = i32x2(1, -1); + let x = i32x2([1, i32::MIN]); + let y = i32x2([1, -1]); simd_div(x, y); //~ERROR: Undefined Behavior: overflow in signed division } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.stderr b/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.stderr index 85058b008eed4..1144f8cf706e7 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-div-overflow.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflow in signed division (dividing MIN by -1) - --> $DIR/simd-div-overflow.rs:LL:CC + --> tests/fail/intrinsics/simd-div-overflow.rs:LL:CC | LL | simd_div(x, y); | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) @@ -7,7 +7,7 @@ LL | simd_div(x, y); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-div-overflow.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-div-overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr b/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr index dc6b22de4925a..fdf08e8303f0a 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `simd_extract` index 4 is out-of-bounds of vector with length 4 - --> $DIR/simd-extract.rs:LL:CC + --> tests/fail/intrinsics/simd-extract.rs:LL:CC | LL | let _x: i32 = unsafe { std::intrinsics::simd::simd_extract(v, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `simd_extract` index 4 is out-of-bounds of vector with length 4 @@ -7,7 +7,7 @@ LL | let _x: i32 = unsafe { std::intrinsics::simd::simd_extract(v, 4) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-extract.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-extract.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr b/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr index d75fefe1ded24..e34ebd3d7f7a6 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `simd_cast` intrinsic called on 3.40282347E+38f32 which cannot be represented in target type `i32` - --> $DIR/simd-float-to-int.rs:LL:CC + --> tests/fail/intrinsics/simd-float-to-int.rs:LL:CC | LL | let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `simd_cast` intrinsic called on 3.40282347E+38f32 which cannot be represented in target type `i32` @@ -7,7 +7,7 @@ LL | let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unch = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-float-to-int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr index bc8d0b041d321..ee1c900961080 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes - --> $DIR/simd-gather.rs:LL:CC + --> tests/fail/intrinsics/simd-gather.rs:LL:CC | LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes @@ -7,7 +7,7 @@ LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-gather.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-gather.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs b/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs index a194f0dd18aa8..ea0f908d996ff 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs @@ -4,11 +4,11 @@ use std::intrinsics::simd::simd_reduce_any; #[repr(simd)] #[allow(non_camel_case_types)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); fn main() { unsafe { - let x = i32x2(0, 1); + let x = i32x2([0, 1]); simd_reduce_any(x); //~ERROR: must be all-0-bits or all-1-bits } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr b/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr index b6c43d34b9de4..db76897faed27 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits - --> $DIR/simd-reduce-invalid-bool.rs:LL:CC + --> tests/fail/intrinsics/simd-reduce-invalid-bool.rs:LL:CC | LL | simd_reduce_any(x); | ^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits @@ -7,7 +7,7 @@ LL | simd_reduce_any(x); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-reduce-invalid-bool.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-reduce-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs b/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs index cd1e4b8162b36..21c9520efc48a 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs @@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_rem; #[repr(simd)] #[allow(non_camel_case_types)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(1, 0); + let x = i32x2([1, 1]); + let y = i32x2([1, 0]); simd_rem(x, y); //~ERROR: Undefined Behavior: calculating the remainder with a divisor of zero } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.stderr b/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.stderr index d29d22d8aef05..ec136a62ff2c2 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero - --> $DIR/simd-rem-by-zero.rs:LL:CC + --> tests/fail/intrinsics/simd-rem-by-zero.rs:LL:CC | LL | simd_rem(x, y); | ^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero @@ -7,7 +7,7 @@ LL | simd_rem(x, y); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-rem-by-zero.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr index aae77edcb6bd7..aaacb94f458df 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes - --> $DIR/simd-scatter.rs:LL:CC + --> tests/fail/intrinsics/simd-scatter.rs:LL:CC | LL | / Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( LL | | @@ -12,12 +12,12 @@ LL | | ); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/simd-scatter.rs:LL:CC + --> tests/fail/intrinsics/simd-scatter.rs:LL:CC | LL | let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/simd-scatter.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-scatter.rs:LL:CC = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs index 96802fae49c23..409098ac3b5df 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs @@ -5,11 +5,11 @@ use std::intrinsics::simd::simd_select_bitmask; #[repr(simd)] #[allow(non_camel_case_types)] #[derive(Copy, Clone)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); fn main() { unsafe { - let x = i32x2(0, 1); + let x = i32x2([0, 1]); simd_select_bitmask(0b11111111u8, x, x); //~ERROR: bitmask less than 8 bits long must be filled with 0s for the remaining bits } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr index 1f978e13bb9b1..9acb51d8c5f36 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits - --> $DIR/simd-select-bitmask-invalid.rs:LL:CC + --> tests/fail/intrinsics/simd-select-bitmask-invalid.rs:LL:CC | LL | simd_select_bitmask(0b11111111u8, x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits @@ -7,7 +7,7 @@ LL | simd_select_bitmask(0b11111111u8, x, x); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-select-bitmask-invalid.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-select-bitmask-invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs b/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs index 388fb2e2a84ae..a81ce95ada62f 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs @@ -5,11 +5,11 @@ use std::intrinsics::simd::simd_select; #[repr(simd)] #[allow(non_camel_case_types)] #[derive(Copy, Clone)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); fn main() { unsafe { - let x = i32x2(0, 1); + let x = i32x2([0, 1]); simd_select(x, x, x); //~ERROR: must be all-0-bits or all-1-bits } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.stderr b/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.stderr index e0c0547483103..52b497046d0d0 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits - --> $DIR/simd-select-invalid-bool.rs:LL:CC + --> tests/fail/intrinsics/simd-select-invalid-bool.rs:LL:CC | LL | simd_select(x, x, x); | ^^^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits @@ -7,7 +7,7 @@ LL | simd_select(x, x, x); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-select-invalid-bool.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-select-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs b/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs index 12aa7c10af4e4..ed317254ee66c 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs @@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_shl; #[repr(simd)] #[allow(non_camel_case_types)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(100, 0); + let x = i32x2([1, 1]); + let y = i32x2([100, 0]); simd_shl(x, y); //~ERROR: overflowing shift by 100 in `simd_shl` in lane 0 } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.stderr b/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.stderr index 475067db801e2..f7dfd0743f174 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflowing shift by 100 in `simd_shl` in lane 0 - --> $DIR/simd-shl-too-far.rs:LL:CC + --> tests/fail/intrinsics/simd-shl-too-far.rs:LL:CC | LL | simd_shl(x, y); | ^^^^^^^^^^^^^^ overflowing shift by 100 in `simd_shl` in lane 0 @@ -7,7 +7,7 @@ LL | simd_shl(x, y); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-shl-too-far.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-shl-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.rs b/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.rs index ada7cf408c4ed..5d2ff1b82ed06 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.rs @@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_shr; #[repr(simd)] #[allow(non_camel_case_types)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(20, 40); + let x = i32x2([1, 1]); + let y = i32x2([20, 40]); simd_shr(x, y); //~ERROR: overflowing shift by 40 in `simd_shr` in lane 1 } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.stderr b/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.stderr index 0d6307837deb5..52259635d2170 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-shr-too-far.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflowing shift by 40 in `simd_shr` in lane 1 - --> $DIR/simd-shr-too-far.rs:LL:CC + --> tests/fail/intrinsics/simd-shr-too-far.rs:LL:CC | LL | simd_shr(x, y); | ^^^^^^^^^^^^^^ overflowing shift by 40 in `simd_shr` in lane 1 @@ -7,7 +7,7 @@ LL | simd_shr(x, y); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/simd-shr-too-far.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/simd-shr-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr index 15f01c1c095ef..20b20412e75ab 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at [0]: encountered 0x02, but expected a boolean - --> $DIR/typed-swap-invalid-array.rs:LL:CC + --> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC | LL | typed_swap(a, b); | ^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean @@ -7,9 +7,9 @@ LL | typed_swap(a, b); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `invalid_array` at $DIR/typed-swap-invalid-array.rs:LL:CC + = note: inside `invalid_array` at tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC note: inside `main` - --> $DIR/typed-swap-invalid-array.rs:LL:CC + --> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC | LL | invalid_array(); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr index 262ca202f9f47..6062465f36a6f 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean - --> $DIR/typed-swap-invalid-scalar.rs:LL:CC + --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC | LL | typed_swap(a, b); | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean @@ -7,9 +7,9 @@ LL | typed_swap(a, b); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `invalid_scalar` at $DIR/typed-swap-invalid-scalar.rs:LL:CC + = note: inside `invalid_scalar` at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC note: inside `main` - --> $DIR/typed-swap-invalid-scalar.rs:LL:CC + --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC | LL | invalid_scalar(); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_add1.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_add1.stderr index eae9ec7a44dcd..f6fe453587fc5 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_add1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_add1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: arithmetic overflow in `unchecked_add` - --> $DIR/unchecked_add1.rs:LL:CC + --> tests/fail/intrinsics/unchecked_add1.rs:LL:CC | LL | let _val = unsafe { 40000u16.unchecked_add(30000) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_add` @@ -7,7 +7,7 @@ LL | let _val = unsafe { 40000u16.unchecked_add(30000) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_add1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_add1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_add2.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_add2.stderr index 6a0dcfcd227e7..0fd1e8ff91c17 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_add2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_add2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: arithmetic overflow in `unchecked_add` - --> $DIR/unchecked_add2.rs:LL:CC + --> tests/fail/intrinsics/unchecked_add2.rs:LL:CC | LL | let _val = unsafe { (-30000i16).unchecked_add(-8000) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_add` @@ -7,7 +7,7 @@ LL | let _val = unsafe { (-30000i16).unchecked_add(-8000) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_add2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_add2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_div1.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_div1.stderr index 9dc4bcaee2f9f..f7aef4914e294 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_div1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_div1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflow in signed division (dividing MIN by -1) - --> $DIR/unchecked_div1.rs:LL:CC + --> tests/fail/intrinsics/unchecked_div1.rs:LL:CC | LL | std::intrinsics::unchecked_div(i16::MIN, -1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) @@ -7,7 +7,7 @@ LL | std::intrinsics::unchecked_div(i16::MIN, -1); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_div1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_mul1.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_mul1.stderr index e37d9827c8cf6..ad7bbaebeecae 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_mul1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: arithmetic overflow in `unchecked_mul` - --> $DIR/unchecked_mul1.rs:LL:CC + --> tests/fail/intrinsics/unchecked_mul1.rs:LL:CC | LL | let _val = unsafe { 300u16.unchecked_mul(250u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_mul` @@ -7,7 +7,7 @@ LL | let _val = unsafe { 300u16.unchecked_mul(250u16) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_mul1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_mul1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_mul2.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_mul2.stderr index 949077ce61d8c..75de5d2338dc7 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_mul2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: arithmetic overflow in `unchecked_mul` - --> $DIR/unchecked_mul2.rs:LL:CC + --> tests/fail/intrinsics/unchecked_mul2.rs:LL:CC | LL | let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_mul` @@ -7,7 +7,7 @@ LL | let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_mul2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_mul2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_shl.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_shl.stderr index f30cf4479e6be..fcf6e1aea0cd2 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_shl.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shl.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflowing shift by 8 in `unchecked_shl` - --> $DIR/unchecked_shl.rs:LL:CC + --> tests/fail/intrinsics/unchecked_shl.rs:LL:CC | LL | let _n = 1i8.unchecked_shl(8); | ^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shl` @@ -7,7 +7,7 @@ LL | let _n = 1i8.unchecked_shl(8); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_shl.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_shl.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_shl2.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_shl2.stderr index a572f34b92cdb..c38139e4c2947 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_shl2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shl2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflowing shift by -1 in `unchecked_shl` - --> $DIR/unchecked_shl2.rs:LL:CC + --> tests/fail/intrinsics/unchecked_shl2.rs:LL:CC | LL | let _n = intrinsics::unchecked_shl(1i8, -1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl` @@ -7,7 +7,7 @@ LL | let _n = intrinsics::unchecked_shl(1i8, -1); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_shl2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_shl2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_shr.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_shr.stderr index 22e0b1a0d9e32..e95227fe89fd1 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_shr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflowing shift by 64 in `unchecked_shr` - --> $DIR/unchecked_shr.rs:LL:CC + --> tests/fail/intrinsics/unchecked_shr.rs:LL:CC | LL | let _n = 1i64.unchecked_shr(64); | ^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` @@ -7,7 +7,7 @@ LL | let _n = 1i64.unchecked_shr(64); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_shr.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_sub1.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_sub1.stderr index 39bfd8a238404..fdd30186c3c8b 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_sub1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: arithmetic overflow in `unchecked_sub` - --> $DIR/unchecked_sub1.rs:LL:CC + --> tests/fail/intrinsics/unchecked_sub1.rs:LL:CC | LL | let _val = unsafe { 14u32.unchecked_sub(22) }; | ^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_sub` @@ -7,7 +7,7 @@ LL | let _val = unsafe { 14u32.unchecked_sub(22) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_sub1.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_sub1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_sub2.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_sub2.stderr index 604eba99e0147..c27bb32c9da64 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_sub2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: arithmetic overflow in `unchecked_sub` - --> $DIR/unchecked_sub2.rs:LL:CC + --> tests/fail/intrinsics/unchecked_sub2.rs:LL:CC | LL | let _val = unsafe { 30000i16.unchecked_sub(-7000) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_sub` @@ -7,7 +7,7 @@ LL | let _val = unsafe { 30000i16.unchecked_sub(-7000) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unchecked_sub2.rs:LL:CC + = note: inside `main` at tests/fail/intrinsics/unchecked_sub2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index 67fd60e572ede..ffc3a3eae9605 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -17,7 +17,7 @@ LL | ABORT(); = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` - --> $DIR/uninit_uninhabited_type.rs:LL:CC + --> tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC | LL | let _ = unsafe { std::mem::uninitialized::() }; | ^ diff --git a/src/tools/miri/tests/fail/intrinsics/write_bytes_overflow.stderr b/src/tools/miri/tests/fail/intrinsics/write_bytes_overflow.stderr index 326c180fadbac..71f53a319920b 100644 --- a/src/tools/miri/tests/fail/intrinsics/write_bytes_overflow.stderr +++ b/src/tools/miri/tests/fail/intrinsics/write_bytes_overflow.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: overflow computing total size of `write_bytes` - --> $DIR/write_bytes_overflow.rs:LL:CC + --> tests/fail/intrinsics/write_bytes_overflow.rs:LL:CC | LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `write_bytes` @@ -7,7 +7,7 @@ LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of:: $DIR/zero_fn_ptr.rs:LL:CC + --> tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC | LL | let _ = unsafe { std::mem::zeroed::() }; | ^ diff --git a/src/tools/miri/tests/fail/issue-miri-1112.stderr b/src/tools/miri/tests/fail/issue-miri-1112.stderr index 7ac65c152e952..ffbbd269216e8 100644 --- a/src/tools/miri/tests/fail/issue-miri-1112.stderr +++ b/src/tools/miri/tests/fail/issue-miri-1112.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer - --> $DIR/issue-miri-1112.rs:LL:CC + --> tests/fail/issue-miri-1112.rs:LL:CC | LL | let obj = std::mem::transmute::(obj); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer @@ -7,9 +7,9 @@ LL | let obj = std::mem::transmute::(obj) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `FunnyPointer::from_data_ptr` at $DIR/issue-miri-1112.rs:LL:CC + = note: inside `FunnyPointer::from_data_ptr` at tests/fail/issue-miri-1112.rs:LL:CC note: inside `main` - --> $DIR/issue-miri-1112.rs:LL:CC + --> tests/fail/issue-miri-1112.rs:LL:CC | LL | let _raw: &FunnyPointer = FunnyPointer::from_data_ptr(&hello, &meta as *const _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr index 4064d7fe4e953..91f9095955087 100644 --- a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr +++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr @@ -1,12 +1,12 @@ error: unsupported operation: extern static `_dispatch_queue_attr_concurrent` is not supported by Miri - --> $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC + --> tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC | LL | let _val = *DISPATCH_QUEUE_CONCURRENT; | ^^^^^^^^^^^^^^^^^^^^^^^^^ extern static `_dispatch_queue_attr_concurrent` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC + = note: inside `main` at tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/layout_cycle.stderr b/src/tools/miri/tests/fail/layout_cycle.stderr index cc343d6431fc6..9f53de3523988 100644 --- a/src/tools/miri/tests/fail/layout_cycle.stderr +++ b/src/tools/miri/tests/fail/layout_cycle.stderr @@ -13,12 +13,12 @@ LL | intrinsics::size_of::() = note: BACKTRACE: = note: inside `std::mem::size_of::>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `foo::>` - --> $DIR/layout_cycle.rs:LL:CC + --> tests/fail/layout_cycle.rs:LL:CC | LL | mem::size_of::>() | ^^^^^^^^^^^^^^^^^^^^^^ note: inside `main` - --> $DIR/layout_cycle.rs:LL:CC + --> tests/fail/layout_cycle.rs:LL:CC | LL | println!("{}", foo::>()); | ^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/memleak.rs b/src/tools/miri/tests/fail/memleak.rs index 984b44d6d4092..8ffa457be9220 100644 --- a/src/tools/miri/tests/fail/memleak.rs +++ b/src/tools/miri/tests/fail/memleak.rs @@ -1,6 +1,5 @@ -//@error-in-other-file: memory leaked //@normalize-stderr-test: ".*│.*" -> "$$stripped$$" fn main() { - std::mem::forget(Box::new(42)); + std::mem::forget(Box::new(42)); //~ERROR: memory leaked } diff --git a/src/tools/miri/tests/fail/memleak.stderr b/src/tools/miri/tests/fail/memleak.stderr index a9ee76fbe8a78..89db0f1eb1628 100644 --- a/src/tools/miri/tests/fail/memleak.stderr +++ b/src/tools/miri/tests/fail/memleak.stderr @@ -1,20 +1,11 @@ error: memory leaked: ALLOC (Rust heap, size: 4, align: 4), allocated here: - --> RUSTLIB/alloc/src/alloc.rs:LL:CC - | -LL | __rust_alloc(layout.size(), layout.align()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: BACKTRACE: - = note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::allocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::exchange_malloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::boxed::Box::::new` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `main` - --> $DIR/memleak.rs:LL:CC + --> tests/fail/memleak.rs:LL:CC | LL | std::mem::forget(Box::new(42)); | ^^^^^^^^^^^^ + | + = note: BACKTRACE: + = note: inside `main` at tests/fail/memleak.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/memleak_rc.stderr b/src/tools/miri/tests/fail/memleak_rc.stderr index dbf2daf818c6f..820e10743bc51 100644 --- a/src/tools/miri/tests/fail/memleak_rc.stderr +++ b/src/tools/miri/tests/fail/memleak_rc.stderr @@ -1,18 +1,13 @@ error: memory leaked: ALLOC (Rust heap, SIZE, ALIGN), allocated here: - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> RUSTLIB/alloc/src/rc.rs:LL:CC | -LL | __rust_alloc(layout.size(), layout.align()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::leak(Box::new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: BACKTRACE: - = note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::allocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::exchange_malloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::boxed::Box::>>>::new` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::rc::Rc::>>::new` at RUSTLIB/alloc/src/rc.rs:LL:CC note: inside `main` - --> $DIR/memleak_rc.rs:LL:CC + --> tests/fail/memleak_rc.rs:LL:CC | LL | let x = Dummy(Rc::new(RefCell::new(None))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr b/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr index 6217191711658..4c60f3be0d246 100644 --- a/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr +++ b/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/miri_start_wrong_sig.rs:LL:CC + --> tests/fail/miri_start_wrong_sig.rs:LL:CC | LL | fn miri_start() -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters diff --git a/src/tools/miri/tests/fail/modifying_constants.stderr b/src/tools/miri/tests/fail/modifying_constants.stderr index c1eca7866ad13..2d8e4dfd8a5df 100644 --- a/src/tools/miri/tests/fail/modifying_constants.stderr +++ b/src/tools/miri/tests/fail/modifying_constants.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: writing to ALLOC which is read-only - --> $DIR/modifying_constants.rs:LL:CC + --> tests/fail/modifying_constants.rs:LL:CC | LL | *y = 42; | ^^^^^^^ writing to ALLOC which is read-only @@ -7,7 +7,7 @@ LL | *y = 42; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/modifying_constants.rs:LL:CC + = note: inside `main` at tests/fail/modifying_constants.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/never_match_never.stderr b/src/tools/miri/tests/fail/never_match_never.stderr index 751894f19859a..e59a028b15b6a 100644 --- a/src/tools/miri/tests/fail/never_match_never.stderr +++ b/src/tools/miri/tests/fail/never_match_never.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/never_match_never.rs:LL:CC + --> tests/fail/never_match_never.rs:LL:CC | LL | unsafe { match (*ptr).1 {} } | ^^^^^^^^ entering unreachable code @@ -7,7 +7,7 @@ LL | unsafe { match (*ptr).1 {} } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/never_match_never.rs:LL:CC + = note: inside `main` at tests/fail/never_match_never.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/never_say_never.stderr b/src/tools/miri/tests/fail/never_say_never.stderr index 1720cc893ab45..7d2952003b217 100644 --- a/src/tools/miri/tests/fail/never_say_never.stderr +++ b/src/tools/miri/tests/fail/never_say_never.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/never_say_never.rs:LL:CC + --> tests/fail/never_say_never.rs:LL:CC | LL | f(x) | ^^^^ entering unreachable code @@ -7,7 +7,7 @@ LL | f(x) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/never_say_never.rs:LL:CC + = note: inside `main` at tests/fail/never_say_never.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/never_transmute_humans.stderr b/src/tools/miri/tests/fail/never_transmute_humans.stderr index 6916c93599506..a00c244841eef 100644 --- a/src/tools/miri/tests/fail/never_transmute_humans.stderr +++ b/src/tools/miri/tests/fail/never_transmute_humans.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/never_transmute_humans.rs:LL:CC + --> tests/fail/never_transmute_humans.rs:LL:CC | LL | std::mem::transmute::(Human) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code @@ -7,7 +7,7 @@ LL | std::mem::transmute::(Human) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/never_transmute_humans.rs:LL:CC + = note: inside `main` at tests/fail/never_transmute_humans.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/never_transmute_void.stderr b/src/tools/miri/tests/fail/never_transmute_void.stderr index 4ca306373a1e1..1906a68bffee3 100644 --- a/src/tools/miri/tests/fail/never_transmute_void.stderr +++ b/src/tools/miri/tests/fail/never_transmute_void.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/never_transmute_void.rs:LL:CC + --> tests/fail/never_transmute_void.rs:LL:CC | LL | match v.0 {} | ^^^ entering unreachable code @@ -7,9 +7,9 @@ LL | match v.0 {} = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `m::f` at $DIR/never_transmute_void.rs:LL:CC + = note: inside `m::f` at tests/fail/never_transmute_void.rs:LL:CC note: inside `main` - --> $DIR/never_transmute_void.rs:LL:CC + --> tests/fail/never_transmute_void.rs:LL:CC | LL | m::f(v); | ^^^^^^^ diff --git a/src/tools/miri/tests/fail/overlapping_assignment.stderr b/src/tools/miri/tests/fail/overlapping_assignment.stderr index 54e104e351370..0ce2e4a098195 100644 --- a/src/tools/miri/tests/fail/overlapping_assignment.stderr +++ b/src/tools/miri/tests/fail/overlapping_assignment.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges - --> $DIR/overlapping_assignment.rs:LL:CC + --> tests/fail/overlapping_assignment.rs:LL:CC | LL | *ptr1 = *ptr2; | ^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges @@ -7,9 +7,9 @@ LL | *ptr1 = *ptr2; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `self_copy` at $DIR/overlapping_assignment.rs:LL:CC + = note: inside `self_copy` at tests/fail/overlapping_assignment.rs:LL:CC note: inside `main` - --> $DIR/overlapping_assignment.rs:LL:CC + --> tests/fail/overlapping_assignment.rs:LL:CC | LL | self_copy(ptr, ptr); | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.stderr b/src/tools/miri/tests/fail/panic/bad_unwind.stderr index c08fe5153b1fc..c152d1a96058d 100644 --- a/src/tools/miri/tests/fail/panic/bad_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/bad_unwind.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/bad_unwind.rs:LL:CC: +thread 'main' panicked at tests/fail/panic/bad_unwind.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding - --> $DIR/bad_unwind.rs:LL:CC + --> tests/fail/panic/bad_unwind.rs:LL:CC | LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); | ^^^^^^^^ unwinding past a stack frame that does not allow unwinding @@ -11,12 +11,12 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside closure at $DIR/bad_unwind.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<{closure@$DIR/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try::<(), {closure@$DIR/bad_unwind.rs:LL:CC}>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<{closure@$DIR/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panic.rs:LL:CC + = note: inside closure at tests/fail/panic/bad_unwind.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<(), {closure@tests/fail/panic/bad_unwind.rs:LL:CC}>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panic.rs:LL:CC note: inside `main` - --> $DIR/bad_unwind.rs:LL:CC + --> tests/fail/panic/bad_unwind.rs:LL:CC | LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 0395fe418d93c..3e00821796eff 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -1,8 +1,8 @@ -thread 'main' panicked at $DIR/double_panic.rs:LL:CC: +thread 'main' panicked at tests/fail/panic/double_panic.rs:LL:CC: first note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -thread 'main' panicked at $DIR/double_panic.rs:LL:CC: +thread 'main' panicked at tests/fail/panic/double_panic.rs:LL:CC: second stack backtrace: thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: @@ -23,7 +23,7 @@ LL | ABORT(); = note: inside `core::panicking::panic_nounwind_nobacktrace` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_in_cleanup` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` - --> $DIR/double_panic.rs:LL:CC + --> tests/fail/panic/double_panic.rs:LL:CC | LL | / fn main() { LL | | let _foo = Foo; diff --git a/src/tools/miri/tests/fail/panic/no_std.stderr b/src/tools/miri/tests/fail/panic/no_std.stderr index 40f6cf1fc0b24..c1cd53e310f9a 100644 --- a/src/tools/miri/tests/fail/panic/no_std.stderr +++ b/src/tools/miri/tests/fail/panic/no_std.stderr @@ -1,15 +1,15 @@ -panicked at $DIR/no_std.rs:LL:CC: +panicked at tests/fail/panic/no_std.rs:LL:CC: blarg I am dead error: abnormal termination: the program aborted execution - --> $DIR/no_std.rs:LL:CC + --> tests/fail/panic/no_std.rs:LL:CC | LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_handler` at $DIR/no_std.rs:LL:CC + = note: inside `panic_handler` at tests/fail/panic/no_std.rs:LL:CC note: inside `start` - --> $DIR/no_std.rs:LL:CC + --> tests/fail/panic/no_std.rs:LL:CC | LL | panic!("blarg I am dead") | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index 6c7cac23beccb..c5f04d581ca36 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic_abort1.rs:LL:CC: +thread 'main' panicked at tests/fail/panic/panic_abort1.rs:LL:CC: panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect @@ -17,7 +17,7 @@ LL | ABORT(); = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` - --> $DIR/panic_abort1.rs:LL:CC + --> tests/fail/panic/panic_abort1.rs:LL:CC | LL | std::panic!("panicking from libstd"); | ^ diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index 1eda5449d1b65..535cddfd4d41d 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic_abort2.rs:LL:CC: +thread 'main' panicked at tests/fail/panic/panic_abort2.rs:LL:CC: 42-panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect @@ -17,7 +17,7 @@ LL | ABORT(); = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` - --> $DIR/panic_abort2.rs:LL:CC + --> tests/fail/panic/panic_abort2.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); | ^ diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index 5c7c5e17beebb..e74cf342e3f4e 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic_abort3.rs:LL:CC: +thread 'main' panicked at tests/fail/panic/panic_abort3.rs:LL:CC: panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect @@ -17,7 +17,7 @@ LL | ABORT(); = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` - --> $DIR/panic_abort3.rs:LL:CC + --> tests/fail/panic/panic_abort3.rs:LL:CC | LL | core::panic!("panicking from libcore"); | ^ diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index c8104f570f633..3983d169bdd8d 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic_abort4.rs:LL:CC: +thread 'main' panicked at tests/fail/panic/panic_abort4.rs:LL:CC: 42-panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect @@ -17,7 +17,7 @@ LL | ABORT(); = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` - --> $DIR/panic_abort4.rs:LL:CC + --> tests/fail/panic/panic_abort4.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); | ^ diff --git a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr index 778061490f04a..d93062b4bdce7 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr +++ b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr @@ -1,4 +1,4 @@ -thread $NAME panicked at $DIR/tls_macro_const_drop_panic.rs:LL:CC: +thread $NAME panicked at tests/fail/panic/tls_macro_const_drop_panic.rs:LL:CC: ow fatal runtime error: thread local panicked on drop error: abnormal termination: the program aborted execution diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr index 367e2ee1f0bc6..c0a2a30dbe139 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr +++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr @@ -1,4 +1,4 @@ -thread $NAME panicked at $DIR/tls_macro_drop_panic.rs:LL:CC: +thread $NAME panicked at tests/fail/panic/tls_macro_drop_panic.rs:LL:CC: ow fatal runtime error: thread local panicked on drop error: abnormal termination: the program aborted execution diff --git a/src/tools/miri/tests/fail/panic/unwind_panic_abort.stderr b/src/tools/miri/tests/fail/panic/unwind_panic_abort.stderr index 26afe8830cfc5..7291f5bce8d6d 100644 --- a/src/tools/miri/tests/fail/panic/unwind_panic_abort.stderr +++ b/src/tools/miri/tests/fail/panic/unwind_panic_abort.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding - --> $DIR/unwind_panic_abort.rs:LL:CC + --> tests/fail/panic/unwind_panic_abort.rs:LL:CC | LL | miri_start_unwind(&mut 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding @@ -7,7 +7,7 @@ LL | miri_start_unwind(&mut 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unwind_panic_abort.rs:LL:CC + = note: inside `main` at tests/fail/panic/unwind_panic_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.rs b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.rs new file mode 100644 index 0000000000000..fd0773ed916b7 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.rs @@ -0,0 +1,10 @@ +use std::mem; + +// Doing a copy at integer type should lose provenance. +// This tests the unoptimized base case. +fn main() { + let ptrs = [(&42, true)]; + let ints: [(usize, bool); 1] = unsafe { mem::transmute(ptrs) }; + let ptr = (&raw const ints[0].0).cast::<&i32>(); + let _val = unsafe { *ptr.read() }; //~ERROR: dangling +} diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.stderr new file mode 100644 index 0000000000000..24a8d7874077e --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) + --> tests/fail/provenance/int_copy_looses_provenance0.rs:LL:CC + | +LL | let _val = unsafe { *ptr.read() }; + | ^^^^^^^^^^ constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/provenance/int_copy_looses_provenance0.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.rs b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.rs new file mode 100644 index 0000000000000..ce64dcc1a07c4 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.rs @@ -0,0 +1,10 @@ +use std::mem; + +// Doing a copy at integer type should lose provenance. +// This tests the optimized-array case of integer copies. +fn main() { + let ptrs = [&42]; + let ints: [usize; 1] = unsafe { mem::transmute(ptrs) }; + let ptr = (&raw const ints[0]).cast::<&i32>(); + let _val = unsafe { *ptr.read() }; //~ERROR: dangling +} diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.stderr new file mode 100644 index 0000000000000..14855a723b448 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) + --> tests/fail/provenance/int_copy_looses_provenance1.rs:LL:CC + | +LL | let _val = unsafe { *ptr.read() }; + | ^^^^^^^^^^ constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/provenance/int_copy_looses_provenance1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.rs b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.rs new file mode 100644 index 0000000000000..e8966c53d7059 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.rs @@ -0,0 +1,12 @@ +use std::mem; + +// Doing a copy at integer type should lose provenance. +// This tests the case where provenacne is hiding in the metadata of a pointer. +fn main() { + let ptrs = [(&42, &42)]; + // Typed copy at wide pointer type (with integer-typed metadata). + let ints: [*const [usize]; 1] = unsafe { mem::transmute(ptrs) }; + // Get a pointer to the metadata field. + let ptr = (&raw const ints[0]).wrapping_byte_add(mem::size_of::<*const ()>()).cast::<&i32>(); + let _val = unsafe { *ptr.read() }; //~ERROR: dangling +} diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.stderr new file mode 100644 index 0000000000000..2d5b97830987b --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) + --> tests/fail/provenance/int_copy_looses_provenance2.rs:LL:CC + | +LL | let _val = unsafe { *ptr.read() }; + | ^^^^^^^^^^ constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/provenance/int_copy_looses_provenance2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.rs b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.rs new file mode 100644 index 0000000000000..d6bbfd7d94c76 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.rs @@ -0,0 +1,29 @@ +#![feature(strict_provenance)] +use std::mem; + +#[repr(C, usize)] +#[allow(unused)] +enum E { + Var1(usize), + Var2(usize), +} + +// Doing a copy at integer type should lose provenance. +// This tests the case where provenacne is hiding in the discriminant of an enum. +fn main() { + assert_eq!(mem::size_of::(), 2 * mem::size_of::()); + + // We want to store provenance in the enum discriminant, but the value still needs to + // be valid atfor the type. So we split provenance and data. + let ptr = &42; + let ptr = ptr as *const i32; + let ptrs = [(ptr.with_addr(0), ptr)]; + // Typed copy at the enum type. + let ints: [E; 1] = unsafe { mem::transmute(ptrs) }; + // Read the discriminant. + let discr = unsafe { (&raw const ints[0]).cast::<*const i32>().read() }; + // Take the provenance from there, together with the original address. + let ptr = discr.with_addr(ptr.addr()); + // There should be no provenance is `discr`, so this should be UB. + let _val = unsafe { *ptr }; //~ERROR: dangling +} diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr new file mode 100644 index 0000000000000..62e3bd2e954cf --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + --> tests/fail/provenance/int_copy_looses_provenance3.rs:LL:CC + | +LL | let _val = unsafe { *ptr }; + | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/provenance/int_copy_looses_provenance3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr index 1ca35be8cb2bd..6bc92fffd5afb 100644 --- a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr +++ b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/pointer_partial_overwrite.rs:LL:CC + --> tests/fail/provenance/pointer_partial_overwrite.rs:LL:CC | LL | let x = *p; | ^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let x = *p; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/pointer_partial_overwrite.rs:LL:CC + = note: inside `main` at tests/fail/provenance/pointer_partial_overwrite.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr index 8a1d39effbd19..7403f4382de21 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/provenance_transmute.rs:LL:CC + --> tests/fail/provenance/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; | ^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) @@ -7,9 +7,9 @@ LL | let _val = *left_ptr; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC + = note: inside `deref` at tests/fail/provenance/provenance_transmute.rs:LL:CC note: inside `main` - --> $DIR/provenance_transmute.rs:LL:CC + --> tests/fail/provenance/provenance_transmute.rs:LL:CC | LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.rs b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.rs new file mode 100644 index 0000000000000..ff94f2263c517 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.rs @@ -0,0 +1,18 @@ +fn main() { + let half_ptr = std::mem::size_of::<*const ()>() / 2; + let mut bytes = [1u8; 16]; + let bytes = bytes.as_mut_ptr(); + + unsafe { + // Put a pointer in the middle. + bytes.add(half_ptr).cast::<&i32>().write_unaligned(&42); + // Typed copy of the entire thing as two pointers, but not perfectly + // overlapping with the pointer we have in there. + let copy = bytes.cast::<[*const (); 2]>().read_unaligned(); + let copy_bytes = copy.as_ptr().cast::(); + // Now go to the middle of the copy and get the pointer back out. + let ptr = copy_bytes.add(half_ptr).cast::<*const i32>().read_unaligned(); + // Dereferencing this should fail as the copy has removed the provenance. + let _val = *ptr; //~ERROR: dangling + } +} diff --git a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr new file mode 100644 index 0000000000000..5ed83951c60a9 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + --> tests/fail/provenance/ptr_copy_loses_partial_provenance0.rs:LL:CC + | +LL | let _val = *ptr; + | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/provenance/ptr_copy_loses_partial_provenance0.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.rs b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.rs new file mode 100644 index 0000000000000..d0e3dac7792b0 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.rs @@ -0,0 +1,18 @@ +fn main() { + let half_ptr = std::mem::size_of::<*const ()>() / 2; + let mut bytes = [1u8; 16]; + let bytes = bytes.as_mut_ptr(); + + unsafe { + // Put a pointer in the middle. + bytes.add(half_ptr).cast::<&i32>().write_unaligned(&42); + // Typed copy of the entire thing as two *function* pointers, but not perfectly + // overlapping with the pointer we have in there. + let copy = bytes.cast::<[fn(); 2]>().read_unaligned(); + let copy_bytes = copy.as_ptr().cast::(); + // Now go to the middle of the copy and get the pointer back out. + let ptr = copy_bytes.add(half_ptr).cast::<*const i32>().read_unaligned(); + // Dereferencing this should fail as the copy has removed the provenance. + let _val = *ptr; //~ERROR: dangling + } +} diff --git a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr new file mode 100644 index 0000000000000..3675653cbe79a --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + --> tests/fail/provenance/ptr_copy_loses_partial_provenance1.rs:LL:CC + | +LL | let _val = *ptr; + | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/provenance/ptr_copy_loses_partial_provenance1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr index e21872244f60c..1b6518612efcc 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/ptr_int_unexposed.rs:LL:CC + --> tests/fail/provenance/ptr_int_unexposed.rs:LL:CC | LL | assert_eq!(unsafe { *ptr }, 3); | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | assert_eq!(unsafe { *ptr }, 3); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_int_unexposed.rs:LL:CC + = note: inside `main` at tests/fail/provenance/ptr_int_unexposed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr index bd0a9eb0d2910..84347ec7a11d3 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/ptr_invalid.rs:LL:CC + --> tests/fail/provenance/ptr_invalid.rs:LL:CC | LL | let _val = unsafe { *xptr_invalid }; | ^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let _val = unsafe { *xptr_invalid }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_invalid.rs:LL:CC + = note: inside `main` at tests/fail/provenance/ptr_invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr index 35e5c08300f98..3910bc4df4b08 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/ptr_invalid_offset.rs:LL:CC + --> tests/fail/provenance/ptr_invalid_offset.rs:LL:CC | LL | let _ = unsafe { roundtrip.offset(1) }; | ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let _ = unsafe { roundtrip.offset(1) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC + = note: inside `main` at tests/fail/provenance/ptr_invalid_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr index 8c61b66ac4693..ab7d8db1a3155 100644 --- a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr +++ b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr @@ -1,12 +1,12 @@ error: unsupported operation: integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance` - --> $DIR/strict_provenance_cast.rs:LL:CC + --> tests/fail/provenance/strict_provenance_cast.rs:LL:CC | LL | let _ptr = std::ptr::with_exposed_provenance::(addr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance` | = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead = note: BACKTRACE: - = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC + = note: inside `main` at tests/fail/provenance/strict_provenance_cast.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/rc_as_ptr.stderr b/src/tools/miri/tests/fail/rc_as_ptr.stderr index 83d85f8adffa2..0fcb0faf49718 100644 --- a/src/tools/miri/tests/fail/rc_as_ptr.stderr +++ b/src/tools/miri/tests/fail/rc_as_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling - --> $DIR/rc_as_ptr.rs:LL:CC + --> tests/fail/rc_as_ptr.rs:LL:CC | LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling @@ -7,12 +7,12 @@ LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/rc_as_ptr.rs:LL:CC + --> tests/fail/rc_as_ptr.rs:LL:CC | LL | let strong = Rc::new(Box::new(42)); | ^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/rc_as_ptr.rs:LL:CC + --> tests/fail/rc_as_ptr.rs:LL:CC | LL | drop(strong); | ^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr index cba8a9f84396e..921796441694a 100644 --- a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr +++ b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/reading_half_a_pointer.rs:LL:CC + --> tests/fail/reading_half_a_pointer.rs:LL:CC | LL | let _val = *x; | ^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) @@ -7,7 +7,7 @@ LL | let _val = *x; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC + = note: inside `main` at tests/fail/reading_half_a_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/rustc-error.stderr b/src/tools/miri/tests/fail/rustc-error.stderr index 3f911c172d4ef..31d9946c411f5 100644 --- a/src/tools/miri/tests/fail/rustc-error.stderr +++ b/src/tools/miri/tests/fail/rustc-error.stderr @@ -1,5 +1,5 @@ error[E0423]: expected function, found macro `println` - --> $DIR/rustc-error.rs:LL:CC + --> tests/fail/rustc-error.rs:LL:CC | LL | println("Hello, world!"); | ^^^^^^^ not a function diff --git a/src/tools/miri/tests/fail/rustc-error2.stderr b/src/tools/miri/tests/fail/rustc-error2.stderr index de2861a019c69..cfbf305d3bbfe 100644 --- a/src/tools/miri/tests/fail/rustc-error2.stderr +++ b/src/tools/miri/tests/fail/rustc-error2.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: use of undeclared crate or module `assert_mem_uninitialized_valid` - --> $DIR/rustc-error2.rs:LL:CC + --> tests/fail/rustc-error2.rs:LL:CC | LL | fn deref(&self) -> &assert_mem_uninitialized_valid::Target { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared crate or module `assert_mem_uninitialized_valid` diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.stderr index 159a02f2c0355..346cc77df1bf3 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields - --> $DIR/bad-backtrace-decl.rs:LL:CC + --> tests/fail/shims/backtrace/bad-backtrace-decl.rs:LL:CC | LL | ... miri_resolve_frame(*frame, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad declaration of miri_resolve_frame - should return a struct with 5 fields @@ -7,7 +7,7 @@ LL | ... miri_resolve_frame(*frame, 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/bad-backtrace-decl.rs:LL:CC + = note: inside `main` at tests/fail/shims/backtrace/bad-backtrace-decl.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-flags.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-flags.stderr index 504485e3b3a41..a8d531c51234b 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-flags.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-flags.stderr @@ -1,12 +1,12 @@ error: unsupported operation: unknown `miri_get_backtrace` flags 2 - --> $DIR/bad-backtrace-flags.rs:LL:CC + --> tests/fail/shims/backtrace/bad-backtrace-flags.rs:LL:CC | LL | miri_get_backtrace(2, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC + = note: inside `main` at tests/fail/shims/backtrace/bad-backtrace-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr index 523c935762ffd..7ae9558fad70a 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer - --> $DIR/bad-backtrace-ptr.rs:LL:CC + --> tests/fail/shims/backtrace/bad-backtrace-ptr.rs:LL:CC | LL | miri_resolve_frame(std::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer @@ -7,7 +7,7 @@ LL | miri_resolve_frame(std::ptr::null_mut(), 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC + = note: inside `main` at tests/fail/shims/backtrace/bad-backtrace-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr index c1f0ce3d1a8c1..d79ae1ec41495 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr @@ -1,12 +1,12 @@ error: unsupported operation: unknown `miri_resolve_frame` flags 2 - --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC + --> tests/fail/shims/backtrace/bad-backtrace-resolve-flags.rs:LL:CC | LL | miri_resolve_frame(buf[0], 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC + = note: inside `main` at tests/fail/shims/backtrace/bad-backtrace-resolve-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr index fc270593e6369..ff3176a789ba8 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -1,12 +1,12 @@ error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 - --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + --> tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.rs:LL:CC | LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + = note: inside `main` at tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr index 2d70733334d85..da287e564e379 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr @@ -1,12 +1,12 @@ error: unsupported operation: unknown `miri_backtrace_size` flags 2 - --> $DIR/bad-backtrace-size-flags.rs:LL:CC + --> tests/fail/shims/backtrace/bad-backtrace-size-flags.rs:LL:CC | LL | miri_backtrace_size(2); | ^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_backtrace_size` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/bad-backtrace-size-flags.rs:LL:CC + = note: inside `main` at tests/fail/shims/backtrace/bad-backtrace-size-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.rs b/src/tools/miri/tests/fail/shims/fs/isolated_file.rs index 2f27e95297b25..e81f0ff426023 100644 --- a/src/tools/miri/tests/fail/shims/fs/isolated_file.rs +++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: File handling is not implemented yet +//@ignore-target: windows # File handling is not implemented yet //@error-in-other-file: `open` not available when isolation is enabled fn main() { diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr index ec956f83348e3..e611d6e28f857 100644 --- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr +++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr @@ -19,7 +19,7 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC = note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC note: inside `main` - --> $DIR/isolated_file.rs:LL:CC + --> tests/fail/shims/fs/isolated_file.rs:LL:CC | LL | let _file = std::fs::File::open("file.txt").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/shims/shim_arg_size.stderr b/src/tools/miri/tests/fail/shims/shim_arg_size.stderr index b40d02ac34577..e17fe9019ff5f 100644 --- a/src/tools/miri/tests/fail/shims/shim_arg_size.stderr +++ b/src/tools/miri/tests/fail/shims/shim_arg_size.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: scalar size mismatch: expected 4 bytes but got 1 bytes instead - --> $DIR/shim_arg_size.rs:LL:CC + --> tests/fail/shims/shim_arg_size.rs:LL:CC | LL | memchr(std::ptr::null(), 0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ scalar size mismatch: expected 4 bytes but got 1 bytes instead @@ -7,7 +7,7 @@ LL | memchr(std::ptr::null(), 0, 0); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC + = note: inside `main` at tests/fail/shims/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.rs b/src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.rs index 545875a582a46..cebad507ea9d2 100644 --- a/src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -8,7 +8,7 @@ // so we have to stick to C++11 emulation from existing research. use std::sync::atomic::Ordering::*; -use std::sync::atomic::{fence, AtomicUsize}; +use std::sync::atomic::{AtomicUsize, fence}; use std::thread::spawn; // Spins until it reads the given value diff --git a/src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 966279723c495..5185845568e7c 100644 --- a/src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/cpp20_rwc_syncs.rs:LL:CC + --> tests/fail/should-pass/cpp20_rwc_syncs.rs:LL:CC | LL | std::hint::unreachable_unchecked(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code @@ -7,9 +7,9 @@ LL | std::hint::unreachable_unchecked(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC + = note: inside `test_cpp20_rwc_syncs` at tests/fail/should-pass/cpp20_rwc_syncs.rs:LL:CC note: inside `main` - --> $DIR/cpp20_rwc_syncs.rs:LL:CC + --> tests/fail/should-pass/cpp20_rwc_syncs.rs:LL:CC | LL | test_cpp20_rwc_syncs(); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr index 2a8d4f3aea0f8..f4cfa49c1564e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr @@ -1,30 +1,28 @@ error: Undefined Behavior: deallocating while item [Unique for ] is strongly protected - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> RUSTLIB/alloc/src/boxed.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [Unique for ] is strongly protected +LL | self.1.deallocate(From::from(ptr.cast()), layout); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [Unique for ] is strongly protected | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: BACKTRACE: - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure - --> $DIR/deallocate_against_protector1.rs:LL:CC + --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<{closure@$DIR/deallocate_against_protector1.rs:LL:CC} as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC + = note: inside `<{closure@tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC} as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC note: inside `inner` - --> $DIR/deallocate_against_protector1.rs:LL:CC + --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC | LL | f(x) | ^^^^ note: inside `main` - --> $DIR/deallocate_against_protector1.rs:LL:CC + --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC | LL | / inner(Box::leak(Box::new(0)), |x| { LL | | let raw = x as *mut _; diff --git a/src/tools/miri/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/src/tools/miri/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr index aa26a003f22f2..2d0209d1a2a2b 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + --> tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs:LL:CC | LL | let _val = *raw; | ^^^^ @@ -10,17 +10,17 @@ LL | let _val = *raw; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + --> tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs:LL:CC | LL | mutref as *mut i32 | ^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + --> tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs:LL:CC | LL | *base = 1; | ^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr index 5147bcd458c6f..f107ea2023dce 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/drop_in_place_protector.rs:LL:CC + --> tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC | LL | let _val = *P; | ^^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,21 +7,21 @@ LL | let _val = *P; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x1] - --> $DIR/drop_in_place_protector.rs:LL:CC + --> tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC | LL | let x = core::ptr::addr_of_mut!(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: is this argument - --> $DIR/drop_in_place_protector.rs:LL:CC + --> tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC | LL | core::ptr::drop_in_place(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `::drop` at $DIR/drop_in_place_protector.rs:LL:CC + = note: inside `::drop` at tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC = note: inside `std::ptr::drop_in_place:: - shim(Some(HasDrop))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::ptr::drop_in_place::<(HasDrop, u8)> - shim(Some((HasDrop, u8)))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC note: inside `main` - --> $DIR/drop_in_place_protector.rs:LL:CC + --> tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC | LL | core::ptr::drop_in_place(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr index 6b8465804a58f..eebedf842ef5e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr @@ -10,14 +10,14 @@ LL | pub unsafe fn drop_in_place(to_drop: *mut T) { = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x1] - --> $DIR/drop_in_place_retag.rs:LL:CC + --> tests/fail/stacked_borrows/drop_in_place_retag.rs:LL:CC | LL | let x = core::ptr::addr_of!(x); | ^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): = note: inside `std::ptr::drop_in_place:: - shim(None)` at RUSTLIB/core/src/ptr/mod.rs:LL:CC note: inside `main` - --> $DIR/drop_in_place_retag.rs:LL:CC + --> tests/fail/stacked_borrows/drop_in_place_retag.rs:LL:CC | LL | core::ptr::drop_in_place(x.cast_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.stderr b/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.stderr index 201bdcdeb9731..861dd75bb2265 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location - --> $DIR/exposed_only_ro.rs:LL:CC + --> tests/fail/stacked_borrows/exposed_only_ro.rs:LL:CC | LL | unsafe { *ptr = 0 }; | ^^^^^^^^ @@ -10,7 +10,7 @@ LL | unsafe { *ptr = 0 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: BACKTRACE: - = note: inside `main` at $DIR/exposed_only_ro.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/exposed_only_ro.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr index 2a841aa0a8d3c..1a71feee7a182 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/fnentry_invalidation.rs:LL:CC + --> tests/fail/stacked_borrows/fnentry_invalidation.rs:LL:CC | LL | let _oof = *z; | ^^ @@ -10,17 +10,17 @@ LL | let _oof = *z; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/fnentry_invalidation.rs:LL:CC + --> tests/fail/stacked_borrows/fnentry_invalidation.rs:LL:CC | LL | let z = &mut x as *mut i32; | ^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a Unique function-entry retag inside this call - --> $DIR/fnentry_invalidation.rs:LL:CC + --> tests/fail/stacked_borrows/fnentry_invalidation.rs:LL:CC | LL | x.do_bad(); | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/fnentry_invalidation.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/fnentry_invalidation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr index 42f042bfad2f1..0b5b005881ec5 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/fnentry_invalidation2.rs:LL:CC + --> tests/fail/stacked_borrows/fnentry_invalidation2.rs:LL:CC | LL | let _oof = *ptr; | ^^^^ @@ -10,17 +10,17 @@ LL | let _oof = *ptr; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0xc] - --> $DIR/fnentry_invalidation2.rs:LL:CC + --> tests/fail/stacked_borrows/fnentry_invalidation2.rs:LL:CC | LL | let ptr = t.sli.as_ptr(); | ^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0xc] by a Unique function-entry retag inside this call - --> $DIR/fnentry_invalidation2.rs:LL:CC + --> tests/fail/stacked_borrows/fnentry_invalidation2.rs:LL:CC | LL | let _ = t.sli.as_mut_ptr(); | ^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/fnentry_invalidation2.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/fnentry_invalidation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.rs b/src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.rs index b2ec23bda02c5..49df267c4c3e2 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.rs @@ -1,5 +1,4 @@ -//@error-in-other-file: /deallocation .* tag does not exist in the borrow stack/ -use std::alloc::{alloc, dealloc, Layout}; +use std::alloc::{Layout, alloc, dealloc}; fn main() { unsafe { @@ -10,5 +9,6 @@ fn main() { ptr1.write(0); // Deallocate through ptr2. dealloc(ptr2, Layout::from_size_align_unchecked(1, 1)); + //~^ERROR: /deallocation .* tag does not exist in the borrow stack/ } } diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.stderr index 7a44c8384a063..ddf8dbea31f59 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.stderr @@ -1,28 +1,23 @@ error: Undefined Behavior: attempting deallocation using at ALLOC, but that tag does not exist in the borrow stack for this location - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_deALLOC.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempting deallocation using at ALLOC, but that tag does not exist in the borrow stack for this location +LL | dealloc(ptr2, Layout::from_size_align_unchecked(1, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempting deallocation using at ALLOC, but that tag does not exist in the borrow stack for this location | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x1] - --> $DIR/illegal_deALLOC.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_deALLOC.rs:LL:CC | LL | let ptr2 = (&mut *ptr1) as *mut u8; | ^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x1] by a write access - --> $DIR/illegal_deALLOC.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_deALLOC.rs:LL:CC | LL | ptr1.write(0); | ^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `main` - --> $DIR/illegal_deALLOC.rs:LL:CC - | -LL | dealloc(ptr2, Layout::from_size_align_unchecked(1, 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at tests/fail/stacked_borrows/illegal_deALLOC.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read1.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read1.stderr index 2dfb660c53c69..bc719f9f205d0 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read1.rs:LL:CC | LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | ^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/illegal_read1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read1.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... | ^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> $DIR/illegal_read1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read1.rs:LL:CC | LL | let _val = unsafe { *xraw }; | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read1.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read2.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read2.stderr index ce3b920c1dcbb..d1bca88d05bc0 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read2.rs:LL:CC | LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | ^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/illegal_read2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read2.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... | ^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a SharedReadOnly retag - --> $DIR/illegal_read2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read2.rs:LL:CC | LL | let shr = unsafe { &*xraw }; | ^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read2.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read3.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read3.stderr index 2c81fda1411e1..6a6701aae1945 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read3.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read3.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read3.rs:LL:CC | LL | let _val = *xref2; | ^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *xref2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/illegal_read3.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read3.rs:LL:CC | LL | let xref2 = &mut *xref1; | ^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> $DIR/illegal_read3.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read3.rs:LL:CC | LL | let _val = unsafe { *xref1.r }; | ^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read3.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read4.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read4.stderr index 98bfd56cd3ce3..0d460df3929a5 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read4.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read4.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read4.rs:LL:CC | LL | let _illegal = *xref2; | ^^^^^^ @@ -10,17 +10,17 @@ LL | let _illegal = *xref2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/illegal_read4.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read4.rs:LL:CC | LL | let xref2 = unsafe { &mut *xraw }; | ^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> $DIR/illegal_read4.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read4.rs:LL:CC | LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read4.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read5.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read5.stderr index e3b18e7d4f81f..9862d8a1a34fe 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read5.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read5.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read5.rs:LL:CC | LL | let _val = *xref; // the mutable one is dead and gone | ^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *xref; // the mutable one is dead and gone = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [$HEX..$HEX] - --> $DIR/illegal_read5.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read5.rs:LL:CC | LL | let xref: &mut i32 = &mut *refmut; | ^^^^^^^^^^^^ help: was later invalidated at offsets [$HEX..$HEX] by a read access - --> $DIR/illegal_read5.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read5.rs:LL:CC | LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref | ^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read5.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read6.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read6.stderr index 415a85bd68c51..31c5ad160a9d6 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read6.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read6.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read6.rs:LL:CC | LL | let _val = *raw; | ^^^^ @@ -10,17 +10,17 @@ LL | let _val = *raw; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/illegal_read6.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read6.rs:LL:CC | LL | let raw = x as *mut _; | ^ help: was later invalidated at offsets [0x0..0x4] by a Unique retag - --> $DIR/illegal_read6.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read6.rs:LL:CC | LL | let x = &mut *x; // kill `raw` | ^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read6.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read7.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read7.stderr index 248ae62d5ebe2..4ae41dd8ee637 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read7.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read7.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read7.rs:LL:CC | LL | let _val = *x.get_mut(); | ^ @@ -10,17 +10,17 @@ LL | let _val = *x.get_mut(); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/illegal_read7.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read7.rs:LL:CC | LL | let x = &mut *raw; | ^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> $DIR/illegal_read7.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read7.rs:LL:CC | LL | let _val = ptr::read(raw); | ^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read7.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read8.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read8.stderr index fd5ed383f1a6b..fc07c3174ba00 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read8.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read8.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read8.rs:LL:CC | LL | let _fail = *y1; | ^^^ @@ -10,17 +10,17 @@ LL | let _fail = *y1; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/illegal_read8.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read8.rs:LL:CC | LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes | ^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/illegal_read8.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read8.rs:LL:CC | LL | *y2 += 1; | ^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read8.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read8.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr index 33fcd11ff7a5f..18a47bb34621f 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs:LL:CC | LL | let _val = *root2; | ^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *root2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs:LL:CC | LL | let root2 = &mut *exposed_ptr; | ^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs:LL:CC | LL | *exposed_ptr = 0; | ^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr index a948c5df1661e..245bce199389e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs:LL:CC | LL | let _val = *root2; | ^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *root2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs:LL:CC | LL | let root2 = &mut *exposed_ptr; | ^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs:LL:CC | LL | let _val = *exposed_ptr; | ^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.stderr index 65b4fc5f3fa06..595d0ca758800 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_write2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write2.rs:LL:CC | LL | unsafe { *target2 = 13 }; | ^^^^^^^^^^^^^ @@ -10,17 +10,17 @@ LL | unsafe { *target2 = 13 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/illegal_write2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write2.rs:LL:CC | LL | let target2 = target as *mut _; | ^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a Unique retag - --> $DIR/illegal_write2.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write2.rs:LL:CC | LL | drop(&mut *target); // reborrow | ^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_write2.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_write2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_write3.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_write3.stderr index 08d9f33a1699d..6805b359367e1 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_write3.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - --> $DIR/illegal_write3.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write3.rs:LL:CC | LL | unsafe { *ptr = 42 }; | ^^^^^^^^^ @@ -10,12 +10,12 @@ LL | unsafe { *ptr = 42 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/illegal_write3.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write3.rs:LL:CC | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_write3.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_write3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_write4.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_write4.stderr index 4ee5ec3853958..0134987caf3a9 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_write4.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_write4.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write4.rs:LL:CC | LL | let _val = *reference; | ^^^^^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *reference; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/illegal_write4.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write4.rs:LL:CC | LL | let reference = unsafe { &*raw }; // freeze | ^^^^^ help: was later invalidated at offsets [0x0..0x4] by a Unique retag - --> $DIR/illegal_write4.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write4.rs:LL:CC | LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag | ^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_write4.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_write4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr b/src/tools/miri/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr index 70e9038bab3fb..42e088dc075e2 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs:LL:CC | LL | let _val = *root2; | ^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *root2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs:LL:CC | LL | let root2 = &*exposed_ptr; | ^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + --> tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs:LL:CC | LL | *exposed_ptr = 0; | ^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/interior_mut1.stderr b/src/tools/miri/tests/fail/stacked_borrows/interior_mut1.stderr index f8bc1667ddb15..3d43bf7e6bf31 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/interior_mut1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/interior_mut1.rs:LL:CC + --> tests/fail/stacked_borrows/interior_mut1.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *inner_shr.get(); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/interior_mut1.rs:LL:CC + --> tests/fail/stacked_borrows/interior_mut1.rs:LL:CC | LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite | ^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/interior_mut1.rs:LL:CC + --> tests/fail/stacked_borrows/interior_mut1.rs:LL:CC | LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/interior_mut1.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/interior_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/interior_mut2.stderr b/src/tools/miri/tests/fail/stacked_borrows/interior_mut2.stderr index a69fc6ff8bab1..a7a1521bd63ad 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/interior_mut2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/interior_mut2.rs:LL:CC + --> tests/fail/stacked_borrows/interior_mut2.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *inner_shr.get(); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/interior_mut2.rs:LL:CC + --> tests/fail/stacked_borrows/interior_mut2.rs:LL:CC | LL | let inner_shr = &*inner_uniq; | ^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> $DIR/interior_mut2.rs:LL:CC + --> tests/fail/stacked_borrows/interior_mut2.rs:LL:CC | LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/interior_mut2.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/interior_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr b/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr index 96cdce5a778b4..5956a3f675314 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected - --> $DIR/invalidate_against_protector1.rs:LL:CC + --> tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC | LL | let _val = unsafe { *x }; | ^^ not granting access to tag because that would remove [Unique for ] which is strongly protected @@ -7,19 +7,19 @@ LL | let _val = unsafe { *x }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/invalidate_against_protector1.rs:LL:CC + --> tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ help: is this argument - --> $DIR/invalidate_against_protector1.rs:LL:CC + --> tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC | LL | fn inner(x: *mut i32, _y: &mut i32) { | ^^ = note: BACKTRACE (of the first span): - = note: inside `inner` at $DIR/invalidate_against_protector1.rs:LL:CC + = note: inside `inner` at tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC note: inside `main` - --> $DIR/invalidate_against_protector1.rs:LL:CC + --> tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC | LL | inner(xraw, xref); | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/load_invalid_mut.stderr b/src/tools/miri/tests/fail/stacked_borrows/load_invalid_mut.stderr index 9d707c3f85d58..733162acff793 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/load_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/load_invalid_mut.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *xref_in_mem; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/load_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/load_invalid_mut.rs:LL:CC | LL | let xref_in_mem = Box::new(xref); | ^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> $DIR/load_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/load_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/load_invalid_mut.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/load_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/src/tools/miri/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 0a017e182644f..c910a05de1c5e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/pass_invalid_mut.rs:LL:CC | LL | foo(xref); | ^^^^ @@ -10,17 +10,17 @@ LL | foo(xref); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/pass_invalid_mut.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/pass_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/pass_invalid_mut.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/pass_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr b/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr index 1fddcaf3dad0b..58c6cd4c31811 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/pointer_smuggling.rs:LL:CC + --> tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC | LL | let _x = unsafe { *PTR }; | ^^^^ @@ -10,19 +10,19 @@ LL | let _x = unsafe { *PTR }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x1] - --> $DIR/pointer_smuggling.rs:LL:CC + --> tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC | LL | PTR = x; | ^ help: was later invalidated at offsets [0x0..0x1] by a write access - --> $DIR/pointer_smuggling.rs:LL:CC + --> tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. | ^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `fun2` at $DIR/pointer_smuggling.rs:LL:CC + = note: inside `fun2` at tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC note: inside `main` - --> $DIR/pointer_smuggling.rs:LL:CC + --> tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC | LL | fun2(); // if they now use a raw ptr they break our reference | ^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/raw_tracking.stderr b/src/tools/miri/tests/fail/stacked_borrows/raw_tracking.stderr index 0d07d154ba5b2..aa320ea908c01 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/raw_tracking.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/raw_tracking.rs:LL:CC + --> tests/fail/stacked_borrows/raw_tracking.rs:LL:CC | LL | unsafe { *raw1 = 13 }; | ^^^^^^^^^^ @@ -10,17 +10,17 @@ LL | unsafe { *raw1 = 13 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/raw_tracking.rs:LL:CC + --> tests/fail/stacked_borrows/raw_tracking.rs:LL:CC | LL | let raw1 = &mut l as *mut _; | ^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a Unique retag - --> $DIR/raw_tracking.rs:LL:CC + --> tests/fail/stacked_borrows/raw_tracking.rs:LL:CC | LL | let raw2 = &mut l as *mut _; // invalidates raw1 | ^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/raw_tracking.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/raw_tracking.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr index 47ae4b5d46d6f..fd5d83211db81 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `main` and (2) retag write of type `i32` on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/retag_data_race_protected_read.rs:LL:CC + --> tests/fail/stacked_borrows/retag_data_race_protected_read.rs:LL:CC | LL | retag(unsafe { &mut *ptr.0 }); | ^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `main` and (2) retag write of type `i32` on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/retag_data_race_protected_read.rs:LL:CC + --> tests/fail/stacked_borrows/retag_data_race_protected_read.rs:LL:CC | LL | unsafe { ptr.0.read() }; | ^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | unsafe { ptr.0.read() }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/retag_data_race_protected_read.rs:LL:CC + = note: inside closure at tests/fail/stacked_borrows/retag_data_race_protected_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr index 9fe9fbeda449a..87155ebc51827 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/retag_data_race_read.rs:LL:CC + --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC | LL | *p = 5; | ^^^^^^ Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/retag_data_race_read.rs:LL:CC + --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC | LL | let _r = &*p; | ^^^ @@ -15,9 +15,9 @@ LL | let _r = &*p; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `thread_2` at $DIR/retag_data_race_read.rs:LL:CC + = note: inside `thread_2` at tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC note: inside closure - --> $DIR/retag_data_race_read.rs:LL:CC + --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); | ^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr index 78008e92642cd..760ed783175f8 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC | LL | ret | ^^^ @@ -10,19 +10,19 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x4..0x8] - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC | LL | let ret = unsafe { &mut (*xraw).1 }; | ^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x8] by a read access - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_mut.rs:LL:CC + = note: inside `foo` at tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC | LL | foo(&mut (1, 2)); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index b9ae34df0775c..3175e09962062 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - --> $DIR/return_invalid_mut_option.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC | LL | ret | ^^^ @@ -11,19 +11,19 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x4..0x8] - --> $DIR/return_invalid_mut_option.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC | LL | let ret = Some(ret); | ^^^^^^^^^ help: was later invalidated at offsets [0x0..0x8] by a read access - --> $DIR/return_invalid_mut_option.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_mut_option.rs:LL:CC + = note: inside `foo` at tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_mut_option.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC | LL | match foo(&mut (1, 2)) { | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index 7522115c5166b..2cc3ba2c9a94b 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - --> $DIR/return_invalid_mut_tuple.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC | LL | ret | ^^^ @@ -11,19 +11,19 @@ LL | ret = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x4..0x8] - --> $DIR/return_invalid_mut_tuple.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC | LL | let ret = (unsafe { &mut (*xraw).1 },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x8] by a read access - --> $DIR/return_invalid_mut_tuple.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/return_invalid_mut_tuple.rs:LL:CC + = note: inside `foo` at tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC note: inside `main` - --> $DIR/return_invalid_mut_tuple.rs:LL:CC + --> tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/src/tools/miri/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index b5106c9d94047..56d9783367bad 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + --> tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs:LL:CC | LL | y.get_mut(); | ^ @@ -10,17 +10,17 @@ LL | y.get_mut(); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + --> tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs:LL:CC | LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime | ^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a Unique retag - --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + --> tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs:LL:CC | LL | shr_rw.set(1); | ^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/src/tools/miri/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index ccea83db8574e..8ca56afc12194 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location - --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + --> tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs:LL:CC | LL | let _val = *y; | ^^ @@ -10,17 +10,17 @@ LL | let _val = *y; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [$HEX..$HEX] - --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + --> tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs:LL:CC | LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [$HEX..$HEX] by a Unique retag - --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + --> tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs:LL:CC | LL | shr_rw.replace(1); | ^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/static_memory_modification.stderr b/src/tools/miri/tests/fail/stacked_borrows/static_memory_modification.stderr index f605fa9d3b962..b86a64623ba75 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/static_memory_modification.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/static_memory_modification.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: writing to ALLOC which is read-only - --> $DIR/static_memory_modification.rs:LL:CC + --> tests/fail/stacked_borrows/static_memory_modification.rs:LL:CC | LL | std::mem::transmute::<&usize, &mut usize>(&X) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only @@ -7,7 +7,7 @@ LL | std::mem::transmute::<&usize, &mut usize>(&X) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/static_memory_modification.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/static_memory_modification.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/track_caller.stderr b/src/tools/miri/tests/fail/stacked_borrows/track_caller.stderr index f341222a664c3..163ec84281df0 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/track_caller.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/track_caller.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/track_caller.rs:LL:CC + --> tests/fail/stacked_borrows/track_caller.rs:LL:CC | LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | ^^^^^ @@ -10,17 +10,17 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/track_caller.rs:LL:CC + --> tests/fail/stacked_borrows/track_caller.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... | ^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> $DIR/track_caller.rs:LL:CC + --> tests/fail/stacked_borrows/track_caller.rs:LL:CC | LL | callee(xraw); | ^^^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/track_caller.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/track_caller.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/src/tools/miri/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index 7d8132b85c89e..becd6681eca4b 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/transmute-is-no-escape.rs:LL:CC + --> tests/fail/stacked_borrows/transmute-is-no-escape.rs:LL:CC | LL | unsafe { *raw = 13 }; | ^^^^^^^^^ @@ -10,12 +10,12 @@ LL | unsafe { *raw = 13 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x4..0x8] - --> $DIR/transmute-is-no-escape.rs:LL:CC + --> tests/fail/stacked_borrows/transmute-is-no-escape.rs:LL:CC | LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/transmute-is-no-escape.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/unescaped_local.stderr b/src/tools/miri/tests/fail/stacked_borrows/unescaped_local.stderr index 50c02b3455e4f..08c2cf2099b55 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/unescaped_local.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location - --> $DIR/unescaped_local.rs:LL:CC + --> tests/fail/stacked_borrows/unescaped_local.rs:LL:CC | LL | *raw = 13; | ^^^^^^^^^ @@ -10,7 +10,7 @@ LL | *raw = 13; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unescaped_local.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/unescaped_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/unescaped_static.stderr b/src/tools/miri/tests/fail/stacked_borrows/unescaped_static.stderr index 7578b89708a82..fb48edc5dddf5 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/unescaped_static.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location - --> $DIR/unescaped_static.rs:LL:CC + --> tests/fail/stacked_borrows/unescaped_static.rs:LL:CC | LL | let _val = unsafe { *ptr_to_first.add(1) }; | ^^^^^^^^^^^^^^^^^^^^ @@ -10,12 +10,12 @@ LL | let _val = unsafe { *ptr_to_first.add(1) }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x1] - --> $DIR/unescaped_static.rs:LL:CC + --> tests/fail/stacked_borrows/unescaped_static.rs:LL:CC | LL | let ptr_to_first = &ARRAY[0] as *const u8; | ^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/unescaped_static.rs:LL:CC + = note: inside `main` at tests/fail/stacked_borrows/unescaped_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/zst_slice.stderr b/src/tools/miri/tests/fail/stacked_borrows/zst_slice.stderr index acae479ced28e..01e3c60f0fe38 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/zst_slice.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/zst_slice.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - --> $DIR/zst_slice.rs:LL:CC + --> tests/fail/stacked_borrows/zst_slice.rs:LL:CC | LL | assert_eq!(*s.as_ptr().add(1), 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | assert_eq!(*s.as_ptr().add(1), 2); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: would have been created here, but this is a zero-size retag ([0x0..0x0]) so the tag in question does not exist anywhere - --> $DIR/zst_slice.rs:LL:CC + --> tests/fail/stacked_borrows/zst_slice.rs:LL:CC | LL | assert_eq!(*s.as_ptr().add(1), 2); | ^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/static_memory_modification1.stderr b/src/tools/miri/tests/fail/static_memory_modification1.stderr index 877cf1d6e4739..2b2cd4af3da05 100644 --- a/src/tools/miri/tests/fail/static_memory_modification1.stderr +++ b/src/tools/miri/tests/fail/static_memory_modification1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: writing to ALLOC which is read-only - --> $DIR/static_memory_modification1.rs:LL:CC + --> tests/fail/static_memory_modification1.rs:LL:CC | LL | *std::mem::transmute::<&usize, &mut usize>(&X) = 6; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only @@ -7,7 +7,7 @@ LL | *std::mem::transmute::<&usize, &mut usize>(&X) = 6; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/static_memory_modification1.rs:LL:CC + = note: inside `main` at tests/fail/static_memory_modification1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/static_memory_modification2.stderr b/src/tools/miri/tests/fail/static_memory_modification2.stderr index 77bbace4696b1..99c7f15d9ffcf 100644 --- a/src/tools/miri/tests/fail/static_memory_modification2.stderr +++ b/src/tools/miri/tests/fail/static_memory_modification2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: writing to ALLOC which is read-only - --> $DIR/static_memory_modification2.rs:LL:CC + --> tests/fail/static_memory_modification2.rs:LL:CC | LL | transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only @@ -7,7 +7,7 @@ LL | transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/static_memory_modification2.rs:LL:CC + = note: inside `main` at tests/fail/static_memory_modification2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/static_memory_modification3.stderr b/src/tools/miri/tests/fail/static_memory_modification3.stderr index a04609805cb84..cb37a2a2dab9a 100644 --- a/src/tools/miri/tests/fail/static_memory_modification3.stderr +++ b/src/tools/miri/tests/fail/static_memory_modification3.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: writing to ALLOC which is read-only - --> $DIR/static_memory_modification3.rs:LL:CC + --> tests/fail/static_memory_modification3.rs:LL:CC | LL | transmute::<&[u8], &mut [u8]>(bs)[4] = 42; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only @@ -7,7 +7,7 @@ LL | transmute::<&[u8], &mut [u8]>(bs)[4] = 42; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/static_memory_modification3.rs:LL:CC + = note: inside `main` at tests/fail/static_memory_modification3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/storage-live-dead-var.stderr b/src/tools/miri/tests/fail/storage-live-dead-var.stderr index ccc77b1c978dc..f370c28483137 100644 --- a/src/tools/miri/tests/fail/storage-live-dead-var.stderr +++ b/src/tools/miri/tests/fail/storage-live-dead-var.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing a dead local variable - --> $DIR/storage-live-dead-var.rs:LL:CC + --> tests/fail/storage-live-dead-var.rs:LL:CC | LL | val = 42; | ^^^^^^^^ accessing a dead local variable @@ -7,7 +7,7 @@ LL | val = 42; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/storage-live-dead-var.rs:LL:CC + = note: inside `main` at tests/fail/storage-live-dead-var.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/storage-live-resets-var.stderr b/src/tools/miri/tests/fail/storage-live-resets-var.stderr index 07d39cc9d6b3f..099dd3a1f7e7b 100644 --- a/src/tools/miri/tests/fail/storage-live-resets-var.stderr +++ b/src/tools/miri/tests/fail/storage-live-resets-var.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered uninitialized memory, but expected an integer - --> $DIR/storage-live-resets-var.rs:LL:CC + --> tests/fail/storage-live-resets-var.rs:LL:CC | LL | _val2 = val; | ^^^^^^^^^^^ constructing invalid value: encountered uninitialized memory, but expected an integer @@ -7,7 +7,7 @@ LL | _val2 = val; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/storage-live-resets-var.rs:LL:CC + = note: inside `main` at tests/fail/storage-live-resets-var.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr index 8823ab9b97059..db8ab7cb46022 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 - --> $DIR/signature-mismatch-arg.rs:LL:CC + --> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC | LL | f(0); | ^^^^ calling a function with argument of type i32 passing data of type u32 @@ -9,7 +9,7 @@ LL | f(0); = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri = note: BACKTRACE: - = note: inside `main` at $DIR/signature-mismatch-arg.rs:LL:CC + = note: inside `main` at tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index 6384689c56357..e1c0fabd03d38 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -1,6 +1,6 @@ warning: You have explicitly enabled MIR optimizations, overriding Miri's default which is to completely disable them. Any optimizations may hide UB that Miri would otherwise detect, and it is not necessarily possible to predict what kind of UB will be missed. If you are enabling optimizations to make Miri run faster, we advise using cfg(miri) to shrink your workload instead. The performance benefit of enabling MIR optimizations is usually marginal at best. -thread 'main' panicked at $DIR/terminate-terminator.rs:LL:CC: +thread 'main' panicked at tests/fail/terminate-terminator.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect @@ -23,7 +23,7 @@ LL | ABORT(); = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `has_cleanup` - --> $DIR/terminate-terminator.rs:LL:CC + --> tests/fail/terminate-terminator.rs:LL:CC | LL | / fn has_cleanup() { LL | | let _f = Foo; @@ -31,12 +31,12 @@ LL | | panic!(); LL | | } | |_^ note: inside `panic_abort` - --> $DIR/terminate-terminator.rs:LL:CC + --> tests/fail/terminate-terminator.rs:LL:CC | LL | has_cleanup(); | ^ note: inside `main` - --> $DIR/terminate-terminator.rs:LL:CC + --> tests/fail/terminate-terminator.rs:LL:CC | LL | panic_abort(); | ^ diff --git a/src/tools/miri/tests/fail/tls/tls_static_dealloc.stderr b/src/tools/miri/tests/fail/tls/tls_static_dealloc.stderr index a49933b7d0574..3a45dbfb58331 100644 --- a/src/tools/miri/tests/fail/tls/tls_static_dealloc.stderr +++ b/src/tools/miri/tests/fail/tls/tls_static_dealloc.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/tls_static_dealloc.rs:LL:CC + --> tests/fail/tls/tls_static_dealloc.rs:LL:CC | LL | let _val = *dangling_ptr.0; | ^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling @@ -7,7 +7,7 @@ LL | let _val = *dangling_ptr.0; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/tls_static_dealloc.rs:LL:CC + = note: inside `main` at tests/fail/tls/tls_static_dealloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tls_macro_leak.rs b/src/tools/miri/tests/fail/tls_macro_leak.rs index 996d7ed4a2360..b8a4b81911aca 100644 --- a/src/tools/miri/tests/fail/tls_macro_leak.rs +++ b/src/tools/miri/tests/fail/tls_macro_leak.rs @@ -1,4 +1,3 @@ -//@error-in-other-file: memory leaked //@normalize-stderr-test: ".*│.*" -> "$$stripped$$" use std::cell::Cell; @@ -10,7 +9,7 @@ pub fn main() { std::thread::spawn(|| { TLS.with(|cell| { - cell.set(Some(Box::leak(Box::new(123)))); + cell.set(Some(Box::leak(Box::new(123)))); //~ERROR: memory leaked }); }) .join() diff --git a/src/tools/miri/tests/fail/tls_macro_leak.stderr b/src/tools/miri/tests/fail/tls_macro_leak.stderr index c7c641a30f1bd..512932b3cb8a6 100644 --- a/src/tools/miri/tests/fail/tls_macro_leak.stderr +++ b/src/tools/miri/tests/fail/tls_macro_leak.stderr @@ -1,24 +1,15 @@ error: memory leaked: ALLOC (Rust heap, size: 4, align: 4), allocated here: - --> RUSTLIB/alloc/src/alloc.rs:LL:CC - | -LL | __rust_alloc(layout.size(), layout.align()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: BACKTRACE: - = note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::allocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::exchange_malloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::boxed::Box::::new` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside closure - --> $DIR/tls_macro_leak.rs:LL:CC + --> tests/fail/tls_macro_leak.rs:LL:CC | LL | cell.set(Some(Box::leak(Box::new(123)))); | ^^^^^^^^^^^^^ - = note: inside `std::thread::LocalKey::>>::try_with::<{closure@$DIR/tls_macro_leak.rs:LL:CC}, ()>` at RUSTLIB/std/src/thread/local.rs:LL:CC - = note: inside `std::thread::LocalKey::>>::with::<{closure@$DIR/tls_macro_leak.rs:LL:CC}, ()>` at RUSTLIB/std/src/thread/local.rs:LL:CC + | + = note: BACKTRACE: + = note: inside closure at tests/fail/tls_macro_leak.rs:LL:CC + = note: inside `std::thread::LocalKey::>>::try_with::<{closure@tests/fail/tls_macro_leak.rs:LL:CC}, ()>` at RUSTLIB/std/src/thread/local.rs:LL:CC + = note: inside `std::thread::LocalKey::>>::with::<{closure@tests/fail/tls_macro_leak.rs:LL:CC}, ()>` at RUSTLIB/std/src/thread/local.rs:LL:CC note: inside closure - --> $DIR/tls_macro_leak.rs:LL:CC + --> tests/fail/tls_macro_leak.rs:LL:CC | LL | / TLS.with(|cell| { LL | | cell.set(Some(Box::leak(Box::new(123)))); diff --git a/src/tools/miri/tests/fail/tls_static_leak.rs b/src/tools/miri/tests/fail/tls_static_leak.rs index 637d648fb3fbf..4d52803363778 100644 --- a/src/tools/miri/tests/fail/tls_static_leak.rs +++ b/src/tools/miri/tests/fail/tls_static_leak.rs @@ -1,4 +1,3 @@ -//@error-in-other-file: memory leaked //@normalize-stderr-test: ".*│.*" -> "$$stripped$$" #![feature(thread_local)] @@ -12,7 +11,7 @@ pub fn main() { static TLS: Cell> = Cell::new(None); std::thread::spawn(|| { - TLS.set(Some(Box::leak(Box::new(123)))); + TLS.set(Some(Box::leak(Box::new(123)))); //~ERROR: memory leaked }) .join() .unwrap(); diff --git a/src/tools/miri/tests/fail/tls_static_leak.stderr b/src/tools/miri/tests/fail/tls_static_leak.stderr index f7b90a1118c85..24306cca7ffdd 100644 --- a/src/tools/miri/tests/fail/tls_static_leak.stderr +++ b/src/tools/miri/tests/fail/tls_static_leak.stderr @@ -1,20 +1,11 @@ error: memory leaked: ALLOC (Rust heap, size: 4, align: 4), allocated here: - --> RUSTLIB/alloc/src/alloc.rs:LL:CC - | -LL | __rust_alloc(layout.size(), layout.align()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: BACKTRACE: - = note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::allocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::exchange_malloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::boxed::Box::::new` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside closure - --> $DIR/tls_static_leak.rs:LL:CC + --> tests/fail/tls_static_leak.rs:LL:CC | LL | TLS.set(Some(Box::leak(Box::new(123)))); | ^^^^^^^^^^^^^ + | + = note: BACKTRACE: + = note: inside closure at tests/fail/tls_static_leak.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.rs b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.rs index 122a8ff8752c5..fee88cf3486af 100644 --- a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.rs @@ -13,7 +13,8 @@ pub fn main() { // This time y gets Frozen... let _val = *x; // ... and the next Write attempt fails. - *y += 1; // Failure //~ ERROR: /write access through .* is forbidden/ + //~v ERROR: /write access through .* is forbidden/ + *y += 1; // Failure let _val = *x; *y += 1; // Unreachable } diff --git a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr index bd969d089c37a..1294b52c05189 100644 --- a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/alternate-read-write.rs:LL:CC + --> tests/fail/tree_borrows/alternate-read-write.rs:LL:CC | LL | *y += 1; // Failure | ^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,24 +7,24 @@ LL | *y += 1; // Failure = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Frozen which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/alternate-read-write.rs:LL:CC + --> tests/fail/tree_borrows/alternate-read-write.rs:LL:CC | LL | let y = unsafe { &mut *(x as *mut u8) }; | ^^^^^^^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Active due to a child write access at offsets [0x0..0x1] - --> $DIR/alternate-read-write.rs:LL:CC + --> tests/fail/tree_borrows/alternate-read-write.rs:LL:CC | LL | *y += 1; // Success | ^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference help: the accessed tag later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1] - --> $DIR/alternate-read-write.rs:LL:CC + --> tests/fail/tree_borrows/alternate-read-write.rs:LL:CC | LL | let _val = *x; | ^^ = help: this transition corresponds to a loss of write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/alternate-read-write.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/alternate-read-write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr index 87286f1a1a62a..b9651e21ecece 100644 --- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/children-can-alias.rs:LL:CC + --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC | LL | std::hint::unreachable_unchecked(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code @@ -7,7 +7,7 @@ LL | std::hint::unreachable_unchecked(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/children-can-alias.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/children-can-alias.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs index b5a01cd4324e2..036267dc11e9d 100644 --- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs +++ b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs @@ -8,8 +8,8 @@ #![feature(ptr_internals)] -use core::ptr::addr_of_mut; use core::ptr::Unique; +use core::ptr::addr_of_mut; fn main() { let mut data = 0u8; diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr index cdfa8a74238a4..83c506abb2d73 100644 --- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/children-can-alias.rs:LL:CC + --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC | LL | child2.write(2); | ^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,20 +7,20 @@ LL | child2.write(2); = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/children-can-alias.rs:LL:CC + --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC | LL | let child2 = x.as_ptr(); | ^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1] - --> $DIR/children-can-alias.rs:LL:CC + --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC | LL | child1.write(1); | ^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span): - = note: inside `raw_children_of_unique_can_alias` at $DIR/children-can-alias.rs:LL:CC + = note: inside `raw_children_of_unique_can_alias` at tests/fail/tree_borrows/children-can-alias.rs:LL:CC note: inside `main` - --> $DIR/children-can-alias.rs:LL:CC + --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC | LL | raw_children_of_unique_can_alias(Unique::new_unchecked(raw)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/tree_borrows/error-range.stderr b/src/tools/miri/tests/fail/tree_borrows/error-range.stderr index 090ae4507bd75..dc4d7c1f7fffe 100644 --- a/src/tools/miri/tests/fail/tree_borrows/error-range.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/error-range.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: read access through at ALLOC[0x5] is forbidden - --> $DIR/error-range.rs:LL:CC + --> tests/fail/tree_borrows/error-range.rs:LL:CC | LL | rmut[5] += 1; | ^^^^^^^^^^^^ read access through at ALLOC[0x5] is forbidden @@ -7,18 +7,18 @@ LL | rmut[5] += 1; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child read access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/error-range.rs:LL:CC + --> tests/fail/tree_borrows/error-range.rs:LL:CC | LL | let rmut = &mut *addr_of_mut!(data[0..6]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x5..0x6] - --> $DIR/error-range.rs:LL:CC + --> tests/fail/tree_borrows/error-range.rs:LL:CC | LL | data[5] = 1; | ^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/error-range.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/error-range.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr index dd5d27107fe8e..6b8e8fc1147d2 100644 --- a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/fnentry_invalidation.rs:LL:CC + --> tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC | LL | *z = 2; | ^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,24 +7,24 @@ LL | *z = 2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Frozen which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/fnentry_invalidation.rs:LL:CC + --> tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC | LL | let z = &mut x as *mut i32; | ^^^^^^ help: the accessed tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/fnentry_invalidation.rs:LL:CC + --> tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC | LL | *z = 1; | ^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference help: the accessed tag later transitioned to Frozen due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4] - --> $DIR/fnentry_invalidation.rs:LL:CC + --> tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC | LL | x.do_bad(); | ^ = help: this transition corresponds to a loss of write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/fnentry_invalidation.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr index 715228028bc4b..39fb956f7396b 100644 --- a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x3] is forbidden - --> $DIR/outside-range.rs:LL:CC + --> tests/fail/tree_borrows/outside-range.rs:LL:CC | LL | *y.add(3) = 42; | ^^^^^^^^^^^^^^ write access through at ALLOC[0x3] is forbidden @@ -9,19 +9,19 @@ LL | *y.add(3) = 42; = help: this foreign write access would cause the protected tag (currently Reserved) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/outside-range.rs:LL:CC + --> tests/fail/tree_borrows/outside-range.rs:LL:CC | LL | let raw = data.as_mut_ptr(); | ^^^^^^^^^^^^^^^^^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/outside-range.rs:LL:CC + --> tests/fail/tree_borrows/outside-range.rs:LL:CC | LL | unsafe fn stuff(x: &mut u8, y: *mut u8) { | ^ = note: BACKTRACE (of the first span): - = note: inside `stuff` at $DIR/outside-range.rs:LL:CC + = note: inside `stuff` at tests/fail/tree_borrows/outside-range.rs:LL:CC note: inside `main` - --> $DIR/outside-range.rs:LL:CC + --> tests/fail/tree_borrows/outside-range.rs:LL:CC | LL | stuff(&mut *raw, raw); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr index 87844ff401123..15f257c3d957b 100644 --- a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/parent_read_freezes_raw_mut.rs:LL:CC + --> tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC | LL | *ptr = 0; | ^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,24 +7,24 @@ LL | *ptr = 0; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Frozen which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/parent_read_freezes_raw_mut.rs:LL:CC + --> tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC | LL | let mref = &mut root; | ^^^^^^^^^ help: the accessed tag later transitioned to Active due to a child write access at offsets [0x0..0x1] - --> $DIR/parent_read_freezes_raw_mut.rs:LL:CC + --> tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC | LL | *ptr = 0; // Write | ^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference help: the accessed tag later transitioned to Frozen due to a reborrow (acting as a foreign read access) at offsets [0x0..0x1] - --> $DIR/parent_read_freezes_raw_mut.rs:LL:CC + --> tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC | LL | assert_eq!(root, 0); // Parent Read | ^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/parent_read_freezes_raw_mut.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr index 84fbc91e686cf..f6da0b8ec5219 100644 --- a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | *nope = 31; | ^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -8,31 +8,31 @@ LL | *nope = 31; = help: the accessed tag is a child of the conflicting tag = help: the conflicting tag has state Frozen which forbids this child write access help: the accessed tag was created here - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | fn foo(nope: &mut i32) { | ^^^^ help: the conflicting tag was created here, in the initial state Reserved - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ help: the conflicting tag later transitioned to Active due to a child write access at offsets [0x0..0x4] - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | *xref = 18; // activate xref | ^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference help: the conflicting tag later transitioned to Frozen due to a foreign read access at offsets [0x0..0x4] - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref for writing | ^^^^^ = help: this transition corresponds to a loss of write permissions = note: BACKTRACE (of the first span): - = note: inside `foo` at $DIR/pass_invalid_mut.rs:LL:CC + = note: inside `foo` at tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC note: inside `main` - --> $DIR/pass_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | foo(xref); | ^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr index 955abd144c7c3..bb07776da61e4 100644 --- a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x0] is forbidden - --> $DIR/protector-write-lazy.rs:LL:CC + --> tests/fail/tree_borrows/protector-write-lazy.rs:LL:CC | LL | unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow through at ALLOC[0x0] is forbidden @@ -7,18 +7,18 @@ LL | unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) } = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Reserved - --> $DIR/protector-write-lazy.rs:LL:CC + --> tests/fail/tree_borrows/protector-write-lazy.rs:LL:CC | LL | unsafe { (&mut *(ptr_to_vec.wrapping_add(1))) as *mut i32 }.wrapping_sub(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the accessed tag later transitioned to Disabled due to a protector release (acting as a foreign write access) on every location previously accessed by this tag - --> $DIR/protector-write-lazy.rs:LL:CC + --> tests/fail/tree_borrows/protector-write-lazy.rs:LL:CC | LL | } | ^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/protector-write-lazy.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/protector-write-lazy.rs:LL:CC = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr b/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr index 963e8e5eca9f6..d81ecff6cccb8 100644 --- a/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/repeated_foreign_read_lazy_conflicted.rs:LL:CC + --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC | LL | *(x as *mut u8).byte_sub(1) = 42; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,20 +7,20 @@ LL | *(x as *mut u8).byte_sub(1) = 42; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Reserved (conflicted) which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/repeated_foreign_read_lazy_conflicted.rs:LL:CC + --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC | LL | unsafe fn access_after_sub_1(x: &mut u8, orig_ptr: *mut u8) { | ^ help: the accessed tag later transitioned to Reserved (conflicted) due to a foreign read access at offsets [0x0..0x1] - --> $DIR/repeated_foreign_read_lazy_conflicted.rs:LL:CC + --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC | LL | do_something(*orig_ptr); | ^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit = note: BACKTRACE (of the first span): - = note: inside `access_after_sub_1` at $DIR/repeated_foreign_read_lazy_conflicted.rs:LL:CC + = note: inside `access_after_sub_1` at tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC note: inside `main` - --> $DIR/repeated_foreign_read_lazy_conflicted.rs:LL:CC + --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC | LL | access_after_sub_1(&mut *(foo as *mut u8).byte_add(1), orig_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr index 133a50938f281..03f79fe0a5d74 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr @@ -9,7 +9,7 @@ Warning: this tree is indicative only. Some tags may have been hidden. | ReIM| └──── ────────────────────────────────────────────────── error: Undefined Behavior: write access through (y, callee:y, caller:y) at ALLOC[0x0] is forbidden - --> $DIR/cell-protected-write.rs:LL:CC + --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC | LL | *y = 1; | ^^^^^^ write access through (y, callee:y, caller:y) at ALLOC[0x0] is forbidden @@ -19,19 +19,19 @@ LL | *y = 1; = help: this foreign write access would cause the protected tag (callee:x) (currently Reserved) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/cell-protected-write.rs:LL:CC + --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC | LL | let y = (&mut *n).get(); | ^^^^^^^^^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/cell-protected-write.rs:LL:CC + --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC | LL | unsafe fn write_second(x: &mut UnsafeCell, y: *mut u8) { | ^ = note: BACKTRACE (of the first span): - = note: inside `main::write_second` at $DIR/cell-protected-write.rs:LL:CC + = note: inside `main::write_second` at tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC note: inside `main` - --> $DIR/cell-protected-write.rs:LL:CC + --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC | LL | write_second(x, y); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr index a4dc123979edf..a9683c9e6147f 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr @@ -9,7 +9,7 @@ Warning: this tree is indicative only. Some tags may have been hidden. | Res | └──── ────────────────────────────────────────────────── error: Undefined Behavior: write access through (y, callee:y, caller:y) at ALLOC[0x0] is forbidden - --> $DIR/int-protected-write.rs:LL:CC + --> tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC | LL | *y = 0; | ^^^^^^ write access through (y, callee:y, caller:y) at ALLOC[0x0] is forbidden @@ -19,19 +19,19 @@ LL | *y = 0; = help: this foreign write access would cause the protected tag (callee:x) (currently Reserved) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here - --> $DIR/int-protected-write.rs:LL:CC + --> tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC | LL | let y = (&mut *n) as *mut _; | ^^^^^^^^^ help: the protected tag was created here, in the initial state Reserved - --> $DIR/int-protected-write.rs:LL:CC + --> tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC | LL | unsafe fn write_second(x: &mut u8, y: *mut u8) { | ^ = note: BACKTRACE (of the first span): - = note: inside `main::write_second` at $DIR/int-protected-write.rs:LL:CC + = note: inside `main::write_second` at tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC note: inside `main` - --> $DIR/int-protected-write.rs:LL:CC + --> tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC | LL | write_second(x, y); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr index 0e4517e90105c..47341e027d7a1 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr @@ -13,7 +13,7 @@ Thread 1 executing: ret x Thread 1 executing: write y Thread 2 executing: write y error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/reservedim_spurious_write.rs:LL:CC + --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC | LL | unsafe { *y = 13 } | ^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -21,18 +21,18 @@ LL | unsafe { *y = 13 } = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/reservedim_spurious_write.rs:LL:CC + --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC | LL | fn inner(y: &mut Cell<()>, b: IdxBarrier) -> *mut u8 { | ^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1] - --> $DIR/reservedim_spurious_write.rs:LL:CC + --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC | LL | *x = 64; | ^^^^^^^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/reservedim_spurious_write.rs:LL:CC + = note: inside closure at tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr index cbeef90243bfb..504b8cc0ac769 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr @@ -13,7 +13,7 @@ Thread 1 executing: ret x Thread 1 executing: write y Thread 2 executing: write y error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/reservedim_spurious_write.rs:LL:CC + --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC | LL | unsafe { *y = 13 } | ^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -21,18 +21,18 @@ LL | unsafe { *y = 13 } = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/reservedim_spurious_write.rs:LL:CC + --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC | LL | fn inner(y: &mut Cell<()>, b: IdxBarrier) -> *mut u8 { | ^ help: the accessed tag later transitioned to Disabled due to a protector release (acting as a foreign write access) on every location previously accessed by this tag - --> $DIR/reservedim_spurious_write.rs:LL:CC + --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC | LL | } | ^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/reservedim_spurious_write.rs:LL:CC + = note: inside closure at tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr index ca8c45d36f9db..81fa3262877d7 100644 --- a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x4] is forbidden - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC | LL | *ret = 3; | ^^^^^^^^ write access through at ALLOC[0x4] is forbidden @@ -8,29 +8,29 @@ LL | *ret = 3; = help: the accessed tag is a child of the conflicting tag = help: the conflicting tag has state Frozen which forbids this child write access help: the accessed tag was created here - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC | LL | let ret = foo(arg); | ^^^^^^^^ help: the conflicting tag was created here, in the initial state Reserved - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC | LL | let ret = unsafe { &mut (*xraw).1 }; | ^^^^^^^^^^^^^^ help: the conflicting tag later transitioned to Active due to a child write access at offsets [0x4..0x8] - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC | LL | *ret = *ret; // activate | ^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference help: the conflicting tag later transitioned to Frozen due to a foreign read access at offsets [0x0..0x8] - --> $DIR/return_invalid_mut.rs:LL:CC + --> tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref for writing | ^^^^^ = help: this transition corresponds to a loss of write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/return_invalid_mut.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr index f3934d4cbe579..bd26b4e36df01 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr @@ -12,7 +12,7 @@ Thread 2 executing: write y Thread 1 executing: write y Thread 1 executing: ret y error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/spurious_read.rs:LL:CC + --> tests/fail/tree_borrows/spurious_read.rs:LL:CC | LL | *y = 2; | ^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -20,20 +20,20 @@ LL | *y = 2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Reserved (conflicted) which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/spurious_read.rs:LL:CC + --> tests/fail/tree_borrows/spurious_read.rs:LL:CC | LL | fn as_mut(y: &mut u8, b: (usize, Arc)) -> *mut u8 { | ^ help: the accessed tag later transitioned to Reserved (conflicted) due to a protector release (acting as a foreign read access) on every location previously accessed by this tag - --> $DIR/spurious_read.rs:LL:CC + --> tests/fail/tree_borrows/spurious_read.rs:LL:CC | LL | } | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `retagx_retagy_retx_writey_rety::{closure#1}::as_mut` at $DIR/spurious_read.rs:LL:CC + = note: inside `retagx_retagy_retx_writey_rety::{closure#1}::as_mut` at tests/fail/tree_borrows/spurious_read.rs:LL:CC note: inside closure - --> $DIR/spurious_read.rs:LL:CC + --> tests/fail/tree_borrows/spurious_read.rs:LL:CC | LL | let _y = as_mut(unsafe { &mut *ptr.0 }, b.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr index 9da43055af240..f6197a2acb391 100644 --- a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr @@ -1,41 +1,39 @@ error: Undefined Behavior: deallocation through at ALLOC[0x0] is forbidden - --> RUSTLIB/alloc/src/alloc.rs:LL:CC + --> RUSTLIB/alloc/src/boxed.rs:LL:CC | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocation through at ALLOC[0x0] is forbidden +LL | self.1.deallocate(From::from(ptr.cast()), layout); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocation through at ALLOC[0x0] is forbidden | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the allocation of the accessed tag also contains the strongly protected tag = help: the strongly protected tag disallows deallocations help: the accessed tag was created here - --> $DIR/strongly-protected.rs:LL:CC + --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the strongly protected tag was created here, in the initial state Reserved - --> $DIR/strongly-protected.rs:LL:CC + --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC | LL | fn inner(x: &mut i32, f: fn(*mut i32)) { | ^ = note: BACKTRACE (of the first span): - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure - --> $DIR/strongly-protected.rs:LL:CC + --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<{closure@$DIR/strongly-protected.rs:LL:CC} as std::ops::FnOnce<(*mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC + = note: inside `<{closure@tests/fail/tree_borrows/strongly-protected.rs:LL:CC} as std::ops::FnOnce<(*mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC note: inside `inner` - --> $DIR/strongly-protected.rs:LL:CC + --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC | LL | f(x) | ^^^^ note: inside `main` - --> $DIR/strongly-protected.rs:LL:CC + --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC | LL | / inner(Box::leak(Box::new(0)), |raw| { LL | | drop(unsafe { Box::from_raw(raw) }); diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr b/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr index bce8cb011f64b..c7d72f70f40cf 100644 --- a/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | *uniq.as_ptr() = 3; | ^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -7,24 +7,24 @@ LL | *uniq.as_ptr() = 3; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Frozen which forbids this child write access help: the accessed tag was created here, in the initial state Reserved - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | let refmut = &mut data; | ^^^^^^^^^ help: the accessed tag later transitioned to Active due to a child write access at offsets [0x0..0x1] - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | *uniq.as_ptr() = 1; // activation | ^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference help: the accessed tag later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1] - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | let _definitely_parent = data; // definitely Frozen by now | ^^^^ = help: this transition corresponds to a loss of write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/unique.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/unique.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr b/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr index 7323cd1c5ad82..4ecff3ea0e1f1 100644 --- a/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | *uniq.as_ptr() = 2; | ^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden @@ -8,29 +8,29 @@ LL | *uniq.as_ptr() = 2; = help: the accessed tag is a child of the conflicting tag = help: the conflicting tag has state Frozen which forbids this child write access help: the accessed tag was created here - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | *uniq.as_ptr() = 2; | ^^^^^^^^^^^^^ help: the conflicting tag was created here, in the initial state Reserved - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | let uniq = Unique::new_unchecked(rawptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the conflicting tag later transitioned to Active due to a child write access at offsets [0x0..0x1] - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | *uniq.as_ptr() = 1; // activation | ^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference help: the conflicting tag later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1] - --> $DIR/unique.rs:LL:CC + --> tests/fail/tree_borrows/unique.rs:LL:CC | LL | let _maybe_parent = *rawptr; // maybe becomes Frozen | ^^^^^^^ = help: this transition corresponds to a loss of write permissions = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/unique.rs:LL:CC + = note: inside `main` at tests/fail/tree_borrows/unique.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr index 87589299cb168..b85aac7db76ba 100644 --- a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: reborrow through at ALLOC[0x0] is forbidden - --> $DIR/write-during-2phase.rs:LL:CC + --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC | LL | fn add(&mut self, n: u64) -> u64 { | ^^^^^^^^^ reborrow through at ALLOC[0x0] is forbidden @@ -7,20 +7,20 @@ LL | fn add(&mut self, n: u64) -> u64 { = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag was created here, in the initial state Reserved - --> $DIR/write-during-2phase.rs:LL:CC + --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC | LL | let _res = f.add(unsafe { | ^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8] - --> $DIR/write-during-2phase.rs:LL:CC + --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC | LL | *inner = 42; | ^^^^^^^^^^^ = help: this transition corresponds to a loss of read and write permissions = note: BACKTRACE (of the first span): - = note: inside `Foo::add` at $DIR/write-during-2phase.rs:LL:CC + = note: inside `Foo::add` at tests/fail/tree_borrows/write-during-2phase.rs:LL:CC note: inside `main` - --> $DIR/write-during-2phase.rs:LL:CC + --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC | LL | let _res = f.add(unsafe { | ________________^ diff --git a/src/tools/miri/tests/fail/type-too-large.rs b/src/tools/miri/tests/fail/type-too-large.rs index 81ecc6145d709..46e3ac2d6ca98 100644 --- a/src/tools/miri/tests/fail/type-too-large.rs +++ b/src/tools/miri/tests/fail/type-too-large.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 fn main() { let _fat: [u8; (1 << 61) + (1 << 31)]; // ideally we'd error here, but we avoid computing the layout until absolutely necessary diff --git a/src/tools/miri/tests/fail/type-too-large.stderr b/src/tools/miri/tests/fail/type-too-large.stderr index b07bb84e348f3..cd27b2463891b 100644 --- a/src/tools/miri/tests/fail/type-too-large.stderr +++ b/src/tools/miri/tests/fail/type-too-large.stderr @@ -1,11 +1,11 @@ -error: post-monomorphization error: values of the type `[u8; 2305843011361177600]` are too big for the current architecture - --> $DIR/type-too-large.rs:LL:CC +error: post-monomorphization error: values of the type `[u8; 2305843011361177600]` are too big for the target architecture + --> tests/fail/type-too-large.rs:LL:CC | LL | _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843011361177600]` are too big for the current architecture + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843011361177600]` are too big for the target architecture | = note: BACKTRACE: - = note: inside `main` at $DIR/type-too-large.rs:LL:CC + = note: inside `main` at tests/fail/type-too-large.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr index ca3d34661d38d..8bbb4dfdb603b 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/alignment.rs:LL:CC + --> tests/fail/unaligned_pointers/alignment.rs:LL:CC | LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; | ^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/alignment.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr b/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr index 161e8977bf4ab..a9da740be1db9 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required - --> $DIR/atomic_unaligned.rs:LL:CC + --> tests/fail/unaligned_pointers/atomic_unaligned.rs:LL:CC | LL | ::std::intrinsics::atomic_load_seqcst(zptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | ::std::intrinsics::atomic_load_seqcst(zptr); = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives = note: BACKTRACE: - = note: inside `main` at $DIR/atomic_unaligned.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/atomic_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr index 600028337fa6d..75efa5ff806ce 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr @@ -9,7 +9,7 @@ LL | pub unsafe fn drop_in_place(to_drop: *mut T) { = note: BACKTRACE: = note: inside `std::ptr::drop_in_place:: - shim(Some(PartialDrop))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC note: inside `main` - --> $DIR/drop_in_place.rs:LL:CC + --> tests/fail/unaligned_pointers/drop_in_place.rs:LL:CC | LL | core::ptr::drop_in_place(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr index 05e30f833bb2d..72cded1c0798d 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) - --> $DIR/dyn_alignment.rs:LL:CC + --> tests/fail/unaligned_pointers/dyn_alignment.rs:LL:CC | LL | let _ptr = &*ptr; | ^^^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) @@ -7,7 +7,7 @@ LL | let _ptr = &*ptr; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dyn_alignment.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/dyn_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr index 9046502975d47..04ecf618fc0dd 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/field_requires_parent_struct_alignment.rs:LL:CC + --> tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs:LL:CC | LL | unsafe { (*x).x } | ^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,9 +7,9 @@ LL | unsafe { (*x).x } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `foo` at $DIR/field_requires_parent_struct_alignment.rs:LL:CC + = note: inside `foo` at tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs:LL:CC note: inside `main` - --> $DIR/field_requires_parent_struct_alignment.rs:LL:CC + --> tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs:LL:CC | LL | foo(odd_ptr.cast()); | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr index 0d0057a79abc3..da5a34a8dc675 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/field_requires_parent_struct_alignment2.rs:LL:CC + --> tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs:LL:CC | LL | unsafe { (*x).packed.x } | ^^^^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,9 +7,9 @@ LL | unsafe { (*x).packed.x } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `foo` at $DIR/field_requires_parent_struct_alignment2.rs:LL:CC + = note: inside `foo` at tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs:LL:CC note: inside `main` - --> $DIR/field_requires_parent_struct_alignment2.rs:LL:CC + --> tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs:LL:CC | LL | foo(odd_ptr.cast()); | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 318004da6013a..e0e866b25c8c0 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/intptrcast_alignment_check.rs:LL:CC + --> tests/fail/unaligned_pointers/intptrcast_alignment_check.rs:LL:CC | LL | unsafe { *u16_ptr = 2 }; | ^^^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | unsafe { *u16_ptr = 2 }; = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives = note: BACKTRACE: - = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/intptrcast_alignment_check.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.call_unaligned_ptr.stderr b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.call_unaligned_ptr.stderr index 6d62db4d3d556..91df7cf47a74d 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.call_unaligned_ptr.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.call_unaligned_ptr.stderr @@ -1,12 +1,12 @@ error: unsupported operation: `miri_promise_symbolic_alignment`: pointer is not actually aligned - --> $DIR/promise_alignment.rs:LL:CC + --> tests/fail/unaligned_pointers/promise_alignment.rs:LL:CC | LL | unsafe { utils::miri_promise_symbolic_alignment(align8.add(1).cast(), 8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `miri_promise_symbolic_alignment`: pointer is not actually aligned | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/promise_alignment.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/promise_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.read_unaligned_ptr.stderr b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.read_unaligned_ptr.stderr index 0842ccd6d5bb6..1e984aa3efd21 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.read_unaligned_ptr.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.read_unaligned_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/promise_alignment.rs:LL:CC + --> tests/fail/unaligned_pointers/promise_alignment.rs:LL:CC | LL | let _val = unsafe { align8.cast::().read() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | let _val = unsafe { align8.cast::().read() }; = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives = note: BACKTRACE: - = note: inside `main` at $DIR/promise_alignment.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/promise_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr index 3f7ced0b407df..c687d9986137d 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr @@ -1,12 +1,12 @@ error: unsupported operation: `miri_promise_symbolic_alignment`: alignment must be a power of 2, got 0 - --> $DIR/promise_alignment_zero.rs:LL:CC + --> tests/fail/unaligned_pointers/promise_alignment_zero.rs:LL:CC | LL | unsafe { utils::miri_promise_symbolic_alignment(buffer.as_ptr().cast(), 0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `miri_promise_symbolic_alignment`: alignment must be a power of 2, got 0 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/promise_alignment_zero.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/promise_alignment_zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr index 938a037572995..9adbd7f81539d 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) - --> $DIR/reference_to_packed.rs:LL:CC + --> tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC | LL | mem::transmute(x) | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) @@ -7,9 +7,9 @@ LL | mem::transmute(x) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `raw_to_ref::<'_, i32>` at $DIR/reference_to_packed.rs:LL:CC + = note: inside `raw_to_ref::<'_, i32>` at tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC note: inside `main` - --> $DIR/reference_to_packed.rs:LL:CC + --> tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC | LL | let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr index ae3be1ed3afb0..90cfb4245c886 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/unaligned_ptr1.rs:LL:CC + --> tests/fail/unaligned_pointers/unaligned_ptr1.rs:LL:CC | LL | let _x = unsafe { *x }; | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | let _x = unsafe { *x }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unaligned_ptr1.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/unaligned_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr index 2b92602749820..57ac8553930ca 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/unaligned_ptr2.rs:LL:CC + --> tests/fail/unaligned_pointers/unaligned_ptr2.rs:LL:CC | LL | let _x = unsafe { *x }; | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | let _x = unsafe { *x }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unaligned_ptr2.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/unaligned_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr index 5ac4e23bf015e..d8ab546af6ac2 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/unaligned_ptr3.rs:LL:CC + --> tests/fail/unaligned_pointers/unaligned_ptr3.rs:LL:CC | LL | let _x = unsafe { *x }; | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | let _x = unsafe { *x }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unaligned_ptr3.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/unaligned_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr index 4de90118b4b88..5fe342c9b3163 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/unaligned_ptr4.rs:LL:CC + --> tests/fail/unaligned_pointers/unaligned_ptr4.rs:LL:CC | LL | let _val = unsafe { *ptr }; | ^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | let _val = unsafe { *ptr }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unaligned_ptr4.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/unaligned_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr index 72db125074b59..1ae8d9548821e 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required - --> $DIR/unaligned_ptr_zst.rs:LL:CC + --> tests/fail/unaligned_pointers/unaligned_ptr_zst.rs:LL:CC | LL | let _x = unsafe { *x }; | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required @@ -7,7 +7,7 @@ LL | let _x = unsafe { *x }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unaligned_ptr_zst.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/unaligned_ptr_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr index 448023a2a3d8f..d7561c57a8c5a 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) - --> $DIR/unaligned_ref_addr_of.rs:LL:CC + --> tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs:LL:CC | LL | let _x = unsafe { &*x }; | ^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) @@ -7,7 +7,7 @@ LL | let _x = unsafe { &*x }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unaligned_ref_addr_of.rs:LL:CC + = note: inside `main` at tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.rs b/src/tools/miri/tests/fail/uninit/padding-enum.rs new file mode 100644 index 0000000000000..e1a16bea23ccb --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-enum.rs @@ -0,0 +1,27 @@ +use std::mem; + +// We have three fields to avoid the ScalarPair optimization. +#[allow(unused)] +enum E { + None, + Some(&'static (), &'static (), usize), +} + +fn main() { + unsafe { + let mut p: mem::MaybeUninit = mem::MaybeUninit::zeroed(); + // The copy when `E` is returned from `transmute` should destroy padding + // (even when we use `write_unaligned`, which under the hood uses an untyped copy). + p.as_mut_ptr().write_unaligned(mem::transmute((0usize, 0usize, 0usize))); + // This is a `None`, so everything but the discriminant is padding. + assert!(matches!(*p.as_ptr(), E::None)); + + // Turns out the discriminant is (currently) stored + // in the 1st pointer, so the second half is padding. + let c = &p as *const _ as *const u8; + let padding_offset = mem::size_of::<&'static ()>(); + // Read a padding byte. + let _val = *c.add(padding_offset); + //~^ERROR: uninitialized + } +} diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.stderr b/src/tools/miri/tests/fail/uninit/padding-enum.stderr new file mode 100644 index 0000000000000..765e7cc4e637d --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-enum.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> tests/fail/uninit/padding-enum.rs:LL:CC + | +LL | let _val = *c.add(padding_offset); + | ^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/uninit/padding-enum.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/uninit/padding-pair.rs b/src/tools/miri/tests/fail/uninit/padding-pair.rs new file mode 100644 index 0000000000000..c8c00b3c65a06 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-pair.rs @@ -0,0 +1,25 @@ +#![feature(core_intrinsics)] + +use std::mem::{self, MaybeUninit}; + +fn main() { + // This constructs a `(usize, bool)` pair: 9 bytes initialized, the rest not. + // Ensure that these 9 bytes are indeed initialized, and the rest is indeed not. + // This should be the case even if we write into previously initialized storage. + let mut x: MaybeUninit> = MaybeUninit::zeroed(); + let z = std::intrinsics::add_with_overflow(0usize, 0usize); + unsafe { x.as_mut_ptr().cast::<(usize, bool)>().write(z) }; + // Now read this bytewise. There should be (`ptr_size + 1`) def bytes followed by + // (`ptr_size - 1`) undef bytes (the padding after the bool) in there. + let z: *const u8 = &x as *const _ as *const _; + let first_undef = mem::size_of::() as isize + 1; + for i in 0..first_undef { + let byte = unsafe { *z.offset(i) }; + assert_eq!(byte, 0); + } + let v = unsafe { *z.offset(first_undef) }; + //~^ ERROR: uninitialized + if v == 0 { + println!("it is zero"); + } +} diff --git a/src/tools/miri/tests/fail/uninit/padding-pair.stderr b/src/tools/miri/tests/fail/uninit/padding-pair.stderr new file mode 100644 index 0000000000000..f4ce802b15714 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-pair.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> tests/fail/uninit/padding-pair.rs:LL:CC + | +LL | let v = unsafe { *z.offset(first_undef) }; + | ^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/uninit/padding-pair.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/uninit/padding-struct-in-union.rs b/src/tools/miri/tests/fail/uninit/padding-struct-in-union.rs new file mode 100644 index 0000000000000..132b85828362d --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-struct-in-union.rs @@ -0,0 +1,32 @@ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct Foo { + val16: u16, + // Padding bytes go here! + val32: u32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct Bar { + bytes: [u8; 8], +} + +#[repr(C)] +union FooBar { + foo: Foo, + bar: Bar, +} + +pub fn main() { + // Initialize as u8 to ensure padding bytes are zeroed. + let mut foobar = FooBar { bar: Bar { bytes: [0u8; 8] } }; + // Reading either field is ok. + let _val = unsafe { (foobar.foo, foobar.bar) }; + // Does this assignment copy the uninitialized padding bytes + // over the initialized padding bytes? miri doesn't seem to think so. + foobar.foo = Foo { val16: 1, val32: 2 }; + // This resets the padding to uninit. + let _val = unsafe { (foobar.foo, foobar.bar) }; + //~^ ERROR: uninitialized +} diff --git a/src/tools/miri/tests/fail/uninit/padding-struct-in-union.stderr b/src/tools/miri/tests/fail/uninit/padding-struct-in-union.stderr new file mode 100644 index 0000000000000..5e9dabd56443f --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-struct-in-union.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at .bytes[2]: encountered uninitialized memory, but expected an integer + --> tests/fail/uninit/padding-struct-in-union.rs:LL:CC + | +LL | let _val = unsafe { (foobar.foo, foobar.bar) }; + | ^^^^^^^^^^ constructing invalid value at .bytes[2]: encountered uninitialized memory, but expected an integer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/uninit/padding-struct-in-union.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/uninit/padding-struct.rs b/src/tools/miri/tests/fail/uninit/padding-struct.rs new file mode 100644 index 0000000000000..4cdc6f3a10450 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-struct.rs @@ -0,0 +1,14 @@ +use std::mem; + +#[repr(C)] +struct Pair(u8, u16); + +fn main() { + unsafe { + let p: Pair = mem::transmute(0u32); // The copy when `Pair` is returned from `transmute` should destroy padding. + let c = &p as *const _ as *const u8; + // Read the padding byte. + let _val = *c.add(1); + //~^ERROR: uninitialized + } +} diff --git a/src/tools/miri/tests/fail/uninit/padding-struct.stderr b/src/tools/miri/tests/fail/uninit/padding-struct.stderr new file mode 100644 index 0000000000000..f27783c17e958 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-struct.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> tests/fail/uninit/padding-struct.rs:LL:CC + | +LL | let _val = *c.add(1); + | ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/uninit/padding-struct.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/uninit/padding-union.rs b/src/tools/miri/tests/fail/uninit/padding-union.rs new file mode 100644 index 0000000000000..294578607b37d --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-union.rs @@ -0,0 +1,17 @@ +use std::mem; + +#[allow(unused)] +#[repr(C)] +union U { + field: (u8, u16), +} + +fn main() { + unsafe { + let p: U = mem::transmute(0u32); // The copy when `U` is returned from `transmute` should destroy padding. + let c = &p as *const _ as *const [u8; 4]; + // Read the entire thing, definitely contains the padding byte. + let _val = *c; + //~^ERROR: uninitialized + } +} diff --git a/src/tools/miri/tests/fail/uninit/padding-union.stderr b/src/tools/miri/tests/fail/uninit/padding-union.stderr new file mode 100644 index 0000000000000..248b06a14fe28 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-union.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer + --> tests/fail/uninit/padding-union.rs:LL:CC + | +LL | let _val = *c; + | ^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/uninit/padding-union.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs new file mode 100644 index 0000000000000..4e363dbf81e08 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs @@ -0,0 +1,21 @@ +use std::mem; + +// If this is `None`, the metadata becomes padding. +type T = Option<&'static str>; + +fn main() { + unsafe { + let mut p: mem::MaybeUninit = mem::MaybeUninit::zeroed(); + // The copy when `T` is returned from `transmute` should destroy padding + // (even when we use `write_unaligned`, which under the hood uses an untyped copy). + p.as_mut_ptr().write_unaligned(mem::transmute((0usize, 0usize))); + // Null epresents `None`. + assert!(matches!(*p.as_ptr(), None)); + + // The second part, with the length, becomes padding. + let c = &p as *const _ as *const u8; + // Read a padding byte. + let _val = *c.add(mem::size_of::<*const u8>()); + //~^ERROR: uninitialized + } +} diff --git a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr new file mode 100644 index 0000000000000..219bee45fe8ec --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> tests/fail/uninit/padding-wide-ptr.rs:LL:CC + | +LL | let _val = *c.add(mem::size_of::<*const u8>()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/uninit/padding-wide-ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/transmute-pair-uninit.rs b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs similarity index 61% rename from src/tools/miri/tests/fail/transmute-pair-uninit.rs rename to src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs index bc95f3cb7ad3a..0ba5520a54468 100644 --- a/src/tools/miri/tests/fail/transmute-pair-uninit.rs +++ b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs @@ -1,16 +1,17 @@ #![feature(core_intrinsics)] -use std::mem; +use std::mem::{self, MaybeUninit}; fn main() { - let x: Option> = unsafe { + // This constructs a `(usize, bool)` pair: 9 bytes initialized, the rest not. + // Ensure that these 9 bytes are indeed initialized, and the rest is indeed not. + let x: MaybeUninit> = unsafe { let z = std::intrinsics::add_with_overflow(0usize, 0usize); - std::mem::transmute::<(usize, bool), Option>>(z) + std::mem::transmute::<(usize, bool), MaybeUninit>>(z) }; - let y = &x; // Now read this bytewise. There should be (`ptr_size + 1`) def bytes followed by // (`ptr_size - 1`) undef bytes (the padding after the bool) in there. - let z: *const u8 = y as *const _ as *const _; + let z: *const u8 = &x as *const _ as *const _; let first_undef = mem::size_of::() as isize + 1; for i in 0..first_undef { let byte = unsafe { *z.offset(i) }; diff --git a/src/tools/miri/tests/fail/transmute-pair-uninit.stderr b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr similarity index 83% rename from src/tools/miri/tests/fail/transmute-pair-uninit.stderr rename to src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr index 30306054fbb3a..7fe88df560c83 100644 --- a/src/tools/miri/tests/fail/transmute-pair-uninit.stderr +++ b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/transmute-pair-uninit.rs:LL:CC + --> tests/fail/uninit/transmute-pair-uninit.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; | ^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | let v = unsafe { *z.offset(first_undef) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/transmute-pair-uninit.rs:LL:CC + = note: inside `main` at tests/fail/uninit/transmute-pair-uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr b/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr index 5f3d9bde1f244..ec6ba3fea7d6c 100644 --- a/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer - --> $DIR/uninit-after-aggregate-assign.rs:LL:CC + --> tests/fail/uninit/uninit-after-aggregate-assign.rs:LL:CC | LL | _val = *sptr2; // should hence be UB | ^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer @@ -7,7 +7,7 @@ LL | _val = *sptr2; // should hence be UB = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/uninit-after-aggregate-assign.rs:LL:CC + = note: inside `main` at tests/fail/uninit/uninit-after-aggregate-assign.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.rs b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.rs index 8deaa30d50ff2..5edf4bbb1ccda 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.rs +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.rs @@ -3,7 +3,7 @@ #![allow(dropping_copy_types)] -use std::alloc::{alloc, dealloc, Layout}; +use std::alloc::{Layout, alloc, dealloc}; use std::slice::from_raw_parts; fn main() { diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr index dfe3ed4b522ab..0996e5d11eff6 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr @@ -10,7 +10,7 @@ LL | let mut order = unsafe { compare_bytes(left, right, len) as isize } = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` - --> $DIR/uninit_alloc_diagnostic.rs:LL:CC + --> tests/fail/uninit/uninit_alloc_diagnostic.rs:LL:CC | LL | drop(slice1.cmp(slice2)); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs index adabff4a2cea2..954571f4a22cf 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs @@ -6,7 +6,7 @@ // Test printing allocations that contain single-byte provenance. -use std::alloc::{alloc, dealloc, Layout}; +use std::alloc::{Layout, alloc, dealloc}; use std::mem::{self, MaybeUninit}; use std::slice::from_raw_parts; diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr index 48ce9ae76568a..bcde9377c5400 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr @@ -10,7 +10,7 @@ LL | let mut order = unsafe { compare_bytes(left, right, len) as isize } = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` - --> $DIR/uninit_alloc_diagnostic_with_provenance.rs:LL:CC + --> tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs:LL:CC | LL | drop(slice1.cmp(slice2)); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr index 3917d868289ea..5da89976b0371 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/uninit_byte_read.rs:LL:CC + --> tests/fail/uninit/uninit_byte_read.rs:LL:CC | LL | let undef = unsafe { *v.as_ptr().add(5) }; | ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | let undef = unsafe { *v.as_ptr().add(5) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/uninit_byte_read.rs:LL:CC + = note: inside `main` at tests/fail/uninit/uninit_byte_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unreachable.stderr b/src/tools/miri/tests/fail/unreachable.stderr index f6982dc86535e..46c956ff77ea7 100644 --- a/src/tools/miri/tests/fail/unreachable.stderr +++ b/src/tools/miri/tests/fail/unreachable.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: entering unreachable code - --> $DIR/unreachable.rs:LL:CC + --> tests/fail/unreachable.rs:LL:CC | LL | unsafe { std::hint::unreachable_unchecked() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code @@ -7,7 +7,7 @@ LL | unsafe { std::hint::unreachable_unchecked() } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/unreachable.rs:LL:CC + = note: inside `main` at tests/fail/unreachable.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unsized-local.stderr b/src/tools/miri/tests/fail/unsized-local.stderr index df54c98bb0e11..548f3d66c7338 100644 --- a/src/tools/miri/tests/fail/unsized-local.stderr +++ b/src/tools/miri/tests/fail/unsized-local.stderr @@ -1,12 +1,12 @@ error: unsupported operation: unsized locals are not supported - --> $DIR/unsized-local.rs:LL:CC + --> tests/fail/unsized-local.rs:LL:CC | LL | let x = *(Box::new(A) as Box); | ^ unsized locals are not supported | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: - = note: inside `main` at $DIR/unsized-local.rs:LL:CC + = note: inside `main` at tests/fail/unsized-local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unsupported_foreign_function.stderr b/src/tools/miri/tests/fail/unsupported_foreign_function.stderr index f392e9564c751..4fe45b0868a93 100644 --- a/src/tools/miri/tests/fail/unsupported_foreign_function.stderr +++ b/src/tools/miri/tests/fail/unsupported_foreign_function.stderr @@ -1,5 +1,5 @@ error: unsupported operation: can't call foreign function `foo` on $OS - --> $DIR/unsupported_foreign_function.rs:LL:CC + --> tests/fail/unsupported_foreign_function.rs:LL:CC | LL | foo(); | ^^^^^ can't call foreign function `foo` on $OS @@ -7,7 +7,7 @@ LL | foo(); = help: if this is a basic API commonly used on this target, please report an issue with Miri = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases = note: BACKTRACE: - = note: inside `main` at $DIR/unsupported_foreign_function.rs:LL:CC + = note: inside `main` at tests/fail/unsupported_foreign_function.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index fd67bdf4a90bc..818371220514f 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/unwind-action-terminate.rs:LL:CC: +thread 'main' panicked at tests/fail/unwind-action-terminate.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect @@ -21,14 +21,14 @@ LL | ABORT(); = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `panic_abort` - --> $DIR/unwind-action-terminate.rs:LL:CC + --> tests/fail/unwind-action-terminate.rs:LL:CC | LL | / extern "C" fn panic_abort() { LL | | panic!() LL | | } | |_^ note: inside `main` - --> $DIR/unwind-action-terminate.rs:LL:CC + --> tests/fail/unwind-action-terminate.rs:LL:CC | LL | panic_abort(); | ^ diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr index f526f77a4f000..9b6b7098e5cd6 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC + --> tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs:LL:CC | LL | g(0usize as *const i32) | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -7,7 +7,7 @@ LL | g(0usize as *const i32) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC + = note: inside `main` at tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr index 35de453522257..a0b7cc7a521d4 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 - --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + --> tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs:LL:CC | LL | f(); | ^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 @@ -7,7 +7,7 @@ LL | f(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + = note: inside `main` at tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr index 81d775f6d7f5f..6af0e72b9c43f 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 - --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + --> tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC | LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 @@ -7,9 +7,9 @@ LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + = note: inside `call` at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC note: inside `main` - --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + --> tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC | LL | call(f); | ^^^^^^^ diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr index 7593b8a399873..c02651c7cc9d8 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC + --> tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs:LL:CC | LL | let _x = g(); | ^^^ constructing invalid value: encountered a null reference @@ -7,7 +7,7 @@ LL | let _x = g(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC + = note: inside `main` at tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/dangling_ref1.stderr b/src/tools/miri/tests/fail/validity/dangling_ref1.stderr index fd4dd502bd5c1..09634e5ae7b01 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref1.stderr +++ b/src/tools/miri/tests/fail/validity/dangling_ref1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling reference (0x10[noalloc] has no provenance) - --> $DIR/dangling_ref1.rs:LL:CC + --> tests/fail/validity/dangling_ref1.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x10[noalloc] has no provenance) @@ -7,7 +7,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dangling_ref1.rs:LL:CC + = note: inside `main` at tests/fail/validity/dangling_ref1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/dangling_ref2.stderr b/src/tools/miri/tests/fail/validity/dangling_ref2.stderr index 2d45ae68ca474..fe7fe2795ef55 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref2.stderr +++ b/src/tools/miri/tests/fail/validity/dangling_ref2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) - --> $DIR/dangling_ref2.rs:LL:CC + --> tests/fail/validity/dangling_ref2.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; | ^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -7,7 +7,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dangling_ref2.rs:LL:CC + = note: inside `main` at tests/fail/validity/dangling_ref2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/dangling_ref3.stderr b/src/tools/miri/tests/fail/validity/dangling_ref3.stderr index 5ac4f5deffe7c..fe40aaa122f4f 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref3.stderr +++ b/src/tools/miri/tests/fail/validity/dangling_ref3.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) - --> $DIR/dangling_ref3.rs:LL:CC + --> tests/fail/validity/dangling_ref3.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) @@ -7,7 +7,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/dangling_ref3.rs:LL:CC + = note: inside `main` at tests/fail/validity/dangling_ref3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_bool.stderr b/src/tools/miri/tests/fail/validity/invalid_bool.stderr index 3ed823dde9427..9bed0f716a03c 100644 --- a/src/tools/miri/tests/fail/validity/invalid_bool.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_bool.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean - --> $DIR/invalid_bool.rs:LL:CC + --> tests/fail/validity/invalid_bool.rs:LL:CC | LL | let _b = unsafe { std::mem::transmute::(2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean @@ -7,7 +7,7 @@ LL | let _b = unsafe { std::mem::transmute::(2) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_bool.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_bool_op.stderr b/src/tools/miri/tests/fail/validity/invalid_bool_op.stderr index b938d29e760ad..ee84762fe40ba 100644 --- a/src/tools/miri/tests/fail/validity/invalid_bool_op.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_bool_op.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: interpreting an invalid 8-bit value as a bool: 0x02 - --> $DIR/invalid_bool_op.rs:LL:CC + --> tests/fail/validity/invalid_bool_op.rs:LL:CC | LL | let _x = b == std::hint::black_box(true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ interpreting an invalid 8-bit value as a bool: 0x02 @@ -7,7 +7,7 @@ LL | let _x = b == std::hint::black_box(true); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_bool_op.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_bool_op.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_bool_uninit.stderr b/src/tools/miri/tests/fail/validity/invalid_bool_uninit.stderr index 314416766a57a..487e3714b72b3 100644 --- a/src/tools/miri/tests/fail/validity/invalid_bool_uninit.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_bool_uninit.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean - --> $DIR/invalid_bool_uninit.rs:LL:CC + --> tests/fail/validity/invalid_bool_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean @@ -7,7 +7,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_bool_uninit.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_bool_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_char.stderr b/src/tools/miri/tests/fail/validity/invalid_char.stderr index c761669c6db45..5d258176cb65d 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) - --> $DIR/invalid_char.rs:LL:CC + --> tests/fail/validity/invalid_char.rs:LL:CC | LL | let _val = match unsafe { std::mem::transmute::(-1) } { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) @@ -7,7 +7,7 @@ LL | let _val = match unsafe { std::mem::transmute::(-1) } { = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_char.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_char.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr b/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr index 1b5c838cf463c..b88f9f77208b7 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: interpreting an invalid 32-bit value as a char: $HEX - --> $DIR/invalid_char_cast.rs:LL:CC + --> tests/fail/validity/invalid_char_cast.rs:LL:CC | LL | RET = *ptr as u32; | ^^^^^^^^^^^^^^^^^ interpreting an invalid 32-bit value as a char: $HEX @@ -7,9 +7,9 @@ LL | RET = *ptr as u32; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `cast` at $DIR/invalid_char_cast.rs:LL:CC + = note: inside `cast` at tests/fail/validity/invalid_char_cast.rs:LL:CC note: inside `main` - --> $DIR/invalid_char_cast.rs:LL:CC + --> tests/fail/validity/invalid_char_cast.rs:LL:CC | LL | cast(&v as *const u32 as *const char); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/validity/invalid_char_match.stderr b/src/tools/miri/tests/fail/validity/invalid_char_match.stderr index 7706ed97316ce..9ce1631e67fba 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_match.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_match.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: interpreting an invalid 32-bit value as a char: $HEX - --> $DIR/invalid_char_match.rs:LL:CC + --> tests/fail/validity/invalid_char_match.rs:LL:CC | LL | / match *ptr { LL | | '0' => ret, @@ -10,9 +10,9 @@ LL | | } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `switch_int` at $DIR/invalid_char_match.rs:LL:CC + = note: inside `switch_int` at tests/fail/validity/invalid_char_match.rs:LL:CC note: inside `main` - --> $DIR/invalid_char_match.rs:LL:CC + --> tests/fail/validity/invalid_char_match.rs:LL:CC | LL | switch_int(&v as *const u32 as *const char); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/validity/invalid_char_op.stderr b/src/tools/miri/tests/fail/validity/invalid_char_op.stderr index 113eecd9cf7aa..2d84ef3dda6c4 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_op.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_op.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: interpreting an invalid 32-bit value as a char: $HEX - --> $DIR/invalid_char_op.rs:LL:CC + --> tests/fail/validity/invalid_char_op.rs:LL:CC | LL | let _x = c == 'x'; | ^^^^^^^^ interpreting an invalid 32-bit value as a char: $HEX @@ -7,7 +7,7 @@ LL | let _x = c == 'x'; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_char_op.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_char_op.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_char_uninit.stderr b/src/tools/miri/tests/fail/validity/invalid_char_uninit.stderr index 34babac4dd330..6fd311df5ee24 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_uninit.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_uninit.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value - --> $DIR/invalid_char_uninit.rs:LL:CC + --> tests/fail/validity/invalid_char_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value @@ -7,7 +7,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_char_uninit.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_char_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr index 30afb5e8087b4..0736dfb2df119 100644 --- a/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: enum value has invalid tag: 0xff - --> $DIR/invalid_enum_cast.rs:LL:CC + --> tests/fail/validity/invalid_enum_cast.rs:LL:CC | LL | let _val = *ptr as u32; | ^^^^^^^^^^^ enum value has invalid tag: 0xff @@ -7,9 +7,9 @@ LL | let _val = *ptr as u32; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `cast` at $DIR/invalid_enum_cast.rs:LL:CC + = note: inside `cast` at tests/fail/validity/invalid_enum_cast.rs:LL:CC note: inside `main` - --> $DIR/invalid_enum_cast.rs:LL:CC + --> tests/fail/validity/invalid_enum_cast.rs:LL:CC | LL | cast(&v as *const u32 as *const E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_op.stderr index e7997689c51c0..d2cfa86de869d 100644 --- a/src/tools/miri/tests/fail/validity/invalid_enum_op.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: enum value has invalid tag: $HEX - --> $DIR/invalid_enum_op.rs:LL:CC + --> tests/fail/validity/invalid_enum_op.rs:LL:CC | LL | let _val = mem::discriminant(&f); | ^^^^^^^^^^^^^^^^^^^^^ enum value has invalid tag: $HEX @@ -7,7 +7,7 @@ LL | let _val = mem::discriminant(&f); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_enum_op.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_enum_op.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_tag.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_tag.stderr index 5d27062fbc273..5721cfda932fa 100644 --- a/src/tools/miri/tests/fail/validity/invalid_enum_tag.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_enum_tag.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .: encountered $HEX, but expected a valid enum tag - --> $DIR/invalid_enum_tag.rs:LL:CC + --> tests/fail/validity/invalid_enum_tag.rs:LL:CC | LL | let _f = unsafe { std::mem::transmute::(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered $HEX, but expected a valid enum tag @@ -7,7 +7,7 @@ LL | let _f = unsafe { std::mem::transmute::(42) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_enum_tag.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_fnptr_null.stderr b/src/tools/miri/tests/fail/validity/invalid_fnptr_null.stderr index f781ca04f0334..a07b5babe1af3 100644 --- a/src/tools/miri/tests/fail/validity/invalid_fnptr_null.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_fnptr_null.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null function pointer - --> $DIR/invalid_fnptr_null.rs:LL:CC + --> tests/fail/validity/invalid_fnptr_null.rs:LL:CC | LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer @@ -7,7 +7,7 @@ LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_fnptr_null.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_fnptr_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_fnptr_uninit.stderr b/src/tools/miri/tests/fail/validity/invalid_fnptr_uninit.stderr index 54781b507e081..85fabc1836b5a 100644 --- a/src/tools/miri/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer - --> $DIR/invalid_fnptr_uninit.rs:LL:CC + --> tests/fail/validity/invalid_fnptr_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer @@ -7,7 +7,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_fnptr_uninit.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_fnptr_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_int_op.stderr b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr index df344311b7577..c3f47df12f927 100644 --- a/src/tools/miri/tests/fail/validity/invalid_int_op.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/invalid_int_op.rs:LL:CC + --> tests/fail/validity/invalid_int_op.rs:LL:CC | LL | let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_int_op.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_int_op.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_wide_raw.stderr b/src/tools/miri/tests/fail/validity/invalid_wide_raw.stderr index ed34d5255a438..5321dc0f4cfa1 100644 --- a/src/tools/miri/tests/fail/validity/invalid_wide_raw.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_wide_raw.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered null pointer, but expected a vtable pointer - --> $DIR/invalid_wide_raw.rs:LL:CC + --> tests/fail/validity/invalid_wide_raw.rs:LL:CC | LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer @@ -7,7 +7,7 @@ LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_wide_raw.rs:LL:CC + = note: inside `main` at tests/fail/validity/invalid_wide_raw.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr b/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr index a1bfa267cbe0e..ec607512686cc 100644 --- a/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr +++ b/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a value of uninhabited type `main::Void` - --> $DIR/match_binder_checks_validity1.rs:LL:CC + --> tests/fail/validity/match_binder_checks_validity1.rs:LL:CC | LL | _x => println!("hi from the void!"), | ^^ constructing invalid value: encountered a value of uninhabited type `main::Void` @@ -7,7 +7,7 @@ LL | _x => println!("hi from the void!"), = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/match_binder_checks_validity1.rs:LL:CC + = note: inside `main` at tests/fail/validity/match_binder_checks_validity1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr b/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr index 2d8238350f332..0375ead8f55fc 100644 --- a/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr +++ b/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered 0x03, but expected a boolean - --> $DIR/match_binder_checks_validity2.rs:LL:CC + --> tests/fail/validity/match_binder_checks_validity2.rs:LL:CC | LL | _x => println!("hi from the void!"), | ^^ constructing invalid value: encountered 0x03, but expected a boolean @@ -7,7 +7,7 @@ LL | _x => println!("hi from the void!"), = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/match_binder_checks_validity2.rs:LL:CC + = note: inside `main` at tests/fail/validity/match_binder_checks_validity2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/nonzero.stderr b/src/tools/miri/tests/fail/validity/nonzero.stderr index 2add8434ca562..bbf1f9a73ff59 100644 --- a/src/tools/miri/tests/fail/validity/nonzero.stderr +++ b/src/tools/miri/tests/fail/validity/nonzero.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 - --> $DIR/nonzero.rs:LL:CC + --> tests/fail/validity/nonzero.rs:LL:CC | LL | let _x = Some(unsafe { NonZero(0) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -7,7 +7,7 @@ LL | let _x = Some(unsafe { NonZero(0) }); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/nonzero.rs:LL:CC + = note: inside `main` at tests/fail/validity/nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr index 2b2fa9b8a206d..87ac8c179328a 100644 --- a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr +++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .: encountered 0x03, but expected a boolean - --> $DIR/recursive-validity-ref-bool.rs:LL:CC + --> tests/fail/validity/recursive-validity-ref-bool.rs:LL:CC | LL | let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x03, but expected a boolean @@ -7,7 +7,7 @@ LL | let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/recursive-validity-ref-bool.rs:LL:CC + = note: inside `main` at tests/fail/validity/recursive-validity-ref-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/ref_to_uninhabited1.stderr b/src/tools/miri/tests/fail/validity/ref_to_uninhabited1.stderr index d893f7a9e545e..30acfef02fff1 100644 --- a/src/tools/miri/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/src/tools/miri/tests/fail/validity/ref_to_uninhabited1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a box pointing to uninhabited type ! - --> $DIR/ref_to_uninhabited1.rs:LL:CC + --> tests/fail/validity/ref_to_uninhabited1.rs:LL:CC | LL | let x: Box = transmute(&mut 42); | ^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a box pointing to uninhabited type ! @@ -7,7 +7,7 @@ LL | let x: Box = transmute(&mut 42); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ref_to_uninhabited1.rs:LL:CC + = note: inside `main` at tests/fail/validity/ref_to_uninhabited1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/ref_to_uninhabited2.stderr b/src/tools/miri/tests/fail/validity/ref_to_uninhabited2.stderr index 1d9c89c6880c8..1015d1ec42793 100644 --- a/src/tools/miri/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/src/tools/miri/tests/fail/validity/ref_to_uninhabited2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a reference pointing to uninhabited type (i32, Void) - --> $DIR/ref_to_uninhabited2.rs:LL:CC + --> tests/fail/validity/ref_to_uninhabited2.rs:LL:CC | LL | let _x: &(i32, Void) = transmute(&42); | ^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type (i32, Void) @@ -7,7 +7,7 @@ LL | let _x: &(i32, Void) = transmute(&42); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/ref_to_uninhabited2.rs:LL:CC + = note: inside `main` at tests/fail/validity/ref_to_uninhabited2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/too-big-slice.stderr b/src/tools/miri/tests/fail/validity/too-big-slice.stderr index 2abe6c6fdf3d0..2b0a8f03813c4 100644 --- a/src/tools/miri/tests/fail/validity/too-big-slice.stderr +++ b/src/tools/miri/tests/fail/validity/too-big-slice.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object - --> $DIR/too-big-slice.rs:LL:CC + --> tests/fail/validity/too-big-slice.rs:LL:CC | LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -7,7 +7,7 @@ LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/too-big-slice.rs:LL:CC + = note: inside `main` at tests/fail/validity/too-big-slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/too-big-unsized.stderr b/src/tools/miri/tests/fail/validity/too-big-unsized.stderr index bc8a140ac22c0..1e8b37979b0b6 100644 --- a/src/tools/miri/tests/fail/validity/too-big-unsized.stderr +++ b/src/tools/miri/tests/fail/validity/too-big-unsized.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered invalid reference metadata: total size is bigger than largest supported object - --> $DIR/too-big-unsized.rs:LL:CC + --> tests/fail/validity/too-big-unsized.rs:LL:CC | LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: total size is bigger than largest supported object @@ -7,7 +7,7 @@ LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC + = note: inside `main` at tests/fail/validity/too-big-unsized.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/transmute_through_ptr.stderr b/src/tools/miri/tests/fail/validity/transmute_through_ptr.stderr index fcd077daa38ff..bbb40d1f58f0b 100644 --- a/src/tools/miri/tests/fail/validity/transmute_through_ptr.stderr +++ b/src/tools/miri/tests/fail/validity/transmute_through_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .: encountered $HEX, but expected a valid enum tag - --> $DIR/transmute_through_ptr.rs:LL:CC + --> tests/fail/validity/transmute_through_ptr.rs:LL:CC | LL | let y = x; // reading this ought to be enough to trigger validation | ^ constructing invalid value at .: encountered $HEX, but expected a valid enum tag @@ -7,7 +7,7 @@ LL | let y = x; // reading this ought to be enough to trigger validation = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/transmute_through_ptr.rs:LL:CC + = note: inside `main` at tests/fail/validity/transmute_through_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/uninit_float.stderr b/src/tools/miri/tests/fail/validity/uninit_float.stderr index 3d7ec44fdb064..a6ca0f40f0db3 100644 --- a/src/tools/miri/tests/fail/validity/uninit_float.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_float.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number - --> $DIR/uninit_float.rs:LL:CC + --> tests/fail/validity/uninit_float.rs:LL:CC | LL | let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number @@ -7,7 +7,7 @@ LL | let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/uninit_float.rs:LL:CC + = note: inside `main` at tests/fail/validity/uninit_float.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/uninit_integer.stderr b/src/tools/miri/tests/fail/validity/uninit_integer.stderr index 55f3f803ad14c..b983832799b16 100644 --- a/src/tools/miri/tests/fail/validity/uninit_integer.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_integer.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer - --> $DIR/uninit_integer.rs:LL:CC + --> tests/fail/validity/uninit_integer.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer @@ -7,7 +7,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assum = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/uninit_integer.rs:LL:CC + = note: inside `main` at tests/fail/validity/uninit_integer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr index fed1cf4587431..83af585201a93 100644 --- a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer - --> $DIR/uninit_raw_ptr.rs:LL:CC + --> tests/fail/validity/uninit_raw_ptr.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer @@ -7,7 +7,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().a = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/uninit_raw_ptr.rs:LL:CC + = note: inside `main` at tests/fail/validity/uninit_raw_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs new file mode 100644 index 0000000000000..1478abedee0d8 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs @@ -0,0 +1,18 @@ +trait Trait { + type Assoc; + fn foo(&self) -> Self::Assoc; +} + +impl Trait for T { + type Assoc = T; + fn foo(&self) -> T { *self } +} + +fn main() { + let v: Box> = Box::new(2); + let v: Box> = unsafe { std::mem::transmute(v) }; //~ERROR: wrong trait + + if v.foo() { + println!("huh"); + } +} diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr new file mode 100644 index 0000000000000..44939a5a838cc --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` + --> tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC + | +LL | let v: Box> = unsafe { std::mem::transmute(v) }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr index 1219f9f88cf8c..0b5163f711ec4 100644 --- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` - --> $DIR/wrong-dyn-trait-generic.rs:LL:CC + --> tests/fail/validity/wrong-dyn-trait-generic.rs:LL:CC | LL | let _y: *const dyn Trait = unsafe { mem::transmute(x) }; | ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` @@ -7,7 +7,7 @@ LL | let _y: *const dyn Trait = unsafe { mem::transmute(x) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/wrong-dyn-trait-generic.rs:LL:CC + = note: inside `main` at tests/fail/validity/wrong-dyn-trait-generic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr index e3503323b31a7..45c882bebdfc6 100644 --- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr @@ -1,13 +1,13 @@ -error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `` - --> $DIR/wrong-dyn-trait.rs:LL:CC +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send` + --> tests/fail/validity/wrong-dyn-trait.rs:LL:CC | LL | let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) }; - | ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `` + | ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/wrong-dyn-trait.rs:LL:CC + = note: inside `main` at tests/fail/validity/wrong-dyn-trait.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr index 44430cd25db72..a437ca3425853 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Race condition detected between (1) 4-byte atomic store on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/racing_mixed_size.rs:LL:CC + --> tests/fail/weak_memory/racing_mixed_size.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic store on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/racing_mixed_size.rs:LL:CC + --> tests/fail/weak_memory/racing_mixed_size.rs:LL:CC | LL | x.store(1, Relaxed); | ^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | x.store(1, Relaxed); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC + = note: inside closure at tests/fail/weak_memory/racing_mixed_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr index 94b4123d34567..9e6a6e80418cf 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Race condition detected between (1) 4-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/racing_mixed_size_read.rs:LL:CC + --> tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC | LL | (*hi).load(Relaxed); | ^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> $DIR/racing_mixed_size_read.rs:LL:CC + --> tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC | LL | x.load(Relaxed); | ^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | x.load(Relaxed); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC + = note: inside closure at tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr b/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr index 9aa5bc2fa76df..816bd323f4cc4 100644 --- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr +++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/weak_uninit.rs:LL:CC + --> tests/fail/weak_memory/weak_uninit.rs:LL:CC | LL | let j2 = spawn(move || x.load(Ordering::Relaxed)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | let j2 = spawn(move || x.load(Ordering::Relaxed)); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at $DIR/weak_uninit.rs:LL:CC + = note: inside closure at tests/fail/weak_memory/weak_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/zst_local_oob.stderr b/src/tools/miri/tests/fail/zst_local_oob.stderr index 39ac2c91437c6..26911948eff71 100644 --- a/src/tools/miri/tests/fail/zst_local_oob.stderr +++ b/src/tools/miri/tests/fail/zst_local_oob.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes - --> $DIR/zst_local_oob.rs:LL:CC + --> tests/fail/zst_local_oob.rs:LL:CC | LL | let _val = unsafe { *x }; | ^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes @@ -7,7 +7,7 @@ LL | let _val = unsafe { *x }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/zst_local_oob.rs:LL:CC + = note: inside `main` at tests/fail/zst_local_oob.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/native-lib/fail/function_not_in_so.rs b/src/tools/miri/tests/native-lib/fail/function_not_in_so.rs index 3540c75b73a12..a7df3e6118725 100644 --- a/src/tools/miri/tests/native-lib/fail/function_not_in_so.rs +++ b/src/tools/miri/tests/native-lib/fail/function_not_in_so.rs @@ -1,4 +1,5 @@ -//@only-target-linux +// Only works on Unix targets +//@ignore-target: windows wasm //@only-on-host //@normalize-stderr-test: "OS `.*`" -> "$$OS" diff --git a/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr b/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr index e905d7d039143..bf1cfd573b8a5 100644 --- a/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr +++ b/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr @@ -1,5 +1,5 @@ error: unsupported operation: can't call foreign function `foo` on $OS - --> $DIR/function_not_in_so.rs:LL:CC + --> tests/native-lib/fail/function_not_in_so.rs:LL:CC | LL | foo(); | ^^^^^ can't call foreign function `foo` on $OS @@ -7,7 +7,7 @@ LL | foo(); = help: if this is a basic API commonly used on this target, please report an issue with Miri = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases = note: BACKTRACE: - = note: inside `main` at $DIR/function_not_in_so.rs:LL:CC + = note: inside `main` at tests/native-lib/fail/function_not_in_so.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/native-lib/fail/private_function.rs b/src/tools/miri/tests/native-lib/fail/private_function.rs new file mode 100644 index 0000000000000..e54880e97dabc --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/private_function.rs @@ -0,0 +1,14 @@ +// Only works on Unix targets +//@ignore-target: windows wasm +//@only-on-host +//@normalize-stderr-test: "OS `.*`" -> "$$OS" + +extern "C" { + fn not_exported(); +} + +fn main() { + unsafe { + not_exported(); //~ ERROR: unsupported operation: can't call foreign function `not_exported` + } +} diff --git a/src/tools/miri/tests/native-lib/fail/private_function.stderr b/src/tools/miri/tests/native-lib/fail/private_function.stderr new file mode 100644 index 0000000000000..2cfc062212b6d --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/private_function.stderr @@ -0,0 +1,15 @@ +error: unsupported operation: can't call foreign function `not_exported` on $OS + --> tests/native-lib/fail/private_function.rs:LL:CC + | +LL | not_exported(); + | ^^^^^^^^^^^^^^ can't call foreign function `not_exported` on $OS + | + = help: if this is a basic API commonly used on this target, please report an issue with Miri + = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases + = note: BACKTRACE: + = note: inside `main` at tests/native-lib/fail/private_function.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/native-lib/native-lib.map b/src/tools/miri/tests/native-lib/native-lib.map deleted file mode 100644 index 7e3bd19622af3..0000000000000 --- a/src/tools/miri/tests/native-lib/native-lib.map +++ /dev/null @@ -1,20 +0,0 @@ -CODEABI_1.0 { - # Define which symbols to export. - global: - # scalar_arguments.c - add_one_int; - printer; - test_stack_spill; - get_unsigned_int; - add_int16; - add_short_to_long; - - # ptr_read_access.c - print_pointer; - access_simple; - access_nested; - access_static; - - # The rest remains private. - local: *; -}; diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs index d8e6209839e2a..46eb5778b3258 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs @@ -1,4 +1,5 @@ -//@only-target-linux +// Only works on Unix targets +//@ignore-target: windows wasm //@only-on-host fn main() { @@ -26,7 +27,7 @@ fn test_pointer() { fn test_simple() { #[repr(C)] struct Simple { - field: i32 + field: i32, } extern "C" { @@ -41,7 +42,7 @@ fn test_simple() { // Test function that dereferences nested struct pointers and accesses fields. fn test_nested() { use std::ptr::NonNull; - + #[derive(Debug, PartialEq, Eq)] #[repr(C)] struct Nested { @@ -62,7 +63,6 @@ fn test_nested() { // Test function that dereferences static struct pointers and accesses fields. fn test_static() { - #[repr(C)] struct Static { value: i32, @@ -72,11 +72,8 @@ fn test_static() { extern "C" { fn access_static(n_ptr: *const Static) -> i32; } - - static STATIC: Static = Static { - value: 9001, - recurse: &STATIC, - }; + + static STATIC: Static = Static { value: 9001, recurse: &STATIC }; assert_eq!(unsafe { access_static(&STATIC) }, 9001); } diff --git a/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs b/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs index 1e1d0b11e99ff..c896bd8dd345f 100644 --- a/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs +++ b/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs @@ -1,4 +1,5 @@ -//@only-target-linux +// Only works on Unix targets +//@ignore-target: windows wasm //@only-on-host extern "C" { diff --git a/src/tools/miri/tests/native-lib/ptr_read_access.c b/src/tools/miri/tests/native-lib/ptr_read_access.c index 03b9189e2e86d..540845d53a744 100644 --- a/src/tools/miri/tests/native-lib/ptr_read_access.c +++ b/src/tools/miri/tests/native-lib/ptr_read_access.c @@ -1,8 +1,11 @@ #include +// See comments in build_native_lib() +#define EXPORT __attribute__((visibility("default"))) + /* Test: test_pointer */ -void print_pointer(const int *ptr) { +EXPORT void print_pointer(const int *ptr) { printf("printing pointer dereference from C: %d\n", *ptr); } @@ -12,7 +15,7 @@ typedef struct Simple { int field; } Simple; -int access_simple(const Simple *s_ptr) { +EXPORT int access_simple(const Simple *s_ptr) { return s_ptr->field; } @@ -24,7 +27,7 @@ typedef struct Nested { } Nested; // Returns the innermost/last value of a Nested pointer chain. -int access_nested(const Nested *n_ptr) { +EXPORT int access_nested(const Nested *n_ptr) { // Edge case: `n_ptr == NULL` (i.e. first Nested is None). if (!n_ptr) { return 0; } @@ -42,6 +45,6 @@ typedef struct Static { struct Static *recurse; } Static; -int access_static(const Static *s_ptr) { +EXPORT int access_static(const Static *s_ptr) { return s_ptr->recurse->recurse->value; } diff --git a/src/tools/miri/tests/native-lib/scalar_arguments.c b/src/tools/miri/tests/native-lib/scalar_arguments.c index 68714f1743b6e..6da730a498724 100644 --- a/src/tools/miri/tests/native-lib/scalar_arguments.c +++ b/src/tools/miri/tests/native-lib/scalar_arguments.c @@ -1,27 +1,35 @@ #include -int add_one_int(int x) { +// See comments in build_native_lib() +#define EXPORT __attribute__((visibility("default"))) + +EXPORT int add_one_int(int x) { return 2 + x; } -void printer() { +EXPORT void printer(void) { printf("printing from C\n"); } // function with many arguments, to test functionality when some args are stored // on the stack -int test_stack_spill(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) { +EXPORT int test_stack_spill(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) { return a+b+c+d+e+f+g+h+i+j+k+l; } -unsigned int get_unsigned_int() { +EXPORT unsigned int get_unsigned_int(void) { return -10; } -short add_int16(short x) { +EXPORT short add_int16(short x) { return x + 3; } -long add_short_to_long(short x, long y) { +EXPORT long add_short_to_long(short x, long y) { return x + y; } + +// To test that functions not marked with EXPORT cannot be called by Miri. +int not_exported(void) { + return 0; +} diff --git a/src/tools/miri/tests/panic/alloc_error_handler_hook.stderr b/src/tools/miri/tests/panic/alloc_error_handler_hook.stderr index 319a10febb372..363298e49d99b 100644 --- a/src/tools/miri/tests/panic/alloc_error_handler_hook.stderr +++ b/src/tools/miri/tests/panic/alloc_error_handler_hook.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/alloc_error_handler_hook.rs:LL:CC: +thread 'main' panicked at tests/panic/alloc_error_handler_hook.rs:LL:CC: alloc error hook called note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/div-by-zero-2.stderr b/src/tools/miri/tests/panic/div-by-zero-2.stderr index ed394f76b0e00..e47a754d38dde 100644 --- a/src/tools/miri/tests/panic/div-by-zero-2.stderr +++ b/src/tools/miri/tests/panic/div-by-zero-2.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/div-by-zero-2.rs:LL:CC: +thread 'main' panicked at tests/panic/div-by-zero-2.rs:LL:CC: attempt to divide by zero note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr index 6733f2e42c1a7..ec75b6201c280 100644 --- a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr +++ b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr @@ -1,8 +1,8 @@ -thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC: +thread 'main' panicked at tests/panic/function_calls/exported_symbol_good_unwind.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC: +thread 'main' panicked at tests/panic/function_calls/exported_symbol_good_unwind.rs:LL:CC: explicit panic -thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC: +thread 'main' panicked at tests/panic/function_calls/exported_symbol_good_unwind.rs:LL:CC: explicit panic diff --git a/src/tools/miri/tests/panic/mir-validation.rs b/src/tools/miri/tests/panic/mir-validation.rs index f1d0ccc7d0376..e4b75cccbb5c4 100644 --- a/src/tools/miri/tests/panic/mir-validation.rs +++ b/src/tools/miri/tests/panic/mir-validation.rs @@ -7,7 +7,7 @@ //@normalize-stderr-test: "DefId\([^()]*\)" -> "DefId" // Somehow on rustc Windows CI, the "Miri caused an ICE" message is not shown // and we don't even get a regular panic; rustc aborts with a different exit code instead. -//@ignore-host-windows +//@ignore-host: windows #![feature(custom_mir, core_intrinsics)] use core::intrinsics::mir::*; diff --git a/src/tools/miri/tests/panic/oob_subslice.stderr b/src/tools/miri/tests/panic/oob_subslice.stderr index 46f0f643a4728..d608cec20a487 100644 --- a/src/tools/miri/tests/panic/oob_subslice.stderr +++ b/src/tools/miri/tests/panic/oob_subslice.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/oob_subslice.rs:LL:CC: +thread 'main' panicked at tests/panic/oob_subslice.rs:LL:CC: range end index 5 out of range for slice of length 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr b/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr index be822bd02852f..29150052b30d7 100644 --- a/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr +++ b/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/overflowing-lsh-neg.rs:LL:CC: +thread 'main' panicked at tests/panic/overflowing-lsh-neg.rs:LL:CC: attempt to shift left with overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/overflowing-rsh-1.stderr b/src/tools/miri/tests/panic/overflowing-rsh-1.stderr index fc090aba5fdb5..9a71a797dae8b 100644 --- a/src/tools/miri/tests/panic/overflowing-rsh-1.stderr +++ b/src/tools/miri/tests/panic/overflowing-rsh-1.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/overflowing-rsh-1.rs:LL:CC: +thread 'main' panicked at tests/panic/overflowing-rsh-1.rs:LL:CC: attempt to shift right with overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/overflowing-rsh-2.stderr b/src/tools/miri/tests/panic/overflowing-rsh-2.stderr index 77160e1870f96..b671c53c611db 100644 --- a/src/tools/miri/tests/panic/overflowing-rsh-2.stderr +++ b/src/tools/miri/tests/panic/overflowing-rsh-2.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/overflowing-rsh-2.rs:LL:CC: +thread 'main' panicked at tests/panic/overflowing-rsh-2.rs:LL:CC: attempt to shift right with overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/panic1.stderr b/src/tools/miri/tests/panic/panic1.stderr index 4eb4244d7472c..7e011bfd53b14 100644 --- a/src/tools/miri/tests/panic/panic1.stderr +++ b/src/tools/miri/tests/panic/panic1.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic1.rs:LL:CC: +thread 'main' panicked at tests/panic/panic1.rs:LL:CC: panicking from libstd stack backtrace: 0: std::panicking::begin_panic_handler @@ -6,7 +6,7 @@ stack backtrace: 1: std::rt::panic_fmt at RUSTLIB/core/src/panicking.rs:LL:CC 2: main - at $DIR/panic1.rs:LL:CC + at tests/panic/panic1.rs:LL:CC 3: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/src/tools/miri/tests/panic/panic2.stderr b/src/tools/miri/tests/panic/panic2.stderr index f7408310093d7..5640bd0b8d6a1 100644 --- a/src/tools/miri/tests/panic/panic2.stderr +++ b/src/tools/miri/tests/panic/panic2.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic2.rs:LL:CC: +thread 'main' panicked at tests/panic/panic2.rs:LL:CC: 42-panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/panic3.stderr b/src/tools/miri/tests/panic/panic3.stderr index 32ba400e025c3..0114320503b1d 100644 --- a/src/tools/miri/tests/panic/panic3.stderr +++ b/src/tools/miri/tests/panic/panic3.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic3.rs:LL:CC: +thread 'main' panicked at tests/panic/panic3.rs:LL:CC: panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/panic4.stderr b/src/tools/miri/tests/panic/panic4.stderr index a8a23ee3ce14f..f13b355ea45ab 100644 --- a/src/tools/miri/tests/panic/panic4.stderr +++ b/src/tools/miri/tests/panic/panic4.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic4.rs:LL:CC: +thread 'main' panicked at tests/panic/panic4.rs:LL:CC: 42-panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/transmute_fat2.stderr b/src/tools/miri/tests/panic/transmute_fat2.stderr index 021ca1c4b3298..a9bc0eb9d01c8 100644 --- a/src/tools/miri/tests/panic/transmute_fat2.stderr +++ b/src/tools/miri/tests/panic/transmute_fat2.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/transmute_fat2.rs:LL:CC: +thread 'main' panicked at tests/panic/transmute_fat2.rs:LL:CC: index out of bounds: the len is 0 but the index is 0 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/unsupported_foreign_function.stderr b/src/tools/miri/tests/panic/unsupported_foreign_function.stderr index fcc4220bfceb8..278af9612d655 100644 --- a/src/tools/miri/tests/panic/unsupported_foreign_function.stderr +++ b/src/tools/miri/tests/panic/unsupported_foreign_function.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/unsupported_foreign_function.rs:LL:CC: +thread 'main' panicked at tests/panic/unsupported_foreign_function.rs:LL:CC: unsupported Miri functionality: can't call foreign function `foo` on $OS note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/unsupported_syscall.rs b/src/tools/miri/tests/panic/unsupported_syscall.rs index 30f9da5f80e78..bbb076b169a6a 100644 --- a/src/tools/miri/tests/panic/unsupported_syscall.rs +++ b/src/tools/miri/tests/panic/unsupported_syscall.rs @@ -1,5 +1,5 @@ -//@ignore-target-windows: no `syscall` on Windows -//@ignore-target-apple: `syscall` is not supported on macOS +//@ignore-target: windows # no `syscall` on Windows +//@ignore-target: apple # `syscall` is not supported on macOS //@compile-flags: -Zmiri-panic-on-unsupported fn main() { diff --git a/src/tools/miri/tests/panic/unsupported_syscall.stderr b/src/tools/miri/tests/panic/unsupported_syscall.stderr index 660cfba8900f7..e9b2b5b665227 100644 --- a/src/tools/miri/tests/panic/unsupported_syscall.stderr +++ b/src/tools/miri/tests/panic/unsupported_syscall.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/unsupported_syscall.rs:LL:CC: +thread 'main' panicked at tests/panic/unsupported_syscall.rs:LL:CC: unsupported Miri functionality: can't execute syscall with ID 0 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs index c2b9c37bbfb27..0fc432f24c8ec 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs @@ -1,4 +1,4 @@ -//@ only-target-darwin +//@only-target: darwin use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs index 86a47ba365526..c9c9dc5dfd2ac 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: No libc env support on Windows +//@ignore-target: windows # No libc env support on Windows use std::ffi::CStr; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs index 399d6df73ff12..255a93226a958 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs @@ -1,6 +1,9 @@ -//@only-target-linux +//@only-target: linux //@compile-flags: -Zmiri-disable-isolation +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use std::mem::MaybeUninit; use std::ptr::{self, addr_of}; use std::sync::atomic::AtomicI32; diff --git a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs index 52348aad33d72..2dc09709b8eed 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs @@ -1,10 +1,13 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows //! Test that pthread_key destructors are run in the right order. //! Note that these are *not* used by actual `thread_local!` on Linux! Those use //! `destructors::register` from the stdlib instead. In Miri this ends up hitting //! the fallback path in `guard::key::enable`, which uses a *single* pthread_key //! to manage a thread-local list of dtors to call. +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use std::mem; use std::ptr; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs index 3d4f8c5e1c063..fe2d20bb76f8e 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs @@ -1,4 +1,4 @@ -//@only-target-windows: Uses win32 api functions +//@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs index 5e33617f98ad1..6853395686aa9 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs @@ -1,4 +1,4 @@ -//@only-target-windows: Uses win32 api functions +//@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 @@ -7,7 +7,7 @@ use std::thread; use windows_sys::Win32::Foundation::{FALSE, TRUE}; use windows_sys::Win32::System::Threading::{ - InitOnceBeginInitialize, InitOnceComplete, INIT_ONCE, INIT_ONCE_INIT_FAILED, + INIT_ONCE, INIT_ONCE_INIT_FAILED, InitOnceBeginInitialize, InitOnceComplete, }; // not in windows-sys diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs index bff59591a94ad..ce829eee22704 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs @@ -1,4 +1,4 @@ -//@only-target-windows: Uses win32 api functions +//@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 @@ -7,7 +7,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::thread; use windows_sys::Win32::Foundation::{HANDLE, WAIT_OBJECT_0}; -use windows_sys::Win32::System::Threading::{WaitForSingleObject, INFINITE}; +use windows_sys::Win32::System::Threading::{INFINITE, WaitForSingleObject}; fn main() { static FLAG: AtomicBool = AtomicBool::new(false); diff --git a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs index 1198168795daf..9e5627c75a97a 100644 --- a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs +++ b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No `dlsym` on Windows +//@ignore-target: windows # No `dlsym` on Windows //@compile-flags: -Zmiri-permissive-provenance #[path = "../utils/mod.rs"] diff --git a/src/tools/miri/tests/pass-dep/libc/ccrandomgeneratebytes_apple.rs b/src/tools/miri/tests/pass-dep/libc/ccrandomgeneratebytes_apple.rs new file mode 100644 index 0000000000000..afcc02bc83971 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/ccrandomgeneratebytes_apple.rs @@ -0,0 +1,7 @@ +//@only-target: apple # This directly tests apple-only functions + +fn main() { + let mut bytes = [0u8; 24]; + let ret = unsafe { libc::CCRandomGenerateBytes(bytes.as_mut_ptr().cast(), bytes.len()) }; + assert_eq!(ret, libc::kCCSuccess); +} diff --git a/src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.rs b/src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.rs index 307906f2583b2..7dddfa6661388 100644 --- a/src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.rs +++ b/src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.rs @@ -1,4 +1,4 @@ -//@only-target-apple: F_FULLFSYNC only on apple systems +//@only-target: apple # F_FULLFSYNC only on apple systems //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace use std::io::Error; diff --git a/src/tools/miri/tests/pass-dep/libc/gettid.rs b/src/tools/miri/tests/pass-dep/libc/gettid.rs index 87405b02ac35d..ca352e0109a47 100644 --- a/src/tools/miri/tests/pass-dep/libc/gettid.rs +++ b/src/tools/miri/tests/pass-dep/libc/gettid.rs @@ -1,4 +1,4 @@ -//@only-target-linux +//@only-target: linux //@revisions: with_isolation without_isolation //@[without_isolation] compile-flags: -Zmiri-disable-isolation diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs index 0e482ab26010e..ff152eaea5c50 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs @@ -1,5 +1,5 @@ -//@ignore-target-windows: only very limited libc on Windows -//@ignore-target-apple: `sched_{g, s}etaffinity` are not supported on macOS +//@ignore-target: windows # only very limited libc on Windows +//@ignore-target: apple # `sched_{g, s}etaffinity` are not supported on macOS //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4 #![feature(io_error_more)] #![feature(pointer_is_aligned_to)] diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs index 2a5d3dff07f91..eb38529ae57df 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs @@ -1,4 +1,4 @@ -//@only-target-linux +//@only-target: linux // test_epoll_block_then_unblock depends on a deterministic schedule. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs index 647b5e60649e8..3ea345133769b 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs @@ -1,4 +1,4 @@ -//@only-target-linux +//@only-target: linux #![feature(strict_provenance)] use std::convert::TryInto; @@ -23,6 +23,7 @@ fn main() { test_ready_list_fetching_logic(); test_epoll_ctl_epfd_equal_fd(); test_epoll_ctl_notification(); + test_issue_3858(); } // Using `as` cast since `EPOLLET` wraps around @@ -230,10 +231,10 @@ fn test_two_same_fd_in_same_epoll_instance() { //Two notification should be received. let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); let expected_value = 5 as u64; - check_epoll_wait::<8>( - epfd, - &[(expected_event, expected_value), (expected_event, expected_value)], - ); + check_epoll_wait::<8>(epfd, &[ + (expected_event, expected_value), + (expected_event, expected_value), + ]); } fn test_epoll_eventfd() { @@ -290,10 +291,10 @@ fn test_epoll_socketpair_both_sides() { let expected_value0 = fds[0] as u64; let expected_event1 = u32::try_from(libc::EPOLLOUT).unwrap(); let expected_value1 = fds[1] as u64; - check_epoll_wait::<8>( - epfd, - &[(expected_event0, expected_value0), (expected_event1, expected_value1)], - ); + check_epoll_wait::<8>(epfd, &[ + (expected_event0, expected_value0), + (expected_event1, expected_value1), + ]); // Read from fds[0]. let mut buf: [u8; 5] = [0; 5]; @@ -453,10 +454,10 @@ fn test_socketpair_read() { let expected_value0 = fds[0] as u64; let expected_event1 = u32::try_from(libc::EPOLLOUT).unwrap(); let expected_value1 = fds[1] as u64; - check_epoll_wait::<8>( - epfd, - &[(expected_event0, expected_value0), (expected_event1, expected_value1)], - ); + check_epoll_wait::<8>(epfd, &[ + (expected_event0, expected_value0), + (expected_event1, expected_value1), + ]); // Read 3 bytes from fds[0]. let mut buf: [u8; 3] = [0; 3]; @@ -683,3 +684,40 @@ fn test_epoll_ctl_notification() { // for this epfd, because there is no I/O event between the two epoll_wait. check_epoll_wait::<1>(epfd0, &[]); } + +// Test for ICE caused by weak epoll interest upgrade succeed, but the attempt to retrieve +// the epoll instance based on the epoll file descriptor value failed. EpollEventInterest +// should store a WeakFileDescriptionRef instead of the file descriptor number, so if the +// epoll instance is duped, it'd still be usable after `close` is called on the original +// epoll file descriptor. +// https://github.com/rust-lang/miri/issues/3858 +fn test_issue_3858() { + // Create an eventfd instance. + let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + + // Create an epoll instance. + let epfd = unsafe { libc::epoll_create1(0) }; + assert_ne!(epfd, -1); + + // Register eventfd with EPOLLIN | EPOLLET. + let mut ev = libc::epoll_event { + events: (libc::EPOLLIN | libc::EPOLLET) as _, + u64: u64::try_from(fd).unwrap(), + }; + let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; + assert_eq!(res, 0); + + // Dup the epoll instance. + let newfd = unsafe { libc::dup(epfd) }; + assert_ne!(newfd, -1); + + // Close the old epoll instance, so the new FD is now the only FD. + let res = unsafe { libc::close(epfd) }; + assert_eq!(res, 0); + + // Write to the eventfd instance. + let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes(); + let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) }; + assert_eq!(res, 8); +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs index a3567eeb7cb4a..1d08419465889 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs @@ -1,7 +1,10 @@ -//@only-target-linux +//@only-target: linux // test_race depends on a deterministic schedule. //@compile-flags: -Zmiri-preemption-rate=0 +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use std::thread; fn main() { diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs index 3f7f9b18be931..be11f65a1e081 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: File handling is not implemented yet +//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation use std::{fs::File, io::Error, os::fd::AsRawFd}; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs index 619c6db3a29de..a35c92636ce64 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs @@ -1,6 +1,6 @@ // Symlink tests are separate since they don't in general work on a Windows host. -//@ignore-host-windows: creating symlinks requires admin permissions on Windows -//@ignore-target-windows: File handling is not implemented yet +//@ignore-host: windows # creating symlinks requires admin permissions on Windows +//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation use std::ffi::CString; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs index 088a632427e70..ab3fd6733ffe5 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: File handling is not implemented yet +//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 5b2bbfbb27d08..17e6e507c2750 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -1,11 +1,11 @@ -//@ignore-target-windows: File handling is not implemented yet +//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] #![feature(io_error_uncategorized)] use std::ffi::{CStr, CString, OsString}; -use std::fs::{canonicalize, remove_file, File}; +use std::fs::{File, canonicalize, remove_file}; use std::io::{Error, ErrorKind, Write}; use std::os::unix::ffi::OsStrExt; use std::os::unix::io::AsRawFd; @@ -169,7 +169,7 @@ fn test_ftruncate>( #[cfg(target_os = "linux")] fn test_o_tmpfile_flag() { - use std::fs::{create_dir, OpenOptions}; + use std::fs::{OpenOptions, create_dir}; use std::os::unix::fs::OpenOptionsExt; let dir_path = utils::prepare_dir("miri_test_fs_dir"); create_dir(&dir_path).unwrap(); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs index aa383a99bc289..c399616b9aee5 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs @@ -101,6 +101,10 @@ fn test_malloc() { let slice = slice::from_raw_parts(p3 as *const u8, 20); assert_eq!(&slice, &[0_u8; 20]); + // new size way too big (so this doesn't actually realloc). + let p_too_big = libc::realloc(p3, usize::MAX); + assert!(p_too_big.is_null()); + // old size > new size let p4 = libc::realloc(p3, 10); let slice = slice::from_raw_parts(p4 as *const u8, 10); @@ -119,9 +123,13 @@ fn test_malloc() { unsafe { let p1 = libc::realloc(ptr::null_mut(), 20); assert!(!p1.is_null()); - libc::free(p1); } + + unsafe { + let p_too_big = libc::malloc(usize::MAX); + assert!(p_too_big.is_null()); + } } fn test_calloc() { @@ -143,6 +151,9 @@ fn test_calloc() { let slice = slice::from_raw_parts(p4 as *const u8, 4 * 8); assert_eq!(&slice, &[0_u8; 4 * 8]); libc::free(p4); + + let p_too_big = libc::calloc(usize::MAX / 4, 4); + assert!(p_too_big.is_null()); } } diff --git a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs index a5b944e9d426a..f3261eaa43c92 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: only very limited libc on Windows +//@ignore-target: windows # only very limited libc on Windows //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] #![feature(pointer_is_aligned_to)] diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index 90dbd888392bf..76f883e5d8d58 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc pipe on Windows +//@ignore-target: windows # No libc pipe on Windows // test_race depends on a deterministic schedule. //@compile-flags: -Zmiri-preemption-rate=0 use std::thread; @@ -72,6 +72,8 @@ fn test_pipe_threaded() { thread2.join().unwrap(); } +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#[allow(static_mut_refs)] fn test_race() { static mut VAL: u8 = 0; let mut fds = [-1, -1]; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-random.rs b/src/tools/miri/tests/pass-dep/libc/libc-random.rs index 71e335226345e..e951603639c3f 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-random.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-random.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: no libc +//@ignore-target: windows # no libc //@revisions: isolation no_isolation //@[no_isolation]compile-flags: -Zmiri-disable-isolation diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs index 15e040116debc..64819e576799f 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs @@ -1,6 +1,10 @@ -//@ignore-target-windows: No libc socketpair on Windows +//@ignore-target: windows # No libc socketpair on Windows // test_race depends on a deterministic schedule. //@compile-flags: -Zmiri-preemption-rate=0 + +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use std::thread; fn main() { test_socketpair(); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index 5e4bb73e36883..c2c875864920a 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: no libc time APIs on Windows +//@ignore-target: windows # no libc time APIs on Windows //@compile-flags: -Zmiri-disable-isolation use std::{env, mem, ptr}; diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs b/src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait.rs similarity index 96% rename from src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs rename to src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait.rs index d758168c7c30d..997fd5cc89fd5 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait.rs @@ -1,5 +1,5 @@ -//@ignore-target-windows: No pthreads on Windows -//@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS. +//@ignore-target: windows # No pthreads on Windows +//@ignore-target: apple # pthread_condattr_setclock is not supported on MacOS. //@compile-flags: -Zmiri-disable-isolation /// Test that conditional variable timeouts are working properly with both diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs b/src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait_isolated.rs similarity index 96% rename from src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs rename to src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait_isolated.rs index f1a3c5dc10d07..0479d26af7250 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait_isolated.rs @@ -1,5 +1,5 @@ -//@ignore-target-windows: No pthreads on Windows -//@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS. +//@ignore-target: windows # No pthreads 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. diff --git a/src/tools/miri/tests/pass-dep/libc/mmap.rs b/src/tools/miri/tests/pass-dep/libc/mmap.rs index fd874dbe89e55..db305acbf4a7e 100644 --- a/src/tools/miri/tests/pass-dep/libc/mmap.rs +++ b/src/tools/miri/tests/pass-dep/libc/mmap.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No mmap on Windows +//@ignore-target: windows # No mmap on Windows //@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance #![feature(strict_provenance)] diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs index 142752621280a..75848bd44db70 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows // We use `yield` to test specific interleavings, so disable automatic preemption. //@compile-flags: -Zmiri-preemption-rate=0 #![feature(sync_unsafe_cell)] diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs index d66cd3bbb034d..a94f960f442fe 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No pthreads on Windows +//@ignore-target: windows # No pthreads on Windows use std::ffi::CStr; #[cfg(not(target_os = "freebsd"))] use std::ffi::CString; @@ -10,16 +10,42 @@ fn main() { .collect::(); fn set_thread_name(name: &CStr) -> i32 { - #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] - return unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) }; - #[cfg(target_os = "freebsd")] - unsafe { - // pthread_set_name_np does not return anything - libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr().cast()); - return 0; - }; - #[cfg(target_os = "macos")] - return unsafe { libc::pthread_setname_np(name.as_ptr().cast()) }; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] { + unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) } + } else if #[cfg(target_os = "freebsd")] { + // pthread_set_name_np does not return anything + unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr().cast()) }; + 0 + } else if #[cfg(target_os = "macos")] { + unsafe { libc::pthread_setname_np(name.as_ptr().cast()) } + } else { + compile_error!("set_thread_name not supported for this OS") + } + } + } + + fn get_thread_name(name: &mut [u8]) -> i32 { + cfg_if::cfg_if! { + if #[cfg(any( + target_os = "linux", + target_os = "illumos", + target_os = "solaris", + target_os = "macos" + ))] { + unsafe { + libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len()) + } + } else if #[cfg(target_os = "freebsd")] { + // pthread_get_name_np does not return anything + unsafe { + libc::pthread_get_name_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len()) + }; + 0 + } else { + compile_error!("get_thread_name not supported for this OS") + } + } } let result = thread::Builder::new().name(long_name.clone()).spawn(move || { @@ -28,14 +54,7 @@ fn main() { // But the system is limited -- make sure we successfully set a truncation. let mut buf = vec![0u8; long_name.len() + 1]; - #[cfg(not(target_os = "freebsd"))] - unsafe { - libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()) - }; - #[cfg(target_os = "freebsd")] - unsafe { - libc::pthread_get_name_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()) - }; + assert_eq!(get_thread_name(&mut buf), 0); let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); assert!(cstr.to_bytes().len() >= 15, "name is too short: len={}", cstr.to_bytes().len()); // POSIX seems to promise at least 15 chars assert!(long_name.as_bytes().starts_with(cstr.to_bytes())); diff --git a/src/tools/miri/tests/pass-dep/tempfile.rs b/src/tools/miri/tests/pass-dep/tempfile.rs index c4583ca3f47a4..a44a7e7d9244d 100644 --- a/src/tools/miri/tests/pass-dep/tempfile.rs +++ b/src/tools/miri/tests/pass-dep/tempfile.rs @@ -1,5 +1,5 @@ -//@ignore-target-windows: File handling is not implemented yet -//@ignore-host-windows: Only supported for UNIX hosts +//@ignore-target: windows # File handling is not implemented yet +//@ignore-host: windows # Only supported for UNIX hosts //@compile-flags: -Zmiri-disable-isolation #[path = "../utils/mod.rs"] diff --git a/src/tools/miri/tests/pass-dep/tokio/file-io.rs b/src/tools/miri/tests/pass-dep/tokio/file-io.rs index d14af299cd467..14c27285a6ae5 100644 --- a/src/tools/miri/tests/pass-dep/tokio/file-io.rs +++ b/src/tools/miri/tests/pass-dep/tokio/file-io.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@only-target-linux: We only support tokio on Linux +//@only-target: linux # We only support tokio on Linux use std::fs::remove_file; use tokio::fs::{File, OpenOptions}; diff --git a/src/tools/miri/tests/pass-dep/tokio/mpsc-await.rs b/src/tools/miri/tests/pass-dep/tokio/mpsc-await.rs index 7dea07c6e7da9..96018f34aa587 100644 --- a/src/tools/miri/tests/pass-dep/tokio/mpsc-await.rs +++ b/src/tools/miri/tests/pass-dep/tokio/mpsc-await.rs @@ -1,4 +1,4 @@ -//@only-target-linux: We only support tokio on Linux +//@only-target: linux # We only support tokio on Linux use tokio::sync::mpsc; #[tokio::main] diff --git a/src/tools/miri/tests/pass-dep/tokio/sleep.rs b/src/tools/miri/tests/pass-dep/tokio/sleep.rs index 5e63037c8a652..3c409a641f225 100644 --- a/src/tools/miri/tests/pass-dep/tokio/sleep.rs +++ b/src/tools/miri/tests/pass-dep/tokio/sleep.rs @@ -1,6 +1,6 @@ -//@only-target-linux: We only support tokio on Linux +//@only-target: linux # We only support tokio on Linux -use tokio::time::{sleep, Duration, Instant}; +use tokio::time::{Duration, Instant, sleep}; #[tokio::main] async fn main() { diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency.rs b/src/tools/miri/tests/pass/0weak_memory_consistency.rs index 1cbccb2eebdd8..10f7aed9418ab 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency.rs @@ -22,7 +22,7 @@ // Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. use std::sync::atomic::Ordering::*; -use std::sync::atomic::{fence, AtomicBool, AtomicI32}; +use std::sync::atomic::{AtomicBool, AtomicI32, fence}; use std::thread::spawn; #[derive(Copy, Clone)] diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs index 40b8e23a33c47..50e217918b060 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.rs +++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs @@ -2,7 +2,7 @@ #![no_std] //@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort //@normalize-stderr-test: "id 21" -> "id $$ALLOC" -//@only-target-linux: alloc IDs differ between OSes (due to extern static allocations) +//@only-target: linux # alloc IDs differ between OSes (due to extern static allocations) extern "Rust" { fn miri_alloc(size: usize, align: usize) -> *mut u8; diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.stderr b/src/tools/miri/tests/pass/alloc-access-tracking.stderr index 0af6cde833f7f..451f5de25d3b1 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.stderr +++ b/src/tools/miri/tests/pass/alloc-access-tracking.stderr @@ -1,23 +1,23 @@ note: tracking was triggered - --> $DIR/alloc-access-tracking.rs:LL:CC + --> tests/pass/alloc-access-tracking.rs:LL:CC | LL | let ptr = miri_alloc(123, 1); | ^^^^^^^^^^^^^^^^^^ created Miri bare-metal heap allocation of 123 bytes (alignment ALIGN bytes) with id $ALLOC | = note: BACKTRACE: - = note: inside `start` at $DIR/alloc-access-tracking.rs:LL:CC + = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC note: tracking was triggered - --> $DIR/alloc-access-tracking.rs:LL:CC + --> tests/pass/alloc-access-tracking.rs:LL:CC | LL | *ptr = 42; // Crucially, only a write is printed here, no read! | ^^^^^^^^^ write access to allocation with id $ALLOC | = note: BACKTRACE: - = note: inside `start` at $DIR/alloc-access-tracking.rs:LL:CC + = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC note: tracking was triggered - --> $DIR/alloc-access-tracking.rs:LL:CC + --> tests/pass/alloc-access-tracking.rs:LL:CC | LL | assert_eq!(*ptr, 42); | ^^^^^^^^^^^^^^^^^^^^ read access to allocation with id $ALLOC @@ -27,11 +27,11 @@ LL | assert_eq!(*ptr, 42); = note: this note originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: tracking was triggered - --> $DIR/alloc-access-tracking.rs:LL:CC + --> tests/pass/alloc-access-tracking.rs:LL:CC | LL | miri_dealloc(ptr, 123, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^ freed allocation with id $ALLOC | = note: BACKTRACE: - = note: inside `start` at $DIR/alloc-access-tracking.rs:LL:CC + = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC diff --git a/src/tools/miri/tests/pass/arrays.rs b/src/tools/miri/tests/pass/arrays.rs index 61b44453e9bd9..5cb04d0f8be19 100644 --- a/src/tools/miri/tests/pass/arrays.rs +++ b/src/tools/miri/tests/pass/arrays.rs @@ -61,6 +61,22 @@ fn debug() { println!("{:?}", array); } +fn huge_zst() { + fn id(x: T) -> T { + x + } + + // A "huge" zero-sized array. Make sure we don't loop over it in any part of Miri. + let val = [(); usize::MAX]; + id(val); // make a copy + + let val = [val; 2]; + id(val); + + // Also wrap it in a union (which, in particular, hits the logic for computing union padding). + let _copy = std::mem::MaybeUninit::new(val); +} + fn main() { assert_eq!(empty_array(), []); assert_eq!(index_unsafe(), 20); @@ -73,4 +89,5 @@ fn main() { from(); eq(); debug(); + huge_zst(); } diff --git a/src/tools/miri/tests/pass/async-drop.rs b/src/tools/miri/tests/pass/async-drop.rs index 92ecbdd29fdb9..53e3476f62040 100644 --- a/src/tools/miri/tests/pass/async-drop.rs +++ b/src/tools/miri/tests/pass/async-drop.rs @@ -10,10 +10,10 @@ #![allow(incomplete_features, dead_code)] // FIXME(zetanumbers): consider AsyncDestruct::async_drop cleanup tests -use core::future::{async_drop_in_place, AsyncDrop, Future}; +use core::future::{AsyncDrop, Future, async_drop_in_place}; use core::hint::black_box; use core::mem::{self, ManuallyDrop}; -use core::pin::{pin, Pin}; +use core::pin::{Pin, pin}; use core::task::{Context, Poll, Waker}; async fn test_async_drop(x: T) { @@ -125,7 +125,10 @@ struct AsyncReference<'a> { } impl AsyncDrop for AsyncReference<'_> { - type Dropper<'a> = impl Future where Self: 'a; + type Dropper<'a> + = impl Future + where + Self: 'a; fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { async move { diff --git a/src/tools/miri/tests/pass/async-niche-aliasing.rs b/src/tools/miri/tests/pass/async-niche-aliasing.rs new file mode 100644 index 0000000000000..ab82c929a94c2 --- /dev/null +++ b/src/tools/miri/tests/pass/async-niche-aliasing.rs @@ -0,0 +1,66 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + +use std::{ + future::Future, + mem::MaybeUninit, + pin::Pin, + sync::Arc, + task::{Context, Poll, Wake}, +}; + +struct ThingAdder<'a> { + // Using `MaybeUninit` to ensure there are no niches here. + thing: MaybeUninit<&'a mut String>, +} + +impl Future for ThingAdder<'_> { + type Output = (); + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + unsafe { + **self.get_unchecked_mut().thing.assume_init_mut() += ", world"; + } + Poll::Pending + } +} + +fn main() { + let mut thing = "hello".to_owned(); + // This future has (at least) two fields, a String (`thing`) and a ThingAdder pointing to that string. + let fut = async move { ThingAdder { thing: MaybeUninit::new(&mut thing) }.await }; + + let mut fut = MaybeDone::Future(fut); + let mut fut = unsafe { Pin::new_unchecked(&mut fut) }; + + let waker = Arc::new(DummyWaker).into(); + let mut ctx = Context::from_waker(&waker); + // This ends up reading the discriminant of the `MaybeDone`. If that is stored inside the + // `thing: String` as a niche optimization, that causes aliasing conflicts with the reference + // stored in `ThingAdder`. + assert_eq!(fut.as_mut().poll(&mut ctx), Poll::Pending); + assert_eq!(fut.as_mut().poll(&mut ctx), Poll::Pending); +} + +struct DummyWaker; + +impl Wake for DummyWaker { + fn wake(self: Arc) {} +} + +pub enum MaybeDone { + Future(F), + Done, +} +impl> Future for MaybeDone { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + unsafe { + match *self.as_mut().get_unchecked_mut() { + MaybeDone::Future(ref mut f) => Pin::new_unchecked(f).poll(cx), + MaybeDone::Done => unreachable!(), + } + } + } +} diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs index dfdc9b42f81fc..781cc9bd30942 100644 --- a/src/tools/miri/tests/pass/atomic.rs +++ b/src/tools/miri/tests/pass/atomic.rs @@ -1,9 +1,13 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance + #![feature(strict_provenance, strict_provenance_atomic_ptr)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use std::sync::atomic::{ - compiler_fence, fence, AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, Ordering::*, + AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, Ordering::*, compiler_fence, fence, }; fn main() { diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr index c05950ebdc746..b87063431ad88 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr @@ -1,8 +1,8 @@ -$DIR/backtrace-api-v0.rs:LL:CC (func_d) -$DIR/backtrace-api-v0.rs:LL:CC (func_c) -$DIR/backtrace-api-v0.rs:LL:CC (func_b) -$DIR/backtrace-api-v0.rs:LL:CC (func_a) -$DIR/backtrace-api-v0.rs:LL:CC (main) +tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_d) +tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_c) +tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_b) +tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_a) +tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (main) RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout index e6644b4453fa5..8c1bc5c353e9f 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v0.rs:24:14 (func_d) -$DIR/backtrace-api-v0.rs:14:9 (func_c) -$DIR/backtrace-api-v0.rs:9:5 (func_b::) -$DIR/backtrace-api-v0.rs:5:5 (func_a) -$DIR/backtrace-api-v0.rs:29:18 (main) +tests/pass/backtrace/backtrace-api-v0.rs:24:14 (func_d) +tests/pass/backtrace/backtrace-api-v0.rs:14:9 (func_c) +tests/pass/backtrace/backtrace-api-v0.rs:9:5 (func_b::) +tests/pass/backtrace/backtrace-api-v0.rs:5:5 (func_a) +tests/pass/backtrace/backtrace-api-v0.rs:29:18 (main) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr index b56d983d42984..2c729c49ee05d 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr @@ -1,8 +1,8 @@ -$DIR/backtrace-api-v1.rs:LL:CC (func_d) -$DIR/backtrace-api-v1.rs:LL:CC (func_c) -$DIR/backtrace-api-v1.rs:LL:CC (func_b) -$DIR/backtrace-api-v1.rs:LL:CC (func_a) -$DIR/backtrace-api-v1.rs:LL:CC (main) +tests/pass/backtrace/backtrace-api-v1.rs:LL:CC (func_d) +tests/pass/backtrace/backtrace-api-v1.rs:LL:CC (func_c) +tests/pass/backtrace/backtrace-api-v1.rs:LL:CC (func_b) +tests/pass/backtrace/backtrace-api-v1.rs:LL:CC (func_a) +tests/pass/backtrace/backtrace-api-v1.rs:LL:CC (main) RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout index 11efd2f0752d9..5c2995e132aa6 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v1.rs:27:9 (func_d) -$DIR/backtrace-api-v1.rs:14:9 (func_c) -$DIR/backtrace-api-v1.rs:9:5 (func_b::) -$DIR/backtrace-api-v1.rs:5:5 (func_a) -$DIR/backtrace-api-v1.rs:34:18 (main) +tests/pass/backtrace/backtrace-api-v1.rs:27:9 (func_d) +tests/pass/backtrace/backtrace-api-v1.rs:14:9 (func_c) +tests/pass/backtrace/backtrace-api-v1.rs:9:5 (func_b::) +tests/pass/backtrace/backtrace-api-v1.rs:5:5 (func_a) +tests/pass/backtrace/backtrace-api-v1.rs:34:18 (main) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr index b06dd1da3c645..d9414aa651835 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr @@ -1,5 +1,5 @@ 0: main - at $DIR/backtrace-global-alloc.rs:LL:CC + at tests/pass/backtrace/backtrace-global-alloc.rs:LL:CC 1: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC 2: std::sys::backtrace::__rust_begin_short_backtrace diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr index 84bdda59fce9a..d6d69ee837ede 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr @@ -1,13 +1,13 @@ 0: func_d - at $DIR/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 1: func_c - at $DIR/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 2: func_b - at $DIR/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 3: func_a - at $DIR/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 4: main - at $DIR/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 5: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC 6: std::sys::backtrace::__rust_begin_short_backtrace diff --git a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs index 18980932f31cc..a1371242f60d9 100644 --- a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs +++ b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs @@ -11,7 +11,7 @@ use std::{ alloc::{AllocError, Allocator, Layout}, cell::{Cell, UnsafeCell}, mem, - ptr::{self, addr_of, NonNull}, + ptr::{self, NonNull, addr_of}, thread::{self, ThreadId}, }; diff --git a/src/tools/miri/tests/pass/catch.rs b/src/tools/miri/tests/pass/catch.rs index 4ede23e68ce25..bedabf3eb286a 100644 --- a/src/tools/miri/tests/pass/catch.rs +++ b/src/tools/miri/tests/pass/catch.rs @@ -1,4 +1,4 @@ -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{AssertUnwindSafe, catch_unwind}; fn main() { let mut i = 3; diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs index d31420380a565..34380dfa504d5 100644 --- a/src/tools/miri/tests/pass/concurrency/data_race.rs +++ b/src/tools/miri/tests/pass/concurrency/data_race.rs @@ -1,6 +1,6 @@ //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::sync::atomic::{fence, AtomicUsize, Ordering}; +use std::sync::atomic::*; use std::thread::spawn; #[derive(Copy, Clone)] @@ -112,9 +112,41 @@ pub fn test_simple_release() { } } +fn test_local_variable_lazy_write() { + static P: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); + + // Create the local variable, and initialize it. + // This write happens before the thread is spanwed, so there is no data race. + let mut val: u8 = 0; + + let t1 = std::thread::spawn(|| { + while P.load(Ordering::Relaxed).is_null() { + std::hint::spin_loop(); + } + unsafe { + // Initialize `*P`. + let ptr = P.load(Ordering::Relaxed); + *ptr = 127; + } + }); + + // Actually generate memory for the local variable. + // This is the time its value is actually written to memory: + // that's *after* the thread above was spawned! + // This may hence look like a data race wrt the access in the thread above. + P.store(std::ptr::addr_of_mut!(val), Ordering::Relaxed); + + // Wait for the thread to be done. + t1.join().unwrap(); + + // Read initialized value. + assert_eq!(val, 127); +} + pub fn main() { test_fence_sync(); test_multiple_reads(); test_rmw_no_block(); test_simple_release(); + test_local_variable_lazy_write(); } diff --git a/src/tools/miri/tests/pass/concurrency/thread_park_isolated.rs b/src/tools/miri/tests/pass/concurrency/thread_park_isolated.rs index 7852d495e28fa..35145fe9bd31a 100644 --- a/src/tools/miri/tests/pass/concurrency/thread_park_isolated.rs +++ b/src/tools/miri/tests/pass/concurrency/thread_park_isolated.rs @@ -1,4 +1,4 @@ -//@ignore-target-apple: park_timeout on macOS uses the system clock +//@ignore-target: apple # park_timeout on macOS uses the system clock use std::thread; use std::time::{Duration, Instant}; diff --git a/src/tools/miri/tests/pass/drop_on_array_elements.rs b/src/tools/miri/tests/pass/drop_on_array_elements.rs index ae1ef036267e2..4bf241fee2b3f 100644 --- a/src/tools/miri/tests/pass/drop_on_array_elements.rs +++ b/src/tools/miri/tests/pass/drop_on_array_elements.rs @@ -1,3 +1,5 @@ +#![allow(static_mut_refs)] + struct Bar(u16); // ZSTs are tested separately static mut DROP_COUNT: usize = 0; diff --git a/src/tools/miri/tests/pass/drop_on_fat_ptr_array_elements.rs b/src/tools/miri/tests/pass/drop_on_fat_ptr_array_elements.rs index 40025cd07f7e0..04723af94c311 100644 --- a/src/tools/miri/tests/pass/drop_on_fat_ptr_array_elements.rs +++ b/src/tools/miri/tests/pass/drop_on_fat_ptr_array_elements.rs @@ -1,3 +1,5 @@ +#![allow(static_mut_refs)] + trait Foo {} struct Bar; diff --git a/src/tools/miri/tests/pass/drop_on_zst_array_elements.rs b/src/tools/miri/tests/pass/drop_on_zst_array_elements.rs index babe098e4e6f5..71398724f2cc8 100644 --- a/src/tools/miri/tests/pass/drop_on_zst_array_elements.rs +++ b/src/tools/miri/tests/pass/drop_on_zst_array_elements.rs @@ -1,3 +1,5 @@ +#![allow(static_mut_refs)] + struct Bar; static mut DROP_COUNT: usize = 0; diff --git a/src/tools/miri/tests/pass/drop_through_owned_slice.rs b/src/tools/miri/tests/pass/drop_through_owned_slice.rs index 8cdeb57d02f79..2d1d876e6f239 100644 --- a/src/tools/miri/tests/pass/drop_through_owned_slice.rs +++ b/src/tools/miri/tests/pass/drop_through_owned_slice.rs @@ -1,3 +1,5 @@ +#![allow(static_mut_refs)] + struct Bar; static mut DROP_COUNT: usize = 0; diff --git a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs index 6be13b155f410..dc2b9e4491b27 100644 --- a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs +++ b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs @@ -1,6 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] +#![feature(arbitrary_self_types_pointers, unsize, coerce_unsized, dispatch_from_dyn)] #![feature(rustc_attrs)] fn pin_box_dyn() { diff --git a/src/tools/miri/tests/pass/enums.rs b/src/tools/miri/tests/pass/enums.rs index 1dafef025e958..9fc61f07c047f 100644 --- a/src/tools/miri/tests/pass/enums.rs +++ b/src/tools/miri/tests/pass/enums.rs @@ -132,6 +132,43 @@ fn overaligned_casts() { assert_eq!(aligned as u8, 0); } +// This hits a corner case in the logic for clearing padding on typed copies. +fn padding_clear_corner_case() { + #[allow(unused)] + #[derive(Copy, Clone)] + #[repr(C)] + pub struct Decoded { + /// The scaled mantissa. + pub mant: u64, + /// The lower error range. + pub minus: u64, + /// The upper error range. + pub plus: u64, + /// The shared exponent in base 2. + pub exp: i16, + /// True when the error range is inclusive. + /// + /// In IEEE 754, this is true when the original mantissa was even. + pub inclusive: bool, + } + + #[allow(unused)] + #[derive(Copy, Clone)] + pub enum FullDecoded { + /// Not-a-number. + Nan, + /// Infinities, either positive or negative. + Infinite, + /// Zero, either positive or negative. + Zero, + /// Finite numbers with further decoded fields. + Finite(Decoded), + } + + let val = FullDecoded::Finite(Decoded { mant: 0, minus: 0, plus: 0, exp: 0, inclusive: false }); + let _val2 = val; // trigger typed copy +} + fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); @@ -141,4 +178,5 @@ fn main() { discriminant_overflow(); more_discriminant_overflow(); overaligned_casts(); + padding_clear_corner_case(); } diff --git a/src/tools/miri/tests/pass/extern_types.stack.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr index 2c9fc0192af83..898c19d514b5b 100644 --- a/src/tools/miri/tests/pass/extern_types.stack.stderr +++ b/src/tools/miri/tests/pass/extern_types.stack.stderr @@ -1,5 +1,5 @@ warning: reborrow of reference to `extern type` - --> $DIR/extern_types.rs:LL:CC + --> tests/pass/extern_types.rs:LL:CC | LL | let x: &Foo = unsafe { &*(ptr::without_provenance::<()>(16) as *const Foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow of a reference to `extern type` is not properly supported @@ -7,5 +7,5 @@ LL | let x: &Foo = unsafe { &*(ptr::without_provenance::<()>(16) as *const F = help: `extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code = help: try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead = note: BACKTRACE: - = note: inside `main` at $DIR/extern_types.rs:LL:CC + = note: inside `main` at tests/pass/extern_types.rs:LL:CC diff --git a/src/tools/miri/tests/pass/function_calls/target_feature.rs b/src/tools/miri/tests/pass/function_calls/target_feature.rs index 0be86ba373165..43df761bd0bb0 100644 --- a/src/tools/miri/tests/pass/function_calls/target_feature.rs +++ b/src/tools/miri/tests/pass/function_calls/target_feature.rs @@ -1,4 +1,4 @@ -//@only-target-x86_64: uses x86 target features +//@only-target: x86_64 # uses x86 target features //@compile-flags: -C target-feature=+ssse3 fn main() { diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index c4ba11d0a436f..cd606a5282a98 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -11,7 +11,7 @@ #![allow(incomplete_features, internal_features)] use std::intrinsics::simd as intrinsics; use std::ptr; -use std::simd::{prelude::*, StdFloat}; +use std::simd::{StdFloat, prelude::*}; extern "rust-intrinsic" { #[rustc_nounwind] @@ -619,13 +619,16 @@ fn simd_intrinsics() { i32x4::from_array([10, 2, 10, 10]) ); assert_eq!(simd_shuffle_generic::<_, i32x4, { &[3, 1, 0, 2] }>(a, b), a,); - assert_eq!(simd_shuffle::<_, _, i32x4>(a, b, const { [3u32, 1, 0, 2] }), a,); + assert_eq!( + simd_shuffle::<_, _, i32x4>(a, b, const { u32x4::from_array([3u32, 1, 0, 2]) }), + a, + ); assert_eq!( simd_shuffle_generic::<_, i32x4, { &[7, 5, 4, 6] }>(a, b), i32x4::from_array([4, 2, 1, 10]), ); assert_eq!( - simd_shuffle::<_, _, i32x4>(a, b, const { [7u32, 5, 4, 6] }), + simd_shuffle::<_, _, i32x4>(a, b, const { u32x4::from_array([7u32, 5, 4, 6]) }), i32x4::from_array([4, 2, 1, 10]), ); } diff --git a/src/tools/miri/tests/pass/intrinsics/simd-intrinsic-generic-elements.rs b/src/tools/miri/tests/pass/intrinsics/simd-intrinsic-generic-elements.rs new file mode 100644 index 0000000000000..9cf0c2ddef333 --- /dev/null +++ b/src/tools/miri/tests/pass/intrinsics/simd-intrinsic-generic-elements.rs @@ -0,0 +1,24 @@ +#![feature(repr_simd)] + +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x2([i32; 2]); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x4([i32; 4]); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x8([i32; 8]); + +fn main() { + let _x2 = i32x2([20, 21]); + let _x4 = i32x4([40, 41, 42, 43]); + let _x8 = i32x8([80, 81, 82, 83, 84, 85, 86, 87]); + + let _y2 = i32x2([120, 121]); + let _y4 = i32x4([140, 141, 142, 143]); + let _y8 = i32x8([180, 181, 182, 183, 184, 185, 186, 187]); +} diff --git a/src/tools/miri/tests/pass/issues/issue-miri-3680.rs b/src/tools/miri/tests/pass/issues/issue-miri-3680.rs index 55b896c91adb7..c8e2498fa5ace 100644 --- a/src/tools/miri/tests/pass/issues/issue-miri-3680.rs +++ b/src/tools/miri/tests/pass/issues/issue-miri-3680.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: File handling is not implemented yet +//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation use std::fs::remove_file; diff --git a/src/tools/miri/tests/pass/miri-alloc.rs b/src/tools/miri/tests/pass/miri-alloc.rs index 8f1724754181f..17f6d5d05a529 100644 --- a/src/tools/miri/tests/pass/miri-alloc.rs +++ b/src/tools/miri/tests/pass/miri-alloc.rs @@ -4,7 +4,7 @@ // 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: no-std not supported on Windows +//@ignore-target: windows # no-std not supported on Windows extern "Rust" { fn miri_alloc(size: usize, align: usize) -> *mut u8; diff --git a/src/tools/miri/tests/pass/panic/catch_panic.rs b/src/tools/miri/tests/pass/panic/catch_panic.rs index b83902a8b19a4..06d15a1a7f94e 100644 --- a/src/tools/miri/tests/pass/panic/catch_panic.rs +++ b/src/tools/miri/tests/pass/panic/catch_panic.rs @@ -2,7 +2,7 @@ #![allow(unconditional_panic, non_fmt_panics)] use std::cell::Cell; -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{AssertUnwindSafe, catch_unwind}; use std::process; thread_local! { diff --git a/src/tools/miri/tests/pass/panic/catch_panic.stderr b/src/tools/miri/tests/pass/panic/catch_panic.stderr index f61b39493ed17..cb74312a83ae5 100644 --- a/src/tools/miri/tests/pass/panic/catch_panic.stderr +++ b/src/tools/miri/tests/pass/panic/catch_panic.stderr @@ -1,36 +1,36 @@ -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: Hello from std::panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect Caught panic message (&str): Hello from std::panic -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: Hello from std::panic: 1 Caught panic message (String): Hello from std::panic: 1 -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: Hello from std::panic_any: 2 Caught panic message (String): Hello from std::panic_any: 2 -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: Box Failed to get caught panic message. -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: Hello from core::panic Caught panic message (&str): Hello from core::panic -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: Hello from core::panic: 5 Caught panic message (String): Hello from core::panic: 5 -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: index out of bounds: the len is 3 but the index is 4 Caught panic message (String): index out of bounds: the len is 3 but the index is 4 -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: attempt to divide by zero Caught panic message (&str): attempt to divide by zero thread 'main' panicked at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC: align_offset: align is not a power-of-two Caught panic message (&str): align_offset: align is not a power-of-two -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: assertion failed: false Caught panic message (&str): assertion failed: false -thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/catch_panic.rs:LL:CC: assertion failed: false Caught panic message (&str): assertion failed: false Success! diff --git a/src/tools/miri/tests/pass/panic/concurrent-panic.rs b/src/tools/miri/tests/pass/panic/concurrent-panic.rs index 7cc1e2a973fd6..e804df90977a9 100644 --- a/src/tools/miri/tests/pass/panic/concurrent-panic.rs +++ b/src/tools/miri/tests/pass/panic/concurrent-panic.rs @@ -5,7 +5,7 @@ //! that separate threads have their own panicking state. use std::sync::{Arc, Condvar, Mutex}; -use std::thread::{spawn, JoinHandle}; +use std::thread::{JoinHandle, spawn}; struct BlockOnDrop(Option>); diff --git a/src/tools/miri/tests/pass/panic/concurrent-panic.stderr b/src/tools/miri/tests/pass/panic/concurrent-panic.stderr index fe0d16ca78ac0..9c87489e8db37 100644 --- a/src/tools/miri/tests/pass/panic/concurrent-panic.stderr +++ b/src/tools/miri/tests/pass/panic/concurrent-panic.stderr @@ -1,13 +1,13 @@ Thread 1 starting, will block on mutex Thread 1 reported it has started -thread '' panicked at $DIR/concurrent-panic.rs:LL:CC: +thread '' panicked at tests/pass/panic/concurrent-panic.rs:LL:CC: panic in thread 2 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect Thread 2 blocking on thread 1 Thread 2 reported it has started Unlocking mutex -thread '' panicked at $DIR/concurrent-panic.rs:LL:CC: +thread '' panicked at tests/pass/panic/concurrent-panic.rs:LL:CC: panic in thread 1 Thread 1 has exited Thread 2 has exited diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr index a346d31f645eb..e066f7dfce167 100644 --- a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr +++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr @@ -1,7 +1,7 @@ -thread 'main' panicked at $DIR/nested_panic_caught.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/nested_panic_caught.rs:LL:CC: once note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -thread 'main' panicked at $DIR/nested_panic_caught.rs:LL:CC: +thread 'main' panicked at tests/pass/panic/nested_panic_caught.rs:LL:CC: twice stack backtrace: diff --git a/src/tools/miri/tests/pass/panic/thread_panic.stderr b/src/tools/miri/tests/pass/panic/thread_panic.stderr index 0fde5922c192d..9464e76b6c9c0 100644 --- a/src/tools/miri/tests/pass/panic/thread_panic.stderr +++ b/src/tools/miri/tests/pass/panic/thread_panic.stderr @@ -1,6 +1,6 @@ -thread '' panicked at $DIR/thread_panic.rs:LL:CC: +thread '' panicked at tests/pass/panic/thread_panic.rs:LL:CC: Hello! note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -thread 'childthread' panicked at $DIR/thread_panic.rs:LL:CC: +thread 'childthread' panicked at tests/pass/panic/thread_panic.rs:LL:CC: Hello, world! diff --git a/src/tools/miri/tests/pass/panic/unwind_dwarf.rs b/src/tools/miri/tests/pass/panic/unwind_dwarf.rs index f690be471ba70..ca90e4f4d94f7 100644 --- a/src/tools/miri/tests/pass/panic/unwind_dwarf.rs +++ b/src/tools/miri/tests/pass/panic/unwind_dwarf.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Windows uses a different unwinding mechanism +//@ignore-target: windows # Windows uses a different unwinding mechanism #![feature(core_intrinsics, panic_unwind, rustc_attrs)] #![allow(internal_features)] diff --git a/src/tools/miri/tests/pass/path.rs b/src/tools/miri/tests/pass/path.rs index fe99d38e073bf..299ee6cfe9dde 100644 --- a/src/tools/miri/tests/pass/path.rs +++ b/src/tools/miri/tests/pass/path.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -use std::path::{absolute, Path, PathBuf}; +use std::path::{Path, PathBuf, absolute}; #[path = "../utils/mod.rs"] mod utils; diff --git a/src/tools/miri/tests/pass/provenance.rs b/src/tools/miri/tests/pass/provenance.rs index 9e8a9651b3d96..2e4d240cc48a1 100644 --- a/src/tools/miri/tests/pass/provenance.rs +++ b/src/tools/miri/tests/pass/provenance.rs @@ -12,6 +12,7 @@ fn main() { bytewise_custom_memcpy(); bytewise_custom_memcpy_chunked(); int_load_strip_provenance(); + maybe_uninit_preserves_partial_provenance(); } /// Some basic smoke tests for provenance. @@ -145,3 +146,24 @@ fn int_load_strip_provenance() { let ints: [usize; 1] = unsafe { mem::transmute(ptrs) }; assert_eq!(ptrs[0] as *const _ as usize, ints[0]); } + +fn maybe_uninit_preserves_partial_provenance() { + // This is the same test as ptr_copy_loses_partial_provenance.rs, but using MaybeUninit and thus + // properly preserving partial provenance. + unsafe { + let mut bytes = [1u8; 16]; + let bytes = bytes.as_mut_ptr(); + + // Put a pointer in the middle. + bytes.add(4).cast::<&i32>().write_unaligned(&42); + // Copy the entire thing as two pointers but not perfectly + // overlapping with the pointer we have in there. + let copy = bytes.cast::<[mem::MaybeUninit<*const ()>; 2]>().read_unaligned(); + let copy_bytes = copy.as_ptr().cast::(); + // Now go to the middle of the copy and get the pointer back out. + let ptr = copy_bytes.add(4).cast::<*const i32>().read_unaligned(); + // And deref this to ensure we get the right value. + let val = *ptr; + assert_eq!(val, 42); + } +} diff --git a/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr b/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr index a34474ee0d627..21c5b2b0dfe8f 100644 --- a/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr +++ b/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr @@ -1,5 +1,5 @@ warning: integer-to-pointer cast - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | assert_eq!(1 as *const i32 as usize, 1); | ^^^^^^^^^^^^^^^ integer-to-pointer cast @@ -10,79 +10,79 @@ LL | assert_eq!(1 as *const i32 as usize, 1); = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics = help: Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used = note: BACKTRACE: - = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC + = note: inside `ptr_int_casts` at tests/pass/ptr_int_casts.rs:LL:CC note: inside `main` - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | ptr_int_casts(); | ^^^^^^^^^^^^^^^ warning: integer-to-pointer cast - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4 * 4); | ^^^^^^^^^^^^^^^^^ integer-to-pointer cast | = note: BACKTRACE: - = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC + = note: inside `ptr_int_casts` at tests/pass/ptr_int_casts.rs:LL:CC note: inside `main` - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | ptr_int_casts(); | ^^^^^^^^^^^^^^^ warning: integer-to-pointer cast - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | *val = (1 as *const u8).wrapping_offset(-4); | ^^^^^^^^^^^^^^^^ integer-to-pointer cast | = note: BACKTRACE: - = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC + = note: inside `ptr_int_casts` at tests/pass/ptr_int_casts.rs:LL:CC note: inside `main` - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | ptr_int_casts(); | ^^^^^^^^^^^^^^^ warning: integer-to-pointer cast - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | let y = y as *const _; | ^^^^^^^^^^^^^ integer-to-pointer cast | = note: BACKTRACE: - = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC + = note: inside `ptr_int_casts` at tests/pass/ptr_int_casts.rs:LL:CC note: inside `main` - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | ptr_int_casts(); | ^^^^^^^^^^^^^^^ warning: integer-to-pointer cast - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | let x: fn() -> i32 = unsafe { mem::transmute(y as *mut u8) }; | ^^^^^^^^^^^^ integer-to-pointer cast | = note: BACKTRACE: - = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC + = note: inside `ptr_int_casts` at tests/pass/ptr_int_casts.rs:LL:CC note: inside `main` - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | ptr_int_casts(); | ^^^^^^^^^^^^^^^ warning: integer-to-pointer cast - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | assert_eq!((-1i32) as usize as *const i32 as usize, (-1i32) as usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | = note: BACKTRACE: - = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC + = note: inside `ptr_int_casts` at tests/pass/ptr_int_casts.rs:LL:CC note: inside `main` - --> $DIR/ptr_int_casts.rs:LL:CC + --> tests/pass/ptr_int_casts.rs:LL:CC | LL | ptr_int_casts(); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr b/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr index 614b0d26a6304..aac6d0f48d015 100644 --- a/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr +++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr @@ -1,5 +1,5 @@ warning: integer-to-pointer cast - --> $DIR/ptr_int_from_exposed.rs:LL:CC + --> tests/pass/ptr_int_from_exposed.rs:LL:CC | LL | let ptr = ptr::with_exposed_provenance::(x_usize).wrapping_offset(-128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast @@ -10,9 +10,9 @@ LL | let ptr = ptr::with_exposed_provenance::(x_usize).wrapping_offset( = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics = help: Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used = note: BACKTRACE: - = note: inside `ptr_roundtrip_out_of_bounds` at $DIR/ptr_int_from_exposed.rs:LL:CC + = note: inside `ptr_roundtrip_out_of_bounds` at tests/pass/ptr_int_from_exposed.rs:LL:CC note: inside `main` - --> $DIR/ptr_int_from_exposed.rs:LL:CC + --> tests/pass/ptr_int_from_exposed.rs:LL:CC | LL | ptr_roundtrip_out_of_bounds(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/pass/shims/fs-symlink.rs b/src/tools/miri/tests/pass/shims/fs-symlink.rs index 4d5103b24c32d..30cf234e7a0d1 100644 --- a/src/tools/miri/tests/pass/shims/fs-symlink.rs +++ b/src/tools/miri/tests/pass/shims/fs-symlink.rs @@ -1,9 +1,9 @@ // Symlink tests are separate since they don't in general work on a Windows host. -//@ignore-host-windows: creating symlinks requires admin permissions on Windows -//@ignore-target-windows: File handling is not implemented yet +//@ignore-host: windows # creating symlinks requires admin permissions on Windows +//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation -use std::fs::{read_link, remove_file, File}; +use std::fs::{File, read_link, remove_file}; use std::io::{Read, Result}; use std::path::Path; diff --git a/src/tools/miri/tests/pass/shims/fs-with-isolation.rs b/src/tools/miri/tests/pass/shims/fs-with-isolation.rs index 8fa683085b98b..c42f97458c4b5 100644 --- a/src/tools/miri/tests/pass/shims/fs-with-isolation.rs +++ b/src/tools/miri/tests/pass/shims/fs-with-isolation.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: File handling is not implemented yet +//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 70e375b098128..62424ca26b1c7 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: File handling is not implemented yet +//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] @@ -7,8 +7,8 @@ use std::collections::HashMap; use std::ffi::OsString; use std::fs::{ - canonicalize, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename, File, - OpenOptions, + File, OpenOptions, canonicalize, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, + rename, }; use std::io::{Error, ErrorKind, IsTerminal, Read, Result, Seek, SeekFrom, Write}; use std::path::Path; diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation.rs b/src/tools/miri/tests/pass/shims/time-with-isolation.rs index 645d42ad975da..e7b1624412358 100644 --- a/src/tools/miri/tests/pass/shims/time-with-isolation.rs +++ b/src/tools/miri/tests/pass/shims/time-with-isolation.rs @@ -41,9 +41,9 @@ fn test_block_for_one_second() { /// Ensures that we get the same behavior across all targets. fn test_deterministic() { let begin = Instant::now(); - for _ in 0..100_000 {} + for _ in 0..10_000 {} let time = begin.elapsed(); - println!("The loop took around {}s", time.as_secs()); + println!("The loop took around {}ms", time.as_millis()); println!("(It's fine for this number to change when you `--bless` this test.)") } diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation.stdout b/src/tools/miri/tests/pass/shims/time-with-isolation.stdout index ff5889bacd5d1..2d7fb5f4a6144 100644 --- a/src/tools/miri/tests/pass/shims/time-with-isolation.stdout +++ b/src/tools/miri/tests/pass/shims/time-with-isolation.stdout @@ -1,2 +1,2 @@ -The loop took around 12s +The loop took around 1250ms (It's fine for this number to change when you `--bless` this test.) diff --git a/src/tools/miri/tests/pass/shims/windows-rand.rs b/src/tools/miri/tests/pass/shims/windows-rand.rs index cfbc1d278a932..1947e6d13569b 100644 --- a/src/tools/miri/tests/pass/shims/windows-rand.rs +++ b/src/tools/miri/tests/pass/shims/windows-rand.rs @@ -1,4 +1,4 @@ -//@only-target-windows: this directly tests windows-only functions +//@only-target: windows # this directly tests windows-only functions use core::ffi::c_void; use core::mem::size_of_val; use core::ptr::null_mut; diff --git a/src/tools/miri/tests/pass/shims/windows-threadname.rs b/src/tools/miri/tests/pass/shims/windows-threadname.rs index c863ac670b6d5..29c3fa5d5f3aa 100644 --- a/src/tools/miri/tests/pass/shims/windows-threadname.rs +++ b/src/tools/miri/tests/pass/shims/windows-threadname.rs @@ -1,4 +1,4 @@ -//@only-target-windows: this directly tests windows-only functions +//@only-target: windows # this directly tests windows-only functions use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs index 79ac4432dffac..4e892e6e3cb38 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+sha,+sse2,+ssse3,+sse4.1 #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs index 0fd4b7c091097..baa984e68d83b 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+adx #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs index d4d1b6180a7b3..47f086f7340d7 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+aes,+vaes,+avx512f #![feature(avx512_target_feature, stdarch_x86_avx512)] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs index 3847a80be9053..b3c2434c0d288 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+avx #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs index 8b8d8880e3bed..de1abc818420c 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+avx2 #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index a40eddde97c15..db59306389016 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq #![feature(avx512_target_feature)] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs index 02f57f4b451e1..030258f21fa51 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+bmi1,+bmi2 #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs index 60da88df046ef..4d5ddd75f385a 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=-sse2 #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs index 86ac5835a168b..6051987f8d4c1 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+pclmulqdq #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs index a62a5ee3781b7..6f7ab3b3c9fb9 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs @@ -1,1107 +1,1088 @@ +// We're testing x86 target specific features +//@only-target: x86_64 i686 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; +use std::f32::NAN; +use std::mem::transmute; + fn main() { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - assert!(is_x86_feature_detected!("sse")); + assert!(is_x86_feature_detected!("sse")); - unsafe { - tests::test_sse(); - } + unsafe { + test_sse(); } } -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod tests { - #[cfg(target_arch = "x86")] - use std::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use std::arch::x86_64::*; - use std::f32::NAN; - use std::mem::transmute; - - macro_rules! assert_approx_eq { - ($a:expr, $b:expr, $eps:expr) => {{ - let (a, b) = (&$a, &$b); - assert!( - (*a - *b).abs() < $eps, - "assertion failed: `(left !== right)` \ +macro_rules! assert_approx_eq { + ($a:expr, $b:expr, $eps:expr) => {{ + let (a, b) = (&$a, &$b); + assert!( + (*a - *b).abs() < $eps, + "assertion failed: `(left !== right)` \ (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", - *a, - *b, - $eps, - (*a - *b).abs() - ); - }}; - } + *a, + *b, + $eps, + (*a - *b).abs() + ); + }}; +} + +#[target_feature(enable = "sse")] +unsafe fn test_sse() { + // Mostly copied from library/stdarch/crates/core_arch/src/x86{,_64}/sse.rs #[target_feature(enable = "sse")] - pub(super) unsafe fn test_sse() { - // Mostly copied from library/stdarch/crates/core_arch/src/x86{,_64}/sse.rs - - #[target_feature(enable = "sse")] - unsafe fn assert_eq_m128(a: __m128, b: __m128) { - let r = _mm_cmpeq_ps(a, b); - if _mm_movemask_ps(r) != 0b1111 { - panic!("{:?} != {:?}", a, b); - } + unsafe fn assert_eq_m128(a: __m128, b: __m128) { + let r = _mm_cmpeq_ps(a, b); + if _mm_movemask_ps(r) != 0b1111 { + panic!("{:?} != {:?}", a, b); } + } - #[target_feature(enable = "sse")] - unsafe fn test_mm_add_ss() { - let a = _mm_set_ps(-1.0, 5.0, 0.0, -10.0); - let b = _mm_set_ps(-100.0, 20.0, 0.0, -5.0); - let r = _mm_add_ss(a, b); - assert_eq_m128(r, _mm_set_ps(-1.0, 5.0, 0.0, -15.0)); - } - test_mm_add_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_sub_ss() { - let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); - let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); - let r = _mm_sub_ss(a, b); - assert_eq_m128(r, _mm_setr_ps(99.0, 5.0, 0.0, -10.0)); - } - test_mm_sub_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_mul_ss() { - let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); - let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); - let r = _mm_mul_ss(a, b); - assert_eq_m128(r, _mm_setr_ps(100.0, 5.0, 0.0, -10.0)); - } - test_mm_mul_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_div_ss() { - let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); - let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); - let r = _mm_div_ss(a, b); - assert_eq_m128(r, _mm_setr_ps(0.01, 5.0, 0.0, -10.0)); - } - test_mm_div_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_sqrt_ss() { - let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); - let r = _mm_sqrt_ss(a); - let e = _mm_setr_ps(2.0, 13.0, 16.0, 100.0); - assert_eq_m128(r, e); - } - test_mm_sqrt_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_sqrt_ps() { - let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); - let r = _mm_sqrt_ps(a); - let e = _mm_setr_ps(2.0, 3.6055512, 4.0, 10.0); - assert_eq_m128(r, e); - } - test_mm_sqrt_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_rcp_ss() { - let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); - let r = _mm_rcp_ss(a); - let e = _mm_setr_ps(0.24993896, 13.0, 16.0, 100.0); - let rel_err = 0.00048828125; - - let r: [f32; 4] = transmute(r); - let e: [f32; 4] = transmute(e); - assert_approx_eq!(r[0], e[0], 2. * rel_err); - for i in 1..4 { - assert_eq!(r[i], e[i]); - } - } - test_mm_rcp_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_rcp_ps() { - let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); - let r = _mm_rcp_ps(a); - let e = _mm_setr_ps(0.24993896, 0.0769043, 0.06248474, 0.0099983215); - let rel_err = 0.00048828125; - - let r: [f32; 4] = transmute(r); - let e: [f32; 4] = transmute(e); - for i in 0..4 { - assert_approx_eq!(r[i], e[i], 2. * rel_err); - } - } - test_mm_rcp_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_rsqrt_ss() { - let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); - let r = _mm_rsqrt_ss(a); - let e = _mm_setr_ps(0.49987793, 13.0, 16.0, 100.0); - let rel_err = 0.00048828125; - - let r: [f32; 4] = transmute(r); - let e: [f32; 4] = transmute(e); - assert_approx_eq!(r[0], e[0], 2. * rel_err); - for i in 1..4 { - assert_eq!(r[i], e[i]); - } - } - test_mm_rsqrt_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_rsqrt_ps() { - let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); - let r = _mm_rsqrt_ps(a); - let e = _mm_setr_ps(0.49987793, 0.2772827, 0.24993896, 0.099990845); - let rel_err = 0.00048828125; - - let r: [f32; 4] = transmute(r); - let e: [f32; 4] = transmute(e); - for i in 0..4 { - assert_approx_eq!(r[i], e[i], 2. * rel_err); - } - } - test_mm_rsqrt_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_min_ss() { - let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); - let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); - let r = _mm_min_ss(a, b); - assert_eq_m128(r, _mm_setr_ps(-100.0, 5.0, 0.0, -10.0)); - } - test_mm_min_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_min_ps() { - let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); - let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); - let r = _mm_min_ps(a, b); - assert_eq_m128(r, _mm_setr_ps(-100.0, 5.0, 0.0, -10.0)); - - // `_mm_min_ps` can **not** be implemented using the `simd_min` rust intrinsic because - // the semantics of `simd_min` are different to those of `_mm_min_ps` regarding handling - // of `-0.0`. - let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0); - let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0); - let r1: [u8; 16] = transmute(_mm_min_ps(a, b)); - let r2: [u8; 16] = transmute(_mm_min_ps(b, a)); - let a: [u8; 16] = transmute(a); - let b: [u8; 16] = transmute(b); - assert_eq!(r1, b); - assert_eq!(r2, a); - assert_ne!(a, b); // sanity check that -0.0 is actually present - } - test_mm_min_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_max_ss() { - let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); - let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); - let r = _mm_max_ss(a, b); - assert_eq_m128(r, _mm_setr_ps(-1.0, 5.0, 0.0, -10.0)); - } - test_mm_max_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_max_ps() { - let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); - let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); - let r = _mm_max_ps(a, b); - assert_eq_m128(r, _mm_setr_ps(-1.0, 20.0, 0.0, -5.0)); - - // `_mm_max_ps` can **not** be implemented using the `simd_max` rust intrinsic because - // the semantics of `simd_max` are different to those of `_mm_max_ps` regarding handling - // of `-0.0`. - let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0); - let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0); - let r1: [u8; 16] = transmute(_mm_max_ps(a, b)); - let r2: [u8; 16] = transmute(_mm_max_ps(b, a)); - let a: [u8; 16] = transmute(a); - let b: [u8; 16] = transmute(b); - assert_eq!(r1, b); - assert_eq!(r2, a); - assert_ne!(a, b); // sanity check that -0.0 is actually present - } - test_mm_max_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpeq_ss() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(-1.0, 5.0, 6.0, 7.0); - let r: [u32; 4] = transmute(_mm_cmpeq_ss(a, b)); - let e: [u32; 4] = transmute(_mm_setr_ps(transmute(0u32), 2.0, 3.0, 4.0)); - assert_eq!(r, e); - - let b2 = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let r2: [u32; 4] = transmute(_mm_cmpeq_ss(a, b2)); - let e2: [u32; 4] = transmute(_mm_setr_ps(transmute(0xffffffffu32), 2.0, 3.0, 4.0)); - assert_eq!(r2, e2); - } - test_mm_cmpeq_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmplt_ss() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = 0u32; // a.extract(0) < b.extract(0) - let c1 = 0u32; // a.extract(0) < c.extract(0) - let d1 = !0u32; // a.extract(0) < d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmplt_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmplt_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmplt_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmplt_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmple_ss() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = 0u32; // a.extract(0) <= b.extract(0) - let c1 = !0u32; // a.extract(0) <= c.extract(0) - let d1 = !0u32; // a.extract(0) <= d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmple_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmple_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmple_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmple_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpgt_ss() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = !0u32; // a.extract(0) > b.extract(0) - let c1 = 0u32; // a.extract(0) > c.extract(0) - let d1 = 0u32; // a.extract(0) > d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpgt_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpgt_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpgt_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpgt_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpge_ss() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = !0u32; // a.extract(0) >= b.extract(0) - let c1 = !0u32; // a.extract(0) >= c.extract(0) - let d1 = 0u32; // a.extract(0) >= d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpge_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpge_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpge_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpge_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpneq_ss() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = !0u32; // a.extract(0) != b.extract(0) - let c1 = 0u32; // a.extract(0) != c.extract(0) - let d1 = !0u32; // a.extract(0) != d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpneq_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpneq_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpneq_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpneq_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpnlt_ss() { - // TODO: this test is exactly the same as for `_mm_cmpge_ss`, but there - // must be a difference. It may have to do with behavior in the - // presence of NaNs (signaling or quiet). If so, we should add tests - // for those. - - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = !0u32; // a.extract(0) >= b.extract(0) - let c1 = !0u32; // a.extract(0) >= c.extract(0) - let d1 = 0u32; // a.extract(0) >= d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpnlt_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpnlt_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpnlt_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpnlt_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpnle_ss() { - // TODO: this test is exactly the same as for `_mm_cmpgt_ss`, but there - // must be a difference. It may have to do with behavior in the - // presence - // of NaNs (signaling or quiet). If so, we should add tests for those. - - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = !0u32; // a.extract(0) > b.extract(0) - let c1 = 0u32; // a.extract(0) > c.extract(0) - let d1 = 0u32; // a.extract(0) > d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpnle_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpnle_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpnle_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpnle_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpngt_ss() { - // TODO: this test is exactly the same as for `_mm_cmple_ss`, but there - // must be a difference. It may have to do with behavior in the - // presence of NaNs (signaling or quiet). If so, we should add tests - // for those. - - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = 0u32; // a.extract(0) <= b.extract(0) - let c1 = !0u32; // a.extract(0) <= c.extract(0) - let d1 = !0u32; // a.extract(0) <= d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpngt_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpngt_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpngt_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpngt_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpnge_ss() { - // TODO: this test is exactly the same as for `_mm_cmplt_ss`, but there - // must be a difference. It may have to do with behavior in the - // presence of NaNs (signaling or quiet). If so, we should add tests - // for those. - - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = 0u32; // a.extract(0) < b.extract(0) - let c1 = 0u32; // a.extract(0) < c.extract(0) - let d1 = !0u32; // a.extract(0) < d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpnge_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpnge_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpnge_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpnge_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpord_ss() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(NAN, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = !0u32; // a.extract(0) ord b.extract(0) - let c1 = 0u32; // a.extract(0) ord c.extract(0) - let d1 = !0u32; // a.extract(0) ord d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpord_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpord_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpord_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpord_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpunord_ss() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); - let c = _mm_setr_ps(NAN, 5.0, 6.0, 7.0); - let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); - - let b1 = 0u32; // a.extract(0) unord b.extract(0) - let c1 = !0u32; // a.extract(0) unord c.extract(0) - let d1 = 0u32; // a.extract(0) unord d.extract(0) - - let rb: [u32; 4] = transmute(_mm_cmpunord_ss(a, b)); - let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); - assert_eq!(rb, eb); - - let rc: [u32; 4] = transmute(_mm_cmpunord_ss(a, c)); - let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); - assert_eq!(rc, ec); - - let rd: [u32; 4] = transmute(_mm_cmpunord_ss(a, d)); - let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); - assert_eq!(rd, ed); - } - test_mm_cmpunord_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpeq_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN); - let tru = !0u32; - let fls = 0u32; - - let e = [fls, fls, tru, fls]; - let r: [u32; 4] = transmute(_mm_cmpeq_ps(a, b)); - assert_eq!(r, e); - } - test_mm_cmpeq_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmplt_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN); - let tru = !0u32; - let fls = 0u32; - - let e = [tru, fls, fls, fls]; - let r: [u32; 4] = transmute(_mm_cmplt_ps(a, b)); - assert_eq!(r, e); - } - test_mm_cmplt_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmple_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, 4.0); - let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN); - let tru = !0u32; - let fls = 0u32; - - let e = [tru, fls, tru, fls]; - let r: [u32; 4] = transmute(_mm_cmple_ps(a, b)); - assert_eq!(r, e); - } - test_mm_cmple_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpgt_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, 42.0); - let tru = !0u32; - let fls = 0u32; - - let e = [fls, tru, fls, fls]; - let r: [u32; 4] = transmute(_mm_cmpgt_ps(a, b)); - assert_eq!(r, e); - } - test_mm_cmpgt_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpge_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, 42.0); - let tru = !0u32; - let fls = 0u32; - - let e = [fls, tru, tru, fls]; - let r: [u32; 4] = transmute(_mm_cmpge_ps(a, b)); - assert_eq!(r, e); - } - test_mm_cmpge_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpneq_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN); - let tru = !0u32; - let fls = 0u32; - - let e = [tru, tru, fls, tru]; - let r: [u32; 4] = transmute(_mm_cmpneq_ps(a, b)); - assert_eq!(r, e); - } - test_mm_cmpneq_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpnlt_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0); - let tru = !0u32; - let fls = 0u32; - - let e = [fls, tru, tru, tru]; - let r: [u32; 4] = transmute(_mm_cmpnlt_ps(a, b)); - assert_eq!(r, e); - } - test_mm_cmpnlt_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpnle_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0); - let tru = !0u32; - let fls = 0u32; - - let e = [fls, tru, fls, tru]; - let r: [u32; 4] = transmute(_mm_cmpnle_ps(a, b)); - assert_eq!(r, e); - } - test_mm_cmpnle_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpngt_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0); - let tru = !0u32; - let fls = 0u32; - - let e = [tru, fls, tru, tru]; - let r: [u32; 4] = transmute(_mm_cmpngt_ps(a, b)); - assert_eq!(r, e); + #[target_feature(enable = "sse")] + unsafe fn test_mm_add_ss() { + let a = _mm_set_ps(-1.0, 5.0, 0.0, -10.0); + let b = _mm_set_ps(-100.0, 20.0, 0.0, -5.0); + let r = _mm_add_ss(a, b); + assert_eq_m128(r, _mm_set_ps(-1.0, 5.0, 0.0, -15.0)); + } + test_mm_add_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_sub_ss() { + let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); + let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); + let r = _mm_sub_ss(a, b); + assert_eq_m128(r, _mm_setr_ps(99.0, 5.0, 0.0, -10.0)); + } + test_mm_sub_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_mul_ss() { + let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); + let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); + let r = _mm_mul_ss(a, b); + assert_eq_m128(r, _mm_setr_ps(100.0, 5.0, 0.0, -10.0)); + } + test_mm_mul_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_div_ss() { + let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); + let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); + let r = _mm_div_ss(a, b); + assert_eq_m128(r, _mm_setr_ps(0.01, 5.0, 0.0, -10.0)); + } + test_mm_div_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_sqrt_ss() { + let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); + let r = _mm_sqrt_ss(a); + let e = _mm_setr_ps(2.0, 13.0, 16.0, 100.0); + assert_eq_m128(r, e); + } + test_mm_sqrt_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_sqrt_ps() { + let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); + let r = _mm_sqrt_ps(a); + let e = _mm_setr_ps(2.0, 3.6055512, 4.0, 10.0); + assert_eq_m128(r, e); + } + test_mm_sqrt_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_rcp_ss() { + let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); + let r = _mm_rcp_ss(a); + let e = _mm_setr_ps(0.24993896, 13.0, 16.0, 100.0); + let rel_err = 0.00048828125; + + let r: [f32; 4] = transmute(r); + let e: [f32; 4] = transmute(e); + assert_approx_eq!(r[0], e[0], 2. * rel_err); + for i in 1..4 { + assert_eq!(r[i], e[i]); } - test_mm_cmpngt_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpnge_ps() { - let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); - let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0); - let tru = !0u32; - let fls = 0u32; - - let e = [tru, fls, fls, tru]; - let r: [u32; 4] = transmute(_mm_cmpnge_ps(a, b)); - assert_eq!(r, e); + } + test_mm_rcp_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_rcp_ps() { + let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); + let r = _mm_rcp_ps(a); + let e = _mm_setr_ps(0.24993896, 0.0769043, 0.06248474, 0.0099983215); + let rel_err = 0.00048828125; + + let r: [f32; 4] = transmute(r); + let e: [f32; 4] = transmute(e); + for i in 0..4 { + assert_approx_eq!(r[i], e[i], 2. * rel_err); } - test_mm_cmpnge_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpord_ps() { - let a = _mm_setr_ps(10.0, 50.0, NAN, NAN); - let b = _mm_setr_ps(15.0, NAN, 1.0, NAN); - let tru = !0u32; - let fls = 0u32; - - let e = [tru, fls, fls, fls]; - let r: [u32; 4] = transmute(_mm_cmpord_ps(a, b)); - assert_eq!(r, e); + } + test_mm_rcp_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_rsqrt_ss() { + let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); + let r = _mm_rsqrt_ss(a); + let e = _mm_setr_ps(0.49987793, 13.0, 16.0, 100.0); + let rel_err = 0.00048828125; + + let r: [f32; 4] = transmute(r); + let e: [f32; 4] = transmute(e); + assert_approx_eq!(r[0], e[0], 2. * rel_err); + for i in 1..4 { + assert_eq!(r[i], e[i]); } - test_mm_cmpord_ps(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cmpunord_ps() { - let a = _mm_setr_ps(10.0, 50.0, NAN, NAN); - let b = _mm_setr_ps(15.0, NAN, 1.0, NAN); - let tru = !0u32; - let fls = 0u32; - - let e = [fls, tru, tru, tru]; - let r: [u32; 4] = transmute(_mm_cmpunord_ps(a, b)); - assert_eq!(r, e); + } + test_mm_rsqrt_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_rsqrt_ps() { + let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0); + let r = _mm_rsqrt_ps(a); + let e = _mm_setr_ps(0.49987793, 0.2772827, 0.24993896, 0.099990845); + let rel_err = 0.00048828125; + + let r: [f32; 4] = transmute(r); + let e: [f32; 4] = transmute(e); + for i in 0..4 { + assert_approx_eq!(r[i], e[i], 2. * rel_err); } - test_mm_cmpunord_ps(); + } + test_mm_rsqrt_ps(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_comieq_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_min_ss() { + let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); + let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); + let r = _mm_min_ss(a, b); + assert_eq_m128(r, _mm_setr_ps(-100.0, 5.0, 0.0, -10.0)); + } + test_mm_min_ss(); - let ee = &[1i32, 0, 0, 0]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_min_ps() { + let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); + let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); + let r = _mm_min_ps(a, b); + assert_eq_m128(r, _mm_setr_ps(-100.0, 5.0, 0.0, -10.0)); + + // `_mm_min_ps` can **not** be implemented using the `simd_min` rust intrinsic because + // the semantics of `simd_min` are different to those of `_mm_min_ps` regarding handling + // of `-0.0`. + let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0); + let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0); + let r1: [u8; 16] = transmute(_mm_min_ps(a, b)); + let r2: [u8; 16] = transmute(_mm_min_ps(b, a)); + let a: [u8; 16] = transmute(a); + let b: [u8; 16] = transmute(b); + assert_eq!(r1, b); + assert_eq!(r2, a); + assert_ne!(a, b); // sanity check that -0.0 is actually present + } + test_mm_min_ps(); - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + #[target_feature(enable = "sse")] + unsafe fn test_mm_max_ss() { + let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); + let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); + let r = _mm_max_ss(a, b); + assert_eq_m128(r, _mm_setr_ps(-1.0, 5.0, 0.0, -10.0)); + } + test_mm_max_ss(); - let r = _mm_comieq_ss(a, b); + #[target_feature(enable = "sse")] + unsafe fn test_mm_max_ps() { + let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0); + let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0); + let r = _mm_max_ps(a, b); + assert_eq_m128(r, _mm_setr_ps(-1.0, 20.0, 0.0, -5.0)); + + // `_mm_max_ps` can **not** be implemented using the `simd_max` rust intrinsic because + // the semantics of `simd_max` are different to those of `_mm_max_ps` regarding handling + // of `-0.0`. + let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0); + let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0); + let r1: [u8; 16] = transmute(_mm_max_ps(a, b)); + let r2: [u8; 16] = transmute(_mm_max_ps(b, a)); + let a: [u8; 16] = transmute(a); + let b: [u8; 16] = transmute(b); + assert_eq!(r1, b); + assert_eq!(r2, a); + assert_ne!(a, b); // sanity check that -0.0 is actually present + } + test_mm_max_ps(); - assert_eq!( - ee[i], r, - "_mm_comieq_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } - } - test_mm_comieq_ss(); + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpeq_ss() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(-1.0, 5.0, 6.0, 7.0); + let r: [u32; 4] = transmute(_mm_cmpeq_ss(a, b)); + let e: [u32; 4] = transmute(_mm_setr_ps(transmute(0u32), 2.0, 3.0, 4.0)); + assert_eq!(r, e); + + let b2 = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let r2: [u32; 4] = transmute(_mm_cmpeq_ss(a, b2)); + let e2: [u32; 4] = transmute(_mm_setr_ps(transmute(0xffffffffu32), 2.0, 3.0, 4.0)); + assert_eq!(r2, e2); + } + test_mm_cmpeq_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmplt_ss() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = 0u32; // a.extract(0) < b.extract(0) + let c1 = 0u32; // a.extract(0) < c.extract(0) + let d1 = !0u32; // a.extract(0) < d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmplt_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmplt_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmplt_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmplt_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmple_ss() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = 0u32; // a.extract(0) <= b.extract(0) + let c1 = !0u32; // a.extract(0) <= c.extract(0) + let d1 = !0u32; // a.extract(0) <= d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmple_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmple_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmple_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmple_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpgt_ss() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = !0u32; // a.extract(0) > b.extract(0) + let c1 = 0u32; // a.extract(0) > c.extract(0) + let d1 = 0u32; // a.extract(0) > d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpgt_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpgt_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpgt_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpgt_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpge_ss() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = !0u32; // a.extract(0) >= b.extract(0) + let c1 = !0u32; // a.extract(0) >= c.extract(0) + let d1 = 0u32; // a.extract(0) >= d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpge_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpge_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpge_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpge_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpneq_ss() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = !0u32; // a.extract(0) != b.extract(0) + let c1 = 0u32; // a.extract(0) != c.extract(0) + let d1 = !0u32; // a.extract(0) != d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpneq_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpneq_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpneq_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpneq_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpnlt_ss() { + // TODO: this test is exactly the same as for `_mm_cmpge_ss`, but there + // must be a difference. It may have to do with behavior in the + // presence of NaNs (signaling or quiet). If so, we should add tests + // for those. + + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = !0u32; // a.extract(0) >= b.extract(0) + let c1 = !0u32; // a.extract(0) >= c.extract(0) + let d1 = 0u32; // a.extract(0) >= d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpnlt_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpnlt_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpnlt_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpnlt_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpnle_ss() { + // TODO: this test is exactly the same as for `_mm_cmpgt_ss`, but there + // must be a difference. It may have to do with behavior in the + // presence + // of NaNs (signaling or quiet). If so, we should add tests for those. + + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = !0u32; // a.extract(0) > b.extract(0) + let c1 = 0u32; // a.extract(0) > c.extract(0) + let d1 = 0u32; // a.extract(0) > d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpnle_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpnle_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpnle_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpnle_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpngt_ss() { + // TODO: this test is exactly the same as for `_mm_cmple_ss`, but there + // must be a difference. It may have to do with behavior in the + // presence of NaNs (signaling or quiet). If so, we should add tests + // for those. + + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = 0u32; // a.extract(0) <= b.extract(0) + let c1 = !0u32; // a.extract(0) <= c.extract(0) + let d1 = !0u32; // a.extract(0) <= d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpngt_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpngt_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpngt_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpngt_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpnge_ss() { + // TODO: this test is exactly the same as for `_mm_cmplt_ss`, but there + // must be a difference. It may have to do with behavior in the + // presence of NaNs (signaling or quiet). If so, we should add tests + // for those. + + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = 0u32; // a.extract(0) < b.extract(0) + let c1 = 0u32; // a.extract(0) < c.extract(0) + let d1 = !0u32; // a.extract(0) < d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpnge_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpnge_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpnge_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpnge_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpord_ss() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(NAN, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = !0u32; // a.extract(0) ord b.extract(0) + let c1 = 0u32; // a.extract(0) ord c.extract(0) + let d1 = !0u32; // a.extract(0) ord d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpord_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpord_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpord_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpord_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpunord_ss() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0); + let c = _mm_setr_ps(NAN, 5.0, 6.0, 7.0); + let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0); + + let b1 = 0u32; // a.extract(0) unord b.extract(0) + let c1 = !0u32; // a.extract(0) unord c.extract(0) + let d1 = 0u32; // a.extract(0) unord d.extract(0) + + let rb: [u32; 4] = transmute(_mm_cmpunord_ss(a, b)); + let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0)); + assert_eq!(rb, eb); + + let rc: [u32; 4] = transmute(_mm_cmpunord_ss(a, c)); + let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0)); + assert_eq!(rc, ec); + + let rd: [u32; 4] = transmute(_mm_cmpunord_ss(a, d)); + let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0)); + assert_eq!(rd, ed); + } + test_mm_cmpunord_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpeq_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN); + let tru = !0u32; + let fls = 0u32; + + let e = [fls, fls, tru, fls]; + let r: [u32; 4] = transmute(_mm_cmpeq_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpeq_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmplt_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN); + let tru = !0u32; + let fls = 0u32; + + let e = [tru, fls, fls, fls]; + let r: [u32; 4] = transmute(_mm_cmplt_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmplt_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmple_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, 4.0); + let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN); + let tru = !0u32; + let fls = 0u32; + + let e = [tru, fls, tru, fls]; + let r: [u32; 4] = transmute(_mm_cmple_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmple_ps(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_comilt_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpgt_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, 42.0); + let tru = !0u32; + let fls = 0u32; + + let e = [fls, tru, fls, fls]; + let r: [u32; 4] = transmute(_mm_cmpgt_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpgt_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpge_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, 42.0); + let tru = !0u32; + let fls = 0u32; + + let e = [fls, tru, tru, fls]; + let r: [u32; 4] = transmute(_mm_cmpge_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpge_ps(); - let ee = &[0i32, 1, 0, 0]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpneq_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN); + let tru = !0u32; + let fls = 0u32; + + let e = [tru, tru, fls, tru]; + let r: [u32; 4] = transmute(_mm_cmpneq_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpneq_ps(); - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpnlt_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0); + let tru = !0u32; + let fls = 0u32; + + let e = [fls, tru, tru, tru]; + let r: [u32; 4] = transmute(_mm_cmpnlt_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpnlt_ps(); - let r = _mm_comilt_ss(a, b); + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpnle_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0); + let tru = !0u32; + let fls = 0u32; + + let e = [fls, tru, fls, tru]; + let r: [u32; 4] = transmute(_mm_cmpnle_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpnle_ps(); - assert_eq!( - ee[i], r, - "_mm_comilt_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpngt_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0); + let tru = !0u32; + let fls = 0u32; + + let e = [tru, fls, tru, tru]; + let r: [u32; 4] = transmute(_mm_cmpngt_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpngt_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpnge_ps() { + let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN); + let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0); + let tru = !0u32; + let fls = 0u32; + + let e = [tru, fls, fls, tru]; + let r: [u32; 4] = transmute(_mm_cmpnge_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpnge_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpord_ps() { + let a = _mm_setr_ps(10.0, 50.0, NAN, NAN); + let b = _mm_setr_ps(15.0, NAN, 1.0, NAN); + let tru = !0u32; + let fls = 0u32; + + let e = [tru, fls, fls, fls]; + let r: [u32; 4] = transmute(_mm_cmpord_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpord_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cmpunord_ps() { + let a = _mm_setr_ps(10.0, 50.0, NAN, NAN); + let b = _mm_setr_ps(15.0, NAN, 1.0, NAN); + let tru = !0u32; + let fls = 0u32; + + let e = [fls, tru, tru, tru]; + let r: [u32; 4] = transmute(_mm_cmpunord_ps(a, b)); + assert_eq!(r, e); + } + test_mm_cmpunord_ps(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_comieq_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; + + let ee = &[1i32, 0, 0, 0]; + + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + + let r = _mm_comieq_ss(a, b); + + assert_eq!( + ee[i], r, + "_mm_comieq_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_comilt_ss(); + } + test_mm_comieq_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_comile_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_comilt_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[1i32, 1, 0, 0]; + let ee = &[0i32, 1, 0, 0]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_comile_ss(a, b); + let r = _mm_comilt_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_comile_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_comilt_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_comile_ss(); + } + test_mm_comilt_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_comigt_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_comile_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[1i32, 0, 1, 0]; + let ee = &[1i32, 1, 0, 0]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_comige_ss(a, b); + let r = _mm_comile_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_comige_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_comile_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_comigt_ss(); + } + test_mm_comile_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_comineq_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_comigt_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[0i32, 1, 1, 1]; + let ee = &[1i32, 0, 1, 0]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_comineq_ss(a, b); + let r = _mm_comige_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_comineq_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_comige_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_comineq_ss(); + } + test_mm_comigt_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_ucomieq_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_comineq_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[1i32, 0, 0, 0]; + let ee = &[0i32, 1, 1, 1]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_ucomieq_ss(a, b); + let r = _mm_comineq_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_ucomieq_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_comineq_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_ucomieq_ss(); + } + test_mm_comineq_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_ucomilt_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_ucomieq_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[0i32, 1, 0, 0]; + let ee = &[1i32, 0, 0, 0]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_ucomilt_ss(a, b); + let r = _mm_ucomieq_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_ucomilt_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_ucomieq_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_ucomilt_ss(); + } + test_mm_ucomieq_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_ucomile_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_ucomilt_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[1i32, 1, 0, 0]; + let ee = &[0i32, 1, 0, 0]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_ucomile_ss(a, b); + let r = _mm_ucomilt_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_ucomile_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_ucomilt_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_ucomile_ss(); + } + test_mm_ucomilt_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_ucomigt_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_ucomile_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[0i32, 0, 1, 0]; + let ee = &[1i32, 1, 0, 0]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_ucomigt_ss(a, b); + let r = _mm_ucomile_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_ucomigt_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_ucomile_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_ucomigt_ss(); + } + test_mm_ucomile_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_ucomige_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_ucomigt_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[1i32, 0, 1, 0]; + let ee = &[0i32, 0, 1, 0]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_ucomige_ss(a, b); + let r = _mm_ucomigt_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_ucomige_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_ucomigt_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_ucomige_ss(); + } + test_mm_ucomigt_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_ucomineq_ss() { - let aa = &[3.0f32, 12.0, 23.0, NAN]; - let bb = &[3.0f32, 47.5, 1.5, NAN]; + #[target_feature(enable = "sse")] + unsafe fn test_mm_ucomige_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; - let ee = &[0i32, 1, 1, 1]; + let ee = &[1i32, 0, 1, 0]; - for i in 0..4 { - let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); - let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); - let r = _mm_ucomineq_ss(a, b); + let r = _mm_ucomige_ss(a, b); - assert_eq!( - ee[i], r, - "_mm_ucomineq_ss({:?}, {:?}) = {}, expected: {} (i={})", - a, b, r, ee[i], i - ); - } + assert_eq!( + ee[i], r, + "_mm_ucomige_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_ucomineq_ss(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cvtss_si32() { - let inputs = &[42.0f32, -3.1, 4.0e10, 4.0e-20, NAN, 2147483500.1]; - let result = &[42i32, -3, i32::MIN, 0, i32::MIN, 2147483520]; - for i in 0..inputs.len() { - let x = _mm_setr_ps(inputs[i], 1.0, 3.0, 4.0); - let e = result[i]; - let r = _mm_cvtss_si32(x); - assert_eq!( - e, r, - "TestCase #{} _mm_cvtss_si32({:?}) = {}, expected: {}", - i, x, r, e - ); - } + } + test_mm_ucomige_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_ucomineq_ss() { + let aa = &[3.0f32, 12.0, 23.0, NAN]; + let bb = &[3.0f32, 47.5, 1.5, NAN]; + + let ee = &[0i32, 1, 1, 1]; + + for i in 0..4 { + let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0); + let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0); + + let r = _mm_ucomineq_ss(a, b); + + assert_eq!( + ee[i], r, + "_mm_ucomineq_ss({:?}, {:?}) = {}, expected: {} (i={})", + a, b, r, ee[i], i + ); } - test_mm_cvtss_si32(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cvttss_si32() { - let inputs = &[ - (42.0f32, 42i32), - (-31.4, -31), - (-33.5, -33), - (-34.5, -34), - (10.999, 10), - (-5.99, -5), - (4.0e10, i32::MIN), - (4.0e-10, 0), - (NAN, i32::MIN), - (2147483500.1, 2147483520), - ]; - for i in 0..inputs.len() { - let (xi, e) = inputs[i]; - let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0); - let r = _mm_cvttss_si32(x); - assert_eq!( - e, r, - "TestCase #{} _mm_cvttss_si32({:?}) = {}, expected: {}", - i, x, r, e - ); - } + } + test_mm_ucomineq_ss(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cvtss_si32() { + let inputs = &[42.0f32, -3.1, 4.0e10, 4.0e-20, NAN, 2147483500.1]; + let result = &[42i32, -3, i32::MIN, 0, i32::MIN, 2147483520]; + for i in 0..inputs.len() { + let x = _mm_setr_ps(inputs[i], 1.0, 3.0, 4.0); + let e = result[i]; + let r = _mm_cvtss_si32(x); + assert_eq!(e, r, "TestCase #{} _mm_cvtss_si32({:?}) = {}, expected: {}", i, x, r, e); } - test_mm_cvttss_si32(); + } + test_mm_cvtss_si32(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_cvtss_f32() { - let a = _mm_setr_ps(312.0134, 5.0, 6.0, 7.0); - assert_eq!(_mm_cvtss_f32(a), 312.0134); + #[target_feature(enable = "sse")] + unsafe fn test_mm_cvttss_si32() { + let inputs = &[ + (42.0f32, 42i32), + (-31.4, -31), + (-33.5, -33), + (-34.5, -34), + (10.999, 10), + (-5.99, -5), + (4.0e10, i32::MIN), + (4.0e-10, 0), + (NAN, i32::MIN), + (2147483500.1, 2147483520), + ]; + for i in 0..inputs.len() { + let (xi, e) = inputs[i]; + let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0); + let r = _mm_cvttss_si32(x); + assert_eq!(e, r, "TestCase #{} _mm_cvttss_si32({:?}) = {}, expected: {}", i, x, r, e); } - test_mm_cvtss_f32(); - - #[target_feature(enable = "sse")] - unsafe fn test_mm_cvtsi32_ss() { - let inputs = &[ - (4555i32, 4555.0f32), - (322223333, 322223330.0), - (-432, -432.0), - (-322223333, -322223330.0), - ]; - - for i in 0..inputs.len() { - let (x, f) = inputs[i]; - let a = _mm_setr_ps(5.0, 6.0, 7.0, 8.0); - let r = _mm_cvtsi32_ss(a, x); - let e = _mm_setr_ps(f, 6.0, 7.0, 8.0); - assert_eq_m128(e, r); - } + } + test_mm_cvttss_si32(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cvtss_f32() { + let a = _mm_setr_ps(312.0134, 5.0, 6.0, 7.0); + assert_eq!(_mm_cvtss_f32(a), 312.0134); + } + test_mm_cvtss_f32(); + + #[target_feature(enable = "sse")] + unsafe fn test_mm_cvtsi32_ss() { + let inputs = &[ + (4555i32, 4555.0f32), + (322223333, 322223330.0), + (-432, -432.0), + (-322223333, -322223330.0), + ]; + + for i in 0..inputs.len() { + let (x, f) = inputs[i]; + let a = _mm_setr_ps(5.0, 6.0, 7.0, 8.0); + let r = _mm_cvtsi32_ss(a, x); + let e = _mm_setr_ps(f, 6.0, 7.0, 8.0); + assert_eq_m128(e, r); } - test_mm_cvtsi32_ss(); - - // Intrinsic only available on x86_64 - #[cfg(target_arch = "x86_64")] - #[target_feature(enable = "sse")] - unsafe fn test_mm_cvtss_si64() { - let inputs = &[ - (42.0f32, 42i64), - (-31.4, -31), - (-33.5, -34), - (-34.5, -34), - (4.0e10, 40_000_000_000), - (4.0e-10, 0), - (f32::NAN, i64::MIN), - (2147483500.1, 2147483520), - (9.223371e18, 9223370937343148032), - ]; - for i in 0..inputs.len() { - let (xi, e) = inputs[i]; - let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0); - let r = _mm_cvtss_si64(x); - assert_eq!( - e, r, - "TestCase #{} _mm_cvtss_si64({:?}) = {}, expected: {}", - i, x, r, e - ); - } + } + test_mm_cvtsi32_ss(); + + // Intrinsic only available on x86_64 + #[cfg(target_arch = "x86_64")] + #[target_feature(enable = "sse")] + unsafe fn test_mm_cvtss_si64() { + let inputs = &[ + (42.0f32, 42i64), + (-31.4, -31), + (-33.5, -34), + (-34.5, -34), + (4.0e10, 40_000_000_000), + (4.0e-10, 0), + (f32::NAN, i64::MIN), + (2147483500.1, 2147483520), + (9.223371e18, 9223370937343148032), + ]; + for i in 0..inputs.len() { + let (xi, e) = inputs[i]; + let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0); + let r = _mm_cvtss_si64(x); + assert_eq!(e, r, "TestCase #{} _mm_cvtss_si64({:?}) = {}, expected: {}", i, x, r, e); } - #[cfg(target_arch = "x86_64")] - test_mm_cvtss_si64(); - - // Intrinsic only available on x86_64 - #[cfg(target_arch = "x86_64")] - #[target_feature(enable = "sse")] - unsafe fn test_mm_cvttss_si64() { - let inputs = &[ - (42.0f32, 42i64), - (-31.4, -31), - (-33.5, -33), - (-34.5, -34), - (10.999, 10), - (-5.99, -5), - (4.0e10, 40_000_000_000), - (4.0e-10, 0), - (f32::NAN, i64::MIN), - (2147483500.1, 2147483520), - (9.223371e18, 9223370937343148032), - (9.223372e18, i64::MIN), - ]; - for i in 0..inputs.len() { - let (xi, e) = inputs[i]; - let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0); - let r = _mm_cvttss_si64(x); - assert_eq!( - e, r, - "TestCase #{} _mm_cvttss_si64({:?}) = {}, expected: {}", - i, x, r, e - ); - } + } + #[cfg(target_arch = "x86_64")] + test_mm_cvtss_si64(); + + // Intrinsic only available on x86_64 + #[cfg(target_arch = "x86_64")] + #[target_feature(enable = "sse")] + unsafe fn test_mm_cvttss_si64() { + let inputs = &[ + (42.0f32, 42i64), + (-31.4, -31), + (-33.5, -33), + (-34.5, -34), + (10.999, 10), + (-5.99, -5), + (4.0e10, 40_000_000_000), + (4.0e-10, 0), + (f32::NAN, i64::MIN), + (2147483500.1, 2147483520), + (9.223371e18, 9223370937343148032), + (9.223372e18, i64::MIN), + ]; + for i in 0..inputs.len() { + let (xi, e) = inputs[i]; + let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0); + let r = _mm_cvttss_si64(x); + assert_eq!(e, r, "TestCase #{} _mm_cvttss_si64({:?}) = {}, expected: {}", i, x, r, e); } - #[cfg(target_arch = "x86_64")] - test_mm_cvttss_si64(); - - // Intrinsic only available on x86_64 - #[cfg(target_arch = "x86_64")] - #[target_feature(enable = "sse")] - unsafe fn test_mm_cvtsi64_ss() { - let inputs = &[ - (4555i64, 4555.0f32), - (322223333, 322223330.0), - (-432, -432.0), - (-322223333, -322223330.0), - (9223372036854775807, 9.223372e18), - (-9223372036854775808, -9.223372e18), - ]; - - for i in 0..inputs.len() { - let (x, f) = inputs[i]; - let a = _mm_setr_ps(5.0, 6.0, 7.0, 8.0); - let r = _mm_cvtsi64_ss(a, x); - let e = _mm_setr_ps(f, 6.0, 7.0, 8.0); - assert_eq_m128(e, r); - } + } + #[cfg(target_arch = "x86_64")] + test_mm_cvttss_si64(); + + // Intrinsic only available on x86_64 + #[cfg(target_arch = "x86_64")] + #[target_feature(enable = "sse")] + unsafe fn test_mm_cvtsi64_ss() { + let inputs = &[ + (4555i64, 4555.0f32), + (322223333, 322223330.0), + (-432, -432.0), + (-322223333, -322223330.0), + (9223372036854775807, 9.223372e18), + (-9223372036854775808, -9.223372e18), + ]; + + for i in 0..inputs.len() { + let (x, f) = inputs[i]; + let a = _mm_setr_ps(5.0, 6.0, 7.0, 8.0); + let r = _mm_cvtsi64_ss(a, x); + let e = _mm_setr_ps(f, 6.0, 7.0, 8.0); + assert_eq_m128(e, r); } - #[cfg(target_arch = "x86_64")] - test_mm_cvtsi64_ss(); + } + #[cfg(target_arch = "x86_64")] + test_mm_cvtsi64_ss(); - #[target_feature(enable = "sse")] - unsafe fn test_mm_movemask_ps() { - let r = _mm_movemask_ps(_mm_setr_ps(-1.0, 5.0, -5.0, 0.0)); - assert_eq!(r, 0b0101); + #[target_feature(enable = "sse")] + unsafe fn test_mm_movemask_ps() { + let r = _mm_movemask_ps(_mm_setr_ps(-1.0, 5.0, -5.0, 0.0)); + assert_eq!(r, 0b0101); - let r = _mm_movemask_ps(_mm_setr_ps(-1.0, -5.0, -5.0, 0.0)); - assert_eq!(r, 0b0111); - } - test_mm_movemask_ps(); - - let x = 0i8; - _mm_prefetch(&x, _MM_HINT_T0); - _mm_prefetch(&x, _MM_HINT_T1); - _mm_prefetch(&x, _MM_HINT_T2); - _mm_prefetch(&x, _MM_HINT_NTA); - _mm_prefetch(&x, _MM_HINT_ET0); - _mm_prefetch(&x, _MM_HINT_ET1); + let r = _mm_movemask_ps(_mm_setr_ps(-1.0, -5.0, -5.0, 0.0)); + assert_eq!(r, 0b0111); } + test_mm_movemask_ps(); + + let x = 0i8; + _mm_prefetch(&x, _MM_HINT_T0); + _mm_prefetch(&x, _MM_HINT_T1); + _mm_prefetch(&x, _MM_HINT_T2); + _mm_prefetch(&x, _MM_HINT_NTA); + _mm_prefetch(&x, _MM_HINT_ET0); + _mm_prefetch(&x, _MM_HINT_ET1); } diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs index e0088b9eb24d3..7aaf9c2624f9c 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs @@ -1,848 +1,843 @@ +// We're testing x86 target specific features +//@only-target: x86_64 i686 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; +use std::f64::NAN; +use std::mem::transmute; + fn main() { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - assert!(is_x86_feature_detected!("sse2")); + assert!(is_x86_feature_detected!("sse2")); - unsafe { - tests::test_sse2(); - } + unsafe { + test_sse2(); } } -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod tests { - #[cfg(target_arch = "x86")] - use std::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use std::arch::x86_64::*; - use std::f64::NAN; - use std::mem::transmute; +#[target_feature(enable = "sse2")] +unsafe fn _mm_setr_epi64x(a: i64, b: i64) -> __m128i { + _mm_set_epi64x(b, a) +} + +#[target_feature(enable = "sse2")] +unsafe fn test_sse2() { + // Mostly copied from library/stdarch/crates/core_arch/src/x86{,_64}/sse2.rs - #[target_feature(enable = "sse2")] unsafe fn _mm_setr_epi64x(a: i64, b: i64) -> __m128i { _mm_set_epi64x(b, a) } - #[target_feature(enable = "sse2")] - pub(super) unsafe fn test_sse2() { - // Mostly copied from library/stdarch/crates/core_arch/src/x86{,_64}/sse2.rs - - unsafe fn _mm_setr_epi64x(a: i64, b: i64) -> __m128i { - _mm_set_epi64x(b, a) + #[track_caller] + #[target_feature(enable = "sse")] + unsafe fn assert_eq_m128(a: __m128, b: __m128) { + let r = _mm_cmpeq_ps(a, b); + if _mm_movemask_ps(r) != 0b1111 { + panic!("{:?} != {:?}", a, b); } + } - #[track_caller] - #[target_feature(enable = "sse")] - unsafe fn assert_eq_m128(a: __m128, b: __m128) { - let r = _mm_cmpeq_ps(a, b); - if _mm_movemask_ps(r) != 0b1111 { - panic!("{:?} != {:?}", a, b); - } - } + #[track_caller] + #[target_feature(enable = "sse2")] + unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) { + assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b)) + } - #[track_caller] - #[target_feature(enable = "sse2")] - unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) { - assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b)) + #[track_caller] + #[target_feature(enable = "sse2")] + unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { + if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { + panic!("{:?} != {:?}", a, b); } + } - #[track_caller] - #[target_feature(enable = "sse2")] - unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { - if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { - panic!("{:?} != {:?}", a, b); - } - } + fn test_mm_pause() { + unsafe { _mm_pause() } + } + test_mm_pause(); - fn test_mm_pause() { - unsafe { _mm_pause() } - } - test_mm_pause(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_avg_epu8() { + let (a, b) = (_mm_set1_epi8(3), _mm_set1_epi8(9)); + let r = _mm_avg_epu8(a, b); + assert_eq_m128i(r, _mm_set1_epi8(6)); + } + test_mm_avg_epu8(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_avg_epu8() { - let (a, b) = (_mm_set1_epi8(3), _mm_set1_epi8(9)); - let r = _mm_avg_epu8(a, b); - assert_eq_m128i(r, _mm_set1_epi8(6)); - } - test_mm_avg_epu8(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_avg_epu16() { + let (a, b) = (_mm_set1_epi16(3), _mm_set1_epi16(9)); + let r = _mm_avg_epu16(a, b); + assert_eq_m128i(r, _mm_set1_epi16(6)); + } + test_mm_avg_epu16(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_avg_epu16() { - let (a, b) = (_mm_set1_epi16(3), _mm_set1_epi16(9)); - let r = _mm_avg_epu16(a, b); - assert_eq_m128i(r, _mm_set1_epi16(6)); - } - test_mm_avg_epu16(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_madd_epi16() { - let a = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8); - let b = _mm_setr_epi16(9, 10, 11, 12, 13, 14, 15, 16); - let r = _mm_madd_epi16(a, b); - let e = _mm_setr_epi32(29, 81, 149, 233); - assert_eq_m128i(r, e); - - let a = - _mm_setr_epi16(i16::MAX, i16::MAX, i16::MIN, i16::MIN, i16::MIN, i16::MAX, 0, 0); - let b = - _mm_setr_epi16(i16::MAX, i16::MAX, i16::MIN, i16::MIN, i16::MAX, i16::MIN, 0, 0); - let r = _mm_madd_epi16(a, b); - let e = _mm_setr_epi32(0x7FFE0002, i32::MIN, -0x7FFF0000, 0); - assert_eq_m128i(r, e); - } - test_mm_madd_epi16(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_madd_epi16() { + let a = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8); + let b = _mm_setr_epi16(9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm_madd_epi16(a, b); + let e = _mm_setr_epi32(29, 81, 149, 233); + assert_eq_m128i(r, e); + + let a = _mm_setr_epi16(i16::MAX, i16::MAX, i16::MIN, i16::MIN, i16::MIN, i16::MAX, 0, 0); + let b = _mm_setr_epi16(i16::MAX, i16::MAX, i16::MIN, i16::MIN, i16::MAX, i16::MIN, 0, 0); + let r = _mm_madd_epi16(a, b); + let e = _mm_setr_epi32(0x7FFE0002, i32::MIN, -0x7FFF0000, 0); + assert_eq_m128i(r, e); + } + test_mm_madd_epi16(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_mulhi_epi16() { - let (a, b) = (_mm_set1_epi16(1000), _mm_set1_epi16(-1001)); - let r = _mm_mulhi_epi16(a, b); - assert_eq_m128i(r, _mm_set1_epi16(-16)); - } - test_mm_mulhi_epi16(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_mulhi_epi16() { + let (a, b) = (_mm_set1_epi16(1000), _mm_set1_epi16(-1001)); + let r = _mm_mulhi_epi16(a, b); + assert_eq_m128i(r, _mm_set1_epi16(-16)); + } + test_mm_mulhi_epi16(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_mulhi_epu16() { - let (a, b) = (_mm_set1_epi16(1000), _mm_set1_epi16(1001)); - let r = _mm_mulhi_epu16(a, b); - assert_eq_m128i(r, _mm_set1_epi16(15)); - } - test_mm_mulhi_epu16(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_mul_epu32() { - let a = _mm_setr_epi64x(1_000_000_000, 1 << 34); - let b = _mm_setr_epi64x(1_000_000_000, 1 << 35); - let r = _mm_mul_epu32(a, b); - let e = _mm_setr_epi64x(1_000_000_000 * 1_000_000_000, 0); - assert_eq_m128i(r, e); - } - test_mm_mul_epu32(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_mulhi_epu16() { + let (a, b) = (_mm_set1_epi16(1000), _mm_set1_epi16(1001)); + let r = _mm_mulhi_epu16(a, b); + assert_eq_m128i(r, _mm_set1_epi16(15)); + } + test_mm_mulhi_epu16(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_mul_epu32() { + let a = _mm_setr_epi64x(1_000_000_000, 1 << 34); + let b = _mm_setr_epi64x(1_000_000_000, 1 << 35); + let r = _mm_mul_epu32(a, b); + let e = _mm_setr_epi64x(1_000_000_000 * 1_000_000_000, 0); + assert_eq_m128i(r, e); + } + test_mm_mul_epu32(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_sad_epu8() { - #[rustfmt::skip] + #[target_feature(enable = "sse2")] + unsafe fn test_mm_sad_epu8() { + #[rustfmt::skip] let a = _mm_setr_epi8( 255u8 as i8, 254u8 as i8, 253u8 as i8, 252u8 as i8, 1, 2, 3, 4, 155u8 as i8, 154u8 as i8, 153u8 as i8, 152u8 as i8, 1, 2, 3, 4, ); - let b = _mm_setr_epi8(0, 0, 0, 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2); - let r = _mm_sad_epu8(a, b); - let e = _mm_setr_epi64x(1020, 614); - assert_eq_m128i(r, e); - } - test_mm_sad_epu8(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_sll_epi16() { - let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF); - let r = _mm_sll_epi16(a, _mm_set_epi64x(0, 4)); - assert_eq_m128i( - r, - _mm_setr_epi16(0xCC0, -0xCC0, 0xDD0, -0xDD0, 0xEE0, -0xEE0, 0xFF0, -0xFF0), - ); - let r = _mm_sll_epi16(a, _mm_set_epi64x(4, 0)); - assert_eq_m128i(r, a); - let r = _mm_sll_epi16(a, _mm_set_epi64x(0, 16)); - assert_eq_m128i(r, _mm_set1_epi16(0)); - let r = _mm_sll_epi16(a, _mm_set_epi64x(0, i64::MAX)); - assert_eq_m128i(r, _mm_set1_epi16(0)); - } - test_mm_sll_epi16(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_srl_epi16() { - let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF); - let r = _mm_srl_epi16(a, _mm_set_epi64x(0, 4)); - assert_eq_m128i(r, _mm_setr_epi16(0xC, 0xFF3, 0xD, 0xFF2, 0xE, 0xFF1, 0xF, 0xFF0)); - let r = _mm_srl_epi16(a, _mm_set_epi64x(4, 0)); - assert_eq_m128i(r, a); - let r = _mm_srl_epi16(a, _mm_set_epi64x(0, 16)); - assert_eq_m128i(r, _mm_set1_epi16(0)); - let r = _mm_srl_epi16(a, _mm_set_epi64x(0, i64::MAX)); - assert_eq_m128i(r, _mm_set1_epi16(0)); - } - test_mm_srl_epi16(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_sra_epi16() { - let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF); - let r = _mm_sra_epi16(a, _mm_set_epi64x(0, 4)); - assert_eq_m128i(r, _mm_setr_epi16(0xC, -0xD, 0xD, -0xE, 0xE, -0xF, 0xF, -0x10)); - let r = _mm_sra_epi16(a, _mm_set_epi64x(4, 0)); - assert_eq_m128i(r, a); - let r = _mm_sra_epi16(a, _mm_set_epi64x(0, 16)); - assert_eq_m128i(r, _mm_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1)); - let r = _mm_sra_epi16(a, _mm_set_epi64x(0, i64::MAX)); - assert_eq_m128i(r, _mm_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1)); - } - test_mm_sra_epi16(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_sll_epi32() { - let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); - let r = _mm_sll_epi32(a, _mm_set_epi64x(0, 4)); - assert_eq_m128i(r, _mm_setr_epi32(0xEEEE0, -0xEEEE0, 0xFFFF0, -0xFFFF0)); - let r = _mm_sll_epi32(a, _mm_set_epi64x(4, 0)); - assert_eq_m128i(r, a); - let r = _mm_sll_epi32(a, _mm_set_epi64x(0, 32)); - assert_eq_m128i(r, _mm_set1_epi32(0)); - let r = _mm_sll_epi32(a, _mm_set_epi64x(0, i64::MAX)); - assert_eq_m128i(r, _mm_set1_epi32(0)); - } - test_mm_sll_epi32(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_srl_epi32() { - let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); - let r = _mm_srl_epi32(a, _mm_set_epi64x(0, 4)); - assert_eq_m128i(r, _mm_setr_epi32(0xEEE, 0xFFFF111, 0xFFF, 0xFFFF000)); - let r = _mm_srl_epi32(a, _mm_set_epi64x(4, 0)); - assert_eq_m128i(r, a); - let r = _mm_srl_epi32(a, _mm_set_epi64x(0, 32)); - assert_eq_m128i(r, _mm_set1_epi32(0)); - let r = _mm_srl_epi32(a, _mm_set_epi64x(0, i64::MAX)); - assert_eq_m128i(r, _mm_set1_epi32(0)); - } - test_mm_srl_epi32(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_sra_epi32() { - let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); - let r = _mm_sra_epi32(a, _mm_set_epi64x(0, 4)); - assert_eq_m128i(r, _mm_setr_epi32(0xEEE, -0xEEF, 0xFFF, -0x1000)); - let r = _mm_sra_epi32(a, _mm_set_epi64x(4, 0)); - assert_eq_m128i(r, a); - let r = _mm_sra_epi32(a, _mm_set_epi64x(0, 32)); - assert_eq_m128i(r, _mm_setr_epi32(0, -1, 0, -1)); - let r = _mm_sra_epi32(a, _mm_set_epi64x(0, i64::MAX)); - assert_eq_m128i(r, _mm_setr_epi32(0, -1, 0, -1)); - } - test_mm_sra_epi32(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_sll_epi64() { - let a = _mm_set_epi64x(0xFFFFFFFF, -0xFFFFFFFF); - let r = _mm_sll_epi64(a, _mm_set_epi64x(0, 4)); - assert_eq_m128i(r, _mm_set_epi64x(0xFFFFFFFF0, -0xFFFFFFFF0)); - let r = _mm_sll_epi64(a, _mm_set_epi64x(4, 0)); - assert_eq_m128i(r, a); - let r = _mm_sll_epi64(a, _mm_set_epi64x(0, 64)); - assert_eq_m128i(r, _mm_set1_epi64x(0)); - let r = _mm_sll_epi64(a, _mm_set_epi64x(0, i64::MAX)); - assert_eq_m128i(r, _mm_set1_epi64x(0)); - } - test_mm_sll_epi64(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_srl_epi64() { - let a = _mm_set_epi64x(0xFFFFFFFF, -0xFFFFFFFF); - let r = _mm_srl_epi64(a, _mm_set_epi64x(0, 4)); - assert_eq_m128i(r, _mm_set_epi64x(0xFFFFFFF, 0xFFFFFFFF0000000)); - let r = _mm_srl_epi64(a, _mm_set_epi64x(4, 0)); - assert_eq_m128i(r, a); - let r = _mm_srl_epi64(a, _mm_set_epi64x(0, 64)); - assert_eq_m128i(r, _mm_set1_epi64x(0)); - let r = _mm_srl_epi64(a, _mm_set_epi64x(0, i64::MAX)); - assert_eq_m128i(r, _mm_set1_epi64x(0)); - } - test_mm_srl_epi64(); + let b = _mm_setr_epi8(0, 0, 0, 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2); + let r = _mm_sad_epu8(a, b); + let e = _mm_setr_epi64x(1020, 614); + assert_eq_m128i(r, e); + } + test_mm_sad_epu8(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtepi32_ps() { - let a = _mm_setr_epi32(1, 2, 3, 4); - let r = _mm_cvtepi32_ps(a); - assert_eq_m128(r, _mm_setr_ps(1.0, 2.0, 3.0, 4.0)); - } - test_mm_cvtepi32_ps(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_sll_epi16() { + let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF); + let r = _mm_sll_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m128i( + r, + _mm_setr_epi16(0xCC0, -0xCC0, 0xDD0, -0xDD0, 0xEE0, -0xEE0, 0xFF0, -0xFF0), + ); + let r = _mm_sll_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m128i(r, a); + let r = _mm_sll_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m128i(r, _mm_set1_epi16(0)); + let r = _mm_sll_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m128i(r, _mm_set1_epi16(0)); + } + test_mm_sll_epi16(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtps_epi32() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let r = _mm_cvtps_epi32(a); - assert_eq_m128i(r, _mm_setr_epi32(1, 2, 3, 4)); - } - test_mm_cvtps_epi32(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_srl_epi16() { + let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF); + let r = _mm_srl_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m128i(r, _mm_setr_epi16(0xC, 0xFF3, 0xD, 0xFF2, 0xE, 0xFF1, 0xF, 0xFF0)); + let r = _mm_srl_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m128i(r, a); + let r = _mm_srl_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m128i(r, _mm_set1_epi16(0)); + let r = _mm_srl_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m128i(r, _mm_set1_epi16(0)); + } + test_mm_srl_epi16(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvttps_epi32() { - let a = _mm_setr_ps(-1.1, 2.2, -3.3, 6.6); - let r = _mm_cvttps_epi32(a); - assert_eq_m128i(r, _mm_setr_epi32(-1, 2, -3, 6)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_sra_epi16() { + let a = _mm_setr_epi16(0xCC, -0xCC, 0xDD, -0xDD, 0xEE, -0xEE, 0xFF, -0xFF); + let r = _mm_sra_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m128i(r, _mm_setr_epi16(0xC, -0xD, 0xD, -0xE, 0xE, -0xF, 0xF, -0x10)); + let r = _mm_sra_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m128i(r, a); + let r = _mm_sra_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m128i(r, _mm_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1)); + let r = _mm_sra_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m128i(r, _mm_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1)); + } + test_mm_sra_epi16(); - let a = _mm_setr_ps(f32::NEG_INFINITY, f32::INFINITY, f32::MIN, f32::MAX); - let r = _mm_cvttps_epi32(a); - assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, i32::MIN, i32::MIN)); - } - test_mm_cvttps_epi32(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_packs_epi16() { - let a = _mm_setr_epi16(0x80, -0x81, 0, 0, 0, 0, 0, 0); - let b = _mm_setr_epi16(0, 0, 0, 0, 0, 0, -0x81, 0x80); - let r = _mm_packs_epi16(a, b); - assert_eq_m128i( - r, - _mm_setr_epi8(0x7F, -0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0x80, 0x7F), - ); - } - test_mm_packs_epi16(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_packus_epi16() { - let a = _mm_setr_epi16(0x100, -1, 0, 0, 0, 0, 0, 0); - let b = _mm_setr_epi16(0, 0, 0, 0, 0, 0, -1, 0x100); - let r = _mm_packus_epi16(a, b); - assert_eq_m128i(r, _mm_setr_epi8(!0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, !0)); - } - test_mm_packus_epi16(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_packs_epi32() { - let a = _mm_setr_epi32(0x8000, -0x8001, 0, 0); - let b = _mm_setr_epi32(0, 0, -0x8001, 0x8000); - let r = _mm_packs_epi32(a, b); - assert_eq_m128i(r, _mm_setr_epi16(0x7FFF, -0x8000, 0, 0, 0, 0, -0x8000, 0x7FFF)); - } - test_mm_packs_epi32(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_min_sd() { - let a = _mm_setr_pd(1.0, 2.0); - let b = _mm_setr_pd(5.0, 10.0); - let r = _mm_min_sd(a, b); - assert_eq_m128d(r, _mm_setr_pd(1.0, 2.0)); - } - test_mm_min_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_min_pd() { - let a = _mm_setr_pd(-1.0, 5.0); - let b = _mm_setr_pd(-100.0, 20.0); - let r = _mm_min_pd(a, b); - assert_eq_m128d(r, _mm_setr_pd(-100.0, 5.0)); - - // `_mm_min_pd` can **not** be implemented using the `simd_min` rust intrinsic because - // the semantics of `simd_min` are different to those of `_mm_min_pd` regarding handling - // of `-0.0`. - let a = _mm_setr_pd(-0.0, 0.0); - let b = _mm_setr_pd(0.0, 0.0); - let r1: [u8; 16] = transmute(_mm_min_pd(a, b)); - let r2: [u8; 16] = transmute(_mm_min_pd(b, a)); - let a: [u8; 16] = transmute(a); - let b: [u8; 16] = transmute(b); - assert_eq!(r1, b); - assert_eq!(r2, a); - assert_ne!(a, b); // sanity check that -0.0 is actually present - } - test_mm_min_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_max_sd() { - let a = _mm_setr_pd(1.0, 2.0); - let b = _mm_setr_pd(5.0, 10.0); - let r = _mm_max_sd(a, b); - assert_eq_m128d(r, _mm_setr_pd(5.0, 2.0)); - } - test_mm_max_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_max_pd() { - let a = _mm_setr_pd(-1.0, 5.0); - let b = _mm_setr_pd(-100.0, 20.0); - let r = _mm_max_pd(a, b); - assert_eq_m128d(r, _mm_setr_pd(-1.0, 20.0)); - - // `_mm_max_pd` can **not** be implemented using the `simd_max` rust intrinsic because - // the semantics of `simd_max` are different to those of `_mm_max_pd` regarding handling - // of `-0.0`. - let a = _mm_setr_pd(-0.0, 0.0); - let b = _mm_setr_pd(0.0, 0.0); - let r1: [u8; 16] = transmute(_mm_max_pd(a, b)); - let r2: [u8; 16] = transmute(_mm_max_pd(b, a)); - let a: [u8; 16] = transmute(a); - let b: [u8; 16] = transmute(b); - assert_eq!(r1, b); - assert_eq!(r2, a); - assert_ne!(a, b); // sanity check that -0.0 is actually present - } - test_mm_max_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_sqrt_sd() { - let a = _mm_setr_pd(1.0, 2.0); - let b = _mm_setr_pd(5.0, 10.0); - let r = _mm_sqrt_sd(a, b); - assert_eq_m128d(r, _mm_setr_pd(5.0f64.sqrt(), 2.0)); - } - test_mm_sqrt_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_sll_epi32() { + let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm_sll_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m128i(r, _mm_setr_epi32(0xEEEE0, -0xEEEE0, 0xFFFF0, -0xFFFF0)); + let r = _mm_sll_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m128i(r, a); + let r = _mm_sll_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m128i(r, _mm_set1_epi32(0)); + let r = _mm_sll_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m128i(r, _mm_set1_epi32(0)); + } + test_mm_sll_epi32(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_sqrt_pd() { - let r = _mm_sqrt_pd(_mm_setr_pd(1.0, 2.0)); - assert_eq_m128d(r, _mm_setr_pd(1.0f64.sqrt(), 2.0f64.sqrt())); - } - test_mm_sqrt_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpeq_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(!0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpeq_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpeq_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmplt_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(!0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmplt_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmplt_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmple_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(!0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmple_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmple_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpgt_sd() { - let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(!0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpgt_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpgt_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpge_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(!0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpge_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpge_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpord_sd() { - let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpord_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpord_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpunord_sd() { - let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(!0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpunord_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpunord_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpneq_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(!0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpneq_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpneq_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpnlt_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpnlt_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpnlt_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpnle_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpnle_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpnle_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpngt_sd() { - let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpngt_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpngt_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpnge_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(0, transmute(2.0f64)); - let r = transmute::<_, __m128i>(_mm_cmpnge_sd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpnge_sd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpeq_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(!0, 0); - let r = transmute::<_, __m128i>(_mm_cmpeq_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpeq_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmplt_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(0, !0); - let r = transmute::<_, __m128i>(_mm_cmplt_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmplt_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmple_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(!0, !0); - let r = transmute::<_, __m128i>(_mm_cmple_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmple_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpgt_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(0, 0); - let r = transmute::<_, __m128i>(_mm_cmpgt_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpgt_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpge_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(!0, 0); - let r = transmute::<_, __m128i>(_mm_cmpge_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpge_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpord_pd() { - let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(0, !0); - let r = transmute::<_, __m128i>(_mm_cmpord_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpord_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpunord_pd() { - let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(!0, 0); - let r = transmute::<_, __m128i>(_mm_cmpunord_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpunord_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpneq_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(!0, !0); - let r = transmute::<_, __m128i>(_mm_cmpneq_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpneq_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpnlt_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); - let e = _mm_setr_epi64x(0, 0); - let r = transmute::<_, __m128i>(_mm_cmpnlt_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpnlt_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpnle_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(0, 0); - let r = transmute::<_, __m128i>(_mm_cmpnle_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpnle_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpngt_pd() { - let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(0, !0); - let r = transmute::<_, __m128i>(_mm_cmpngt_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpngt_pd(); - - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cmpnge_pd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - let e = _mm_setr_epi64x(0, !0); - let r = transmute::<_, __m128i>(_mm_cmpnge_pd(a, b)); - assert_eq_m128i(r, e); - } - test_mm_cmpnge_pd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_srl_epi32() { + let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm_srl_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m128i(r, _mm_setr_epi32(0xEEE, 0xFFFF111, 0xFFF, 0xFFFF000)); + let r = _mm_srl_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m128i(r, a); + let r = _mm_srl_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m128i(r, _mm_set1_epi32(0)); + let r = _mm_srl_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m128i(r, _mm_set1_epi32(0)); + } + test_mm_srl_epi32(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_comieq_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_comieq_sd(a, b) != 0); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_sra_epi32() { + let a = _mm_setr_epi32(0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm_sra_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m128i(r, _mm_setr_epi32(0xEEE, -0xEEF, 0xFFF, -0x1000)); + let r = _mm_sra_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m128i(r, a); + let r = _mm_sra_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m128i(r, _mm_setr_epi32(0, -1, 0, -1)); + let r = _mm_sra_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m128i(r, _mm_setr_epi32(0, -1, 0, -1)); + } + test_mm_sra_epi32(); - let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_comieq_sd(a, b) == 0); - } - test_mm_comieq_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_sll_epi64() { + let a = _mm_set_epi64x(0xFFFFFFFF, -0xFFFFFFFF); + let r = _mm_sll_epi64(a, _mm_set_epi64x(0, 4)); + assert_eq_m128i(r, _mm_set_epi64x(0xFFFFFFFF0, -0xFFFFFFFF0)); + let r = _mm_sll_epi64(a, _mm_set_epi64x(4, 0)); + assert_eq_m128i(r, a); + let r = _mm_sll_epi64(a, _mm_set_epi64x(0, 64)); + assert_eq_m128i(r, _mm_set1_epi64x(0)); + let r = _mm_sll_epi64(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m128i(r, _mm_set1_epi64x(0)); + } + test_mm_sll_epi64(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_comilt_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_comilt_sd(a, b) == 0); - } - test_mm_comilt_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_srl_epi64() { + let a = _mm_set_epi64x(0xFFFFFFFF, -0xFFFFFFFF); + let r = _mm_srl_epi64(a, _mm_set_epi64x(0, 4)); + assert_eq_m128i(r, _mm_set_epi64x(0xFFFFFFF, 0xFFFFFFFF0000000)); + let r = _mm_srl_epi64(a, _mm_set_epi64x(4, 0)); + assert_eq_m128i(r, a); + let r = _mm_srl_epi64(a, _mm_set_epi64x(0, 64)); + assert_eq_m128i(r, _mm_set1_epi64x(0)); + let r = _mm_srl_epi64(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m128i(r, _mm_set1_epi64x(0)); + } + test_mm_srl_epi64(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_comile_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_comile_sd(a, b) != 0); - } - test_mm_comile_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtepi32_ps() { + let a = _mm_setr_epi32(1, 2, 3, 4); + let r = _mm_cvtepi32_ps(a); + assert_eq_m128(r, _mm_setr_ps(1.0, 2.0, 3.0, 4.0)); + } + test_mm_cvtepi32_ps(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_comigt_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_comigt_sd(a, b) == 0); - } - test_mm_comigt_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtps_epi32() { + let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let r = _mm_cvtps_epi32(a); + assert_eq_m128i(r, _mm_setr_epi32(1, 2, 3, 4)); + } + test_mm_cvtps_epi32(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_comige_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_comige_sd(a, b) != 0); - } - test_mm_comige_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvttps_epi32() { + let a = _mm_setr_ps(-1.1, 2.2, -3.3, 6.6); + let r = _mm_cvttps_epi32(a); + assert_eq_m128i(r, _mm_setr_epi32(-1, 2, -3, 6)); + + let a = _mm_setr_ps(f32::NEG_INFINITY, f32::INFINITY, f32::MIN, f32::MAX); + let r = _mm_cvttps_epi32(a); + assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, i32::MIN, i32::MIN)); + } + test_mm_cvttps_epi32(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_comineq_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_comineq_sd(a, b) == 0); - } - test_mm_comineq_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_packs_epi16() { + let a = _mm_setr_epi16(0x80, -0x81, 0, 0, 0, 0, 0, 0); + let b = _mm_setr_epi16(0, 0, 0, 0, 0, 0, -0x81, 0x80); + let r = _mm_packs_epi16(a, b); + assert_eq_m128i( + r, + _mm_setr_epi8(0x7F, -0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0x80, 0x7F), + ); + } + test_mm_packs_epi16(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_ucomieq_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_ucomieq_sd(a, b) != 0); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_packus_epi16() { + let a = _mm_setr_epi16(0x100, -1, 0, 0, 0, 0, 0, 0); + let b = _mm_setr_epi16(0, 0, 0, 0, 0, 0, -1, 0x100); + let r = _mm_packus_epi16(a, b); + assert_eq_m128i(r, _mm_setr_epi8(!0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, !0)); + } + test_mm_packus_epi16(); - let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(NAN, 3.0)); - assert!(_mm_ucomieq_sd(a, b) == 0); - } - test_mm_ucomieq_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_packs_epi32() { + let a = _mm_setr_epi32(0x8000, -0x8001, 0, 0); + let b = _mm_setr_epi32(0, 0, -0x8001, 0x8000); + let r = _mm_packs_epi32(a, b); + assert_eq_m128i(r, _mm_setr_epi16(0x7FFF, -0x8000, 0, 0, 0, 0, -0x8000, 0x7FFF)); + } + test_mm_packs_epi32(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_ucomilt_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_ucomilt_sd(a, b) == 0); - } - test_mm_ucomilt_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_min_sd() { + let a = _mm_setr_pd(1.0, 2.0); + let b = _mm_setr_pd(5.0, 10.0); + let r = _mm_min_sd(a, b); + assert_eq_m128d(r, _mm_setr_pd(1.0, 2.0)); + } + test_mm_min_sd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_ucomile_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_ucomile_sd(a, b) != 0); - } - test_mm_ucomile_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_min_pd() { + let a = _mm_setr_pd(-1.0, 5.0); + let b = _mm_setr_pd(-100.0, 20.0); + let r = _mm_min_pd(a, b); + assert_eq_m128d(r, _mm_setr_pd(-100.0, 5.0)); + + // `_mm_min_pd` can **not** be implemented using the `simd_min` rust intrinsic because + // the semantics of `simd_min` are different to those of `_mm_min_pd` regarding handling + // of `-0.0`. + let a = _mm_setr_pd(-0.0, 0.0); + let b = _mm_setr_pd(0.0, 0.0); + let r1: [u8; 16] = transmute(_mm_min_pd(a, b)); + let r2: [u8; 16] = transmute(_mm_min_pd(b, a)); + let a: [u8; 16] = transmute(a); + let b: [u8; 16] = transmute(b); + assert_eq!(r1, b); + assert_eq!(r2, a); + assert_ne!(a, b); // sanity check that -0.0 is actually present + } + test_mm_min_pd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_ucomigt_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_ucomigt_sd(a, b) == 0); - } - test_mm_ucomigt_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_max_sd() { + let a = _mm_setr_pd(1.0, 2.0); + let b = _mm_setr_pd(5.0, 10.0); + let r = _mm_max_sd(a, b); + assert_eq_m128d(r, _mm_setr_pd(5.0, 2.0)); + } + test_mm_max_sd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_ucomige_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_ucomige_sd(a, b) != 0); - } - test_mm_ucomige_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_max_pd() { + let a = _mm_setr_pd(-1.0, 5.0); + let b = _mm_setr_pd(-100.0, 20.0); + let r = _mm_max_pd(a, b); + assert_eq_m128d(r, _mm_setr_pd(-1.0, 20.0)); + + // `_mm_max_pd` can **not** be implemented using the `simd_max` rust intrinsic because + // the semantics of `simd_max` are different to those of `_mm_max_pd` regarding handling + // of `-0.0`. + let a = _mm_setr_pd(-0.0, 0.0); + let b = _mm_setr_pd(0.0, 0.0); + let r1: [u8; 16] = transmute(_mm_max_pd(a, b)); + let r2: [u8; 16] = transmute(_mm_max_pd(b, a)); + let a: [u8; 16] = transmute(a); + let b: [u8; 16] = transmute(b); + assert_eq!(r1, b); + assert_eq!(r2, a); + assert_ne!(a, b); // sanity check that -0.0 is actually present + } + test_mm_max_pd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_ucomineq_sd() { - let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); - assert!(_mm_ucomineq_sd(a, b) == 0); - } - test_mm_ucomineq_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_sqrt_sd() { + let a = _mm_setr_pd(1.0, 2.0); + let b = _mm_setr_pd(5.0, 10.0); + let r = _mm_sqrt_sd(a, b); + assert_eq_m128d(r, _mm_setr_pd(5.0f64.sqrt(), 2.0)); + } + test_mm_sqrt_sd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtpd_ps() { - let r = _mm_cvtpd_ps(_mm_setr_pd(-1.0, 5.0)); - assert_eq_m128(r, _mm_setr_ps(-1.0, 5.0, 0.0, 0.0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_sqrt_pd() { + let r = _mm_sqrt_pd(_mm_setr_pd(1.0, 2.0)); + assert_eq_m128d(r, _mm_setr_pd(1.0f64.sqrt(), 2.0f64.sqrt())); + } + test_mm_sqrt_pd(); - let r = _mm_cvtpd_ps(_mm_setr_pd(-1.0, -5.0)); - assert_eq_m128(r, _mm_setr_ps(-1.0, -5.0, 0.0, 0.0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpeq_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(!0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpeq_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpeq_sd(); - let r = _mm_cvtpd_ps(_mm_setr_pd(f64::MAX, f64::MIN)); - assert_eq_m128(r, _mm_setr_ps(f32::INFINITY, f32::NEG_INFINITY, 0.0, 0.0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmplt_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(!0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmplt_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmplt_sd(); - let r = _mm_cvtpd_ps(_mm_setr_pd(f32::MAX as f64, f32::MIN as f64)); - assert_eq_m128(r, _mm_setr_ps(f32::MAX, f32::MIN, 0.0, 0.0)); - } - test_mm_cvtpd_ps(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmple_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(!0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmple_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmple_sd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtps_pd() { - let r = _mm_cvtps_pd(_mm_setr_ps(-1.0, 2.0, -3.0, 5.0)); - assert_eq_m128d(r, _mm_setr_pd(-1.0, 2.0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpgt_sd() { + let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(!0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpgt_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpgt_sd(); - let r = _mm_cvtps_pd(_mm_setr_ps(f32::MAX, f32::INFINITY, f32::NEG_INFINITY, f32::MIN)); - assert_eq_m128d(r, _mm_setr_pd(f32::MAX as f64, f64::INFINITY)); - } - test_mm_cvtps_pd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpge_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(!0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpge_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpge_sd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtpd_epi32() { - let r = _mm_cvtpd_epi32(_mm_setr_pd(-1.0, 5.0)); - assert_eq_m128i(r, _mm_setr_epi32(-1, 5, 0, 0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpord_sd() { + let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpord_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpord_sd(); - let r = _mm_cvtpd_epi32(_mm_setr_pd(-1.0, -5.0)); - assert_eq_m128i(r, _mm_setr_epi32(-1, -5, 0, 0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpunord_sd() { + let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(!0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpunord_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpunord_sd(); - let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::MAX, f64::MIN)); - assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpneq_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(!0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpneq_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpneq_sd(); - let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::INFINITY, f64::NEG_INFINITY)); - assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpnlt_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpnlt_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpnlt_sd(); - let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::NAN, f64::NAN)); - assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0)); - } - test_mm_cvtpd_epi32(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpnle_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpnle_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpnle_sd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvttpd_epi32() { - let a = _mm_setr_pd(-1.1, 2.2); - let r = _mm_cvttpd_epi32(a); - assert_eq_m128i(r, _mm_setr_epi32(-1, 2, 0, 0)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpngt_sd() { + let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpngt_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpngt_sd(); - let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN); - let r = _mm_cvttpd_epi32(a); - assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0)); - } - test_mm_cvttpd_epi32(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpnge_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(0, transmute(2.0f64)); + let r = transmute::<_, __m128i>(_mm_cmpnge_sd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpnge_sd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtsd_si32() { - let r = _mm_cvtsd_si32(_mm_setr_pd(-2.0, 5.0)); - assert_eq!(r, -2); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpeq_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(!0, 0); + let r = transmute::<_, __m128i>(_mm_cmpeq_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpeq_pd(); - let r = _mm_cvtsd_si32(_mm_setr_pd(f64::MAX, f64::MIN)); - assert_eq!(r, i32::MIN); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmplt_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(0, !0); + let r = transmute::<_, __m128i>(_mm_cmplt_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmplt_pd(); - let r = _mm_cvtsd_si32(_mm_setr_pd(f64::NAN, f64::NAN)); - assert_eq!(r, i32::MIN); - } - test_mm_cvtsd_si32(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmple_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(!0, !0); + let r = transmute::<_, __m128i>(_mm_cmple_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmple_pd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvttsd_si32() { - let a = _mm_setr_pd(-1.1, 2.2); - let r = _mm_cvttsd_si32(a); - assert_eq!(r, -1); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpgt_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(0, 0); + let r = transmute::<_, __m128i>(_mm_cmpgt_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpgt_pd(); - let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN); - let r = _mm_cvttsd_si32(a); - assert_eq!(r, i32::MIN); - } - test_mm_cvttsd_si32(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpge_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(!0, 0); + let r = transmute::<_, __m128i>(_mm_cmpge_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpge_pd(); - // Intrinsic only available on x86_64 - #[cfg(target_arch = "x86_64")] - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtsd_si64() { - let r = _mm_cvtsd_si64(_mm_setr_pd(-2.0, 5.0)); - assert_eq!(r, -2_i64); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpord_pd() { + let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(0, !0); + let r = transmute::<_, __m128i>(_mm_cmpord_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpord_pd(); - let r = _mm_cvtsd_si64(_mm_setr_pd(f64::MAX, f64::MIN)); - assert_eq!(r, i64::MIN); - } - #[cfg(target_arch = "x86_64")] - test_mm_cvtsd_si64(); - - // Intrinsic only available on x86_64 - #[cfg(target_arch = "x86_64")] - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvttsd_si64() { - let a = _mm_setr_pd(-1.1, 2.2); - let r = _mm_cvttsd_si64(a); - assert_eq!(r, -1_i64); - } - #[cfg(target_arch = "x86_64")] - test_mm_cvttsd_si64(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpunord_pd() { + let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(!0, 0); + let r = transmute::<_, __m128i>(_mm_cmpunord_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpunord_pd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtsd_ss() { - let a = _mm_setr_ps(-1.1, -2.2, 3.3, 4.4); - let b = _mm_setr_pd(2.0, -5.0); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpneq_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(!0, !0); + let r = transmute::<_, __m128i>(_mm_cmpneq_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpneq_pd(); - let r = _mm_cvtsd_ss(a, b); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpnlt_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(5.0, 3.0)); + let e = _mm_setr_epi64x(0, 0); + let r = transmute::<_, __m128i>(_mm_cmpnlt_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpnlt_pd(); - assert_eq_m128(r, _mm_setr_ps(2.0, -2.2, 3.3, 4.4)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpnle_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(0, 0); + let r = transmute::<_, __m128i>(_mm_cmpnle_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpnle_pd(); - let a = _mm_setr_ps(-1.1, f32::NEG_INFINITY, f32::MAX, f32::NEG_INFINITY); - let b = _mm_setr_pd(f64::INFINITY, -5.0); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpngt_pd() { + let (a, b) = (_mm_setr_pd(5.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(0, !0); + let r = transmute::<_, __m128i>(_mm_cmpngt_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpngt_pd(); - let r = _mm_cvtsd_ss(a, b); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cmpnge_pd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + let e = _mm_setr_epi64x(0, !0); + let r = transmute::<_, __m128i>(_mm_cmpnge_pd(a, b)); + assert_eq_m128i(r, e); + } + test_mm_cmpnge_pd(); - assert_eq_m128( - r, - _mm_setr_ps(f32::INFINITY, f32::NEG_INFINITY, f32::MAX, f32::NEG_INFINITY), - ); - } - test_mm_cvtsd_ss(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_comieq_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_comieq_sd(a, b) != 0); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_cvtss_sd() { - let a = _mm_setr_pd(-1.1, 2.2); - let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_comieq_sd(a, b) == 0); + } + test_mm_comieq_sd(); - let r = _mm_cvtss_sd(a, b); - assert_eq_m128d(r, _mm_setr_pd(1.0, 2.2)); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_comilt_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_comilt_sd(a, b) == 0); + } + test_mm_comilt_sd(); - let a = _mm_setr_pd(-1.1, f64::INFINITY); - let b = _mm_setr_ps(f32::NEG_INFINITY, 2.0, 3.0, 4.0); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_comile_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_comile_sd(a, b) != 0); + } + test_mm_comile_sd(); - let r = _mm_cvtss_sd(a, b); - assert_eq_m128d(r, _mm_setr_pd(f64::NEG_INFINITY, f64::INFINITY)); - } - test_mm_cvtss_sd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_comigt_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_comigt_sd(a, b) == 0); + } + test_mm_comigt_sd(); - #[target_feature(enable = "sse2")] - unsafe fn test_mm_movemask_pd() { - let r = _mm_movemask_pd(_mm_setr_pd(-1.0, 5.0)); - assert_eq!(r, 0b01); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_comige_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_comige_sd(a, b) != 0); + } + test_mm_comige_sd(); - let r = _mm_movemask_pd(_mm_setr_pd(-1.0, -5.0)); - assert_eq!(r, 0b11); - } - test_mm_movemask_pd(); + #[target_feature(enable = "sse2")] + unsafe fn test_mm_comineq_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_comineq_sd(a, b) == 0); + } + test_mm_comineq_sd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_ucomieq_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_ucomieq_sd(a, b) != 0); + + let (a, b) = (_mm_setr_pd(NAN, 2.0), _mm_setr_pd(NAN, 3.0)); + assert!(_mm_ucomieq_sd(a, b) == 0); + } + test_mm_ucomieq_sd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_ucomilt_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_ucomilt_sd(a, b) == 0); + } + test_mm_ucomilt_sd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_ucomile_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_ucomile_sd(a, b) != 0); + } + test_mm_ucomile_sd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_ucomigt_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_ucomigt_sd(a, b) == 0); + } + test_mm_ucomigt_sd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_ucomige_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_ucomige_sd(a, b) != 0); + } + test_mm_ucomige_sd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_ucomineq_sd() { + let (a, b) = (_mm_setr_pd(1.0, 2.0), _mm_setr_pd(1.0, 3.0)); + assert!(_mm_ucomineq_sd(a, b) == 0); + } + test_mm_ucomineq_sd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtpd_ps() { + let r = _mm_cvtpd_ps(_mm_setr_pd(-1.0, 5.0)); + assert_eq_m128(r, _mm_setr_ps(-1.0, 5.0, 0.0, 0.0)); + + let r = _mm_cvtpd_ps(_mm_setr_pd(-1.0, -5.0)); + assert_eq_m128(r, _mm_setr_ps(-1.0, -5.0, 0.0, 0.0)); + + let r = _mm_cvtpd_ps(_mm_setr_pd(f64::MAX, f64::MIN)); + assert_eq_m128(r, _mm_setr_ps(f32::INFINITY, f32::NEG_INFINITY, 0.0, 0.0)); + + let r = _mm_cvtpd_ps(_mm_setr_pd(f32::MAX as f64, f32::MIN as f64)); + assert_eq_m128(r, _mm_setr_ps(f32::MAX, f32::MIN, 0.0, 0.0)); + } + test_mm_cvtpd_ps(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtps_pd() { + let r = _mm_cvtps_pd(_mm_setr_ps(-1.0, 2.0, -3.0, 5.0)); + assert_eq_m128d(r, _mm_setr_pd(-1.0, 2.0)); + + let r = _mm_cvtps_pd(_mm_setr_ps(f32::MAX, f32::INFINITY, f32::NEG_INFINITY, f32::MIN)); + assert_eq_m128d(r, _mm_setr_pd(f32::MAX as f64, f64::INFINITY)); + } + test_mm_cvtps_pd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtpd_epi32() { + let r = _mm_cvtpd_epi32(_mm_setr_pd(-1.0, 5.0)); + assert_eq_m128i(r, _mm_setr_epi32(-1, 5, 0, 0)); + + let r = _mm_cvtpd_epi32(_mm_setr_pd(-1.0, -5.0)); + assert_eq_m128i(r, _mm_setr_epi32(-1, -5, 0, 0)); + + let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::MAX, f64::MIN)); + assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0)); + + let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::INFINITY, f64::NEG_INFINITY)); + assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0)); + + let r = _mm_cvtpd_epi32(_mm_setr_pd(f64::NAN, f64::NAN)); + assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0)); + } + test_mm_cvtpd_epi32(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvttpd_epi32() { + let a = _mm_setr_pd(-1.1, 2.2); + let r = _mm_cvttpd_epi32(a); + assert_eq_m128i(r, _mm_setr_epi32(-1, 2, 0, 0)); + + let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN); + let r = _mm_cvttpd_epi32(a); + assert_eq_m128i(r, _mm_setr_epi32(i32::MIN, i32::MIN, 0, 0)); + } + test_mm_cvttpd_epi32(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtsd_si32() { + let r = _mm_cvtsd_si32(_mm_setr_pd(-2.0, 5.0)); + assert_eq!(r, -2); + + let r = _mm_cvtsd_si32(_mm_setr_pd(f64::MAX, f64::MIN)); + assert_eq!(r, i32::MIN); + + let r = _mm_cvtsd_si32(_mm_setr_pd(f64::NAN, f64::NAN)); + assert_eq!(r, i32::MIN); + } + test_mm_cvtsd_si32(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvttsd_si32() { + let a = _mm_setr_pd(-1.1, 2.2); + let r = _mm_cvttsd_si32(a); + assert_eq!(r, -1); + + let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN); + let r = _mm_cvttsd_si32(a); + assert_eq!(r, i32::MIN); + } + test_mm_cvttsd_si32(); + + // Intrinsic only available on x86_64 + #[cfg(target_arch = "x86_64")] + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtsd_si64() { + let r = _mm_cvtsd_si64(_mm_setr_pd(-2.0, 5.0)); + assert_eq!(r, -2_i64); + + let r = _mm_cvtsd_si64(_mm_setr_pd(f64::MAX, f64::MIN)); + assert_eq!(r, i64::MIN); + } + #[cfg(target_arch = "x86_64")] + test_mm_cvtsd_si64(); + + // Intrinsic only available on x86_64 + #[cfg(target_arch = "x86_64")] + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvttsd_si64() { + let a = _mm_setr_pd(-1.1, 2.2); + let r = _mm_cvttsd_si64(a); + assert_eq!(r, -1_i64); + } + #[cfg(target_arch = "x86_64")] + test_mm_cvttsd_si64(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtsd_ss() { + let a = _mm_setr_ps(-1.1, -2.2, 3.3, 4.4); + let b = _mm_setr_pd(2.0, -5.0); + + let r = _mm_cvtsd_ss(a, b); + + assert_eq_m128(r, _mm_setr_ps(2.0, -2.2, 3.3, 4.4)); + + let a = _mm_setr_ps(-1.1, f32::NEG_INFINITY, f32::MAX, f32::NEG_INFINITY); + let b = _mm_setr_pd(f64::INFINITY, -5.0); + + let r = _mm_cvtsd_ss(a, b); + + assert_eq_m128( + r, + _mm_setr_ps(f32::INFINITY, f32::NEG_INFINITY, f32::MAX, f32::NEG_INFINITY), + ); + } + test_mm_cvtsd_ss(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_cvtss_sd() { + let a = _mm_setr_pd(-1.1, 2.2); + let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); + + let r = _mm_cvtss_sd(a, b); + assert_eq_m128d(r, _mm_setr_pd(1.0, 2.2)); + + let a = _mm_setr_pd(-1.1, f64::INFINITY); + let b = _mm_setr_ps(f32::NEG_INFINITY, 2.0, 3.0, 4.0); + + let r = _mm_cvtss_sd(a, b); + assert_eq_m128d(r, _mm_setr_pd(f64::NEG_INFINITY, f64::INFINITY)); + } + test_mm_cvtss_sd(); + + #[target_feature(enable = "sse2")] + unsafe fn test_mm_movemask_pd() { + let r = _mm_movemask_pd(_mm_setr_pd(-1.0, 5.0)); + assert_eq!(r, 0b01); + + let r = _mm_movemask_pd(_mm_setr_pd(-1.0, -5.0)); + assert_eq!(r, 0b11); } + test_mm_movemask_pd(); } diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse3-ssse3.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse3-ssse3.rs index 0b3be7f3cbd00..10842160abdc6 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse3-ssse3.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse3-ssse3.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 // SSSE3 implicitly enables SSE3 //@compile-flags: -C target-feature=+ssse3 diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse41.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse41.rs index 8cd4e6308e29f..7331c6ed0db33 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse41.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse41.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+sse4.1 #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse42.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse42.rs index c87eb51877431..30908baa6c15e 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse42.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse42.rs @@ -1,12 +1,5 @@ -// Ignore everything except x86 and x86_64 -// Any new targets that are added to CI should be ignored here. -// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) -//@ignore-target-aarch64 -//@ignore-target-arm -//@ignore-target-avr -//@ignore-target-s390x -//@ignore-target-thumbv7em -//@ignore-target-wasm +// We're testing x86 target specific features +//@only-target: x86_64 i686 //@compile-flags: -C target-feature=+sse4.2 #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/simd-intrinsic-generic-elements.rs b/src/tools/miri/tests/pass/simd-intrinsic-generic-elements.rs deleted file mode 100644 index 4a87f8c3ca720..0000000000000 --- a/src/tools/miri/tests/pass/simd-intrinsic-generic-elements.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![feature(repr_simd)] - -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x2(i32, i32); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); - -fn main() { - let _x2 = i32x2(20, 21); - let _x4 = i32x4(40, 41, 42, 43); - let _x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); - - let _y2 = i32x2(120, 121); - let _y4 = i32x4(140, 141, 142, 143); - let _y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); -} diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr index 216bb6c76bc9a..bcb7a65e90f05 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr +++ b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr @@ -1,5 +1,5 @@ warning: integer-to-pointer cast - --> $DIR/issue-miri-2389.rs:LL:CC + --> tests/pass/stacked-borrows/issue-miri-2389.rs:LL:CC | LL | let wildcard = &root0 as *const Cell as usize as *const Cell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast @@ -10,5 +10,5 @@ LL | let wildcard = &root0 as *const Cell as usize as *const Cell PathBuf { PathBuf::from(env::var("MIRI").unwrap_or_else(|_| env!("CARGO_BIN_EXE_miri").into())) @@ -36,20 +48,21 @@ fn build_native_lib() -> PathBuf { // Create the directory if it does not already exist. std::fs::create_dir_all(&so_target_dir) .expect("Failed to create directory for shared object file"); - let so_file_path = so_target_dir.join("native-lib.so"); + // We use a platform-neutral file extension to avoid having to hard-code alternatives. + let native_lib_path = so_target_dir.join("native-lib.module"); let cc_output = Command::new(cc) .args([ "-shared", + "-fPIC", + // We hide all symbols by default and export just the ones we need + // This is to future-proof against a more complex shared object which eg defines its own malloc + // (but we wouldn't want miri to call that, as it would if it was exported). + "-fvisibility=hidden", "-o", - so_file_path.to_str().unwrap(), + native_lib_path.to_str().unwrap(), // FIXME: Automate gathering of all relevant C source files in the directory. "tests/native-lib/scalar_arguments.c", "tests/native-lib/ptr_read_access.c", - // Only add the functions specified in libcode.version to the shared object file. - // This is to avoid automatically adding `malloc`, etc. - // Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/ - "-fPIC", - "-Wl,--version-script=tests/native-lib/native-lib.map", // Ensure we notice serious problems in the C code. "-Wall", "-Wextra", @@ -64,7 +77,7 @@ fn build_native_lib() -> PathBuf { String::from_utf8_lossy(&cc_output.stderr), ); } - so_file_path + native_lib_path } /// Does *not* set any args or env vars, since it is shared between the test runner and @@ -76,32 +89,50 @@ fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> let mut config = Config { target: Some(target.to_owned()), - stderr_filters: stderr_filters().into(), - stdout_filters: stdout_filters().into(), - mode, program, out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri_ui"), - edition: Some("2021".into()), // keep in sync with `./miri run` threads: std::env::var("MIRI_TEST_THREADS") .ok() .map(|threads| NonZero::new(threads.parse().unwrap()).unwrap()), ..Config::rustc(path) }; + config.comment_defaults.base().exit_status = match mode { + Mode::Pass => Some(0), + Mode::Fail => Some(1), + Mode::RunDep => None, + Mode::Panic => Some(101), + } + .map(Spanned::dummy) + .into(); + + config.comment_defaults.base().require_annotations = + Spanned::dummy(matches!(mode, Mode::Fail)).into(); + + config.comment_defaults.base().normalize_stderr = + stderr_filters().iter().map(|(m, p)| (m.clone(), p.to_vec())).collect(); + config.comment_defaults.base().normalize_stdout = + stdout_filters().iter().map(|(m, p)| (m.clone(), p.to_vec())).collect(); + + // keep in sync with `./miri run` + config.comment_defaults.base().add_custom("edition", Edition("2021".into())); + if with_dependencies { - // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary. - // (It's a separate crate, so we don't get an env var from cargo.) - config.dependency_builder.program = { - let mut prog = miri_path(); - prog.set_file_name(format!("cargo-miri{}", env::consts::EXE_SUFFIX)); - prog - }; - let builder_args = ["miri", "run"]; // There is no `cargo miri build` so we just use `cargo miri run`. - config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect(); - config.dependencies_crate_manifest_path = - Some(Path::new("test_dependencies").join("Cargo.toml")); - // Reset `RUSTFLAGS` to work around . - config.dependency_builder.envs.push(("RUSTFLAGS".into(), None)); + config.comment_defaults.base().set_custom("dependencies", DependencyBuilder { + program: CommandBuilder { + // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary. + // (It's a separate crate, so we don't get an env var from cargo.) + program: miri_path() + .with_file_name(format!("cargo-miri{}", env::consts::EXE_SUFFIX)), + // There is no `cargo miri build` so we just use `cargo miri run`. + args: ["miri", "run"].into_iter().map(Into::into).collect(), + // Reset `RUSTFLAGS` to work around . + envs: vec![("RUSTFLAGS".into(), None)], + ..CommandBuilder::cargo() + }, + crate_manifest_path: Path::new("test_dependencies").join("Cargo.toml"), + build_std: None, + }); } config } @@ -139,8 +170,6 @@ fn run_tests( } } config.program.args.push("-Zui-testing".into()); - config.program.args.push("--target".into()); - config.program.args.push(target.into()); // If we're testing the native-lib functionality, then build the shared object file for testing // external C function calls and push the relevant compiler flag. @@ -152,14 +181,13 @@ fn run_tests( } // Handle command-line arguments. - let args = ui_test::Args::test()?; - let default_bless = env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); - config.with_args(&args, default_bless); - if let OutputConflictHandling::Error(msg) = &mut config.output_conflict_handling { - *msg = "./miri test --bless".into(); - } + let mut args = ui_test::Args::test()?; + args.bless |= env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); + config.with_args(&args); + config.bless_command = Some("./miri test --bless".into()); + if env::var_os("MIRI_SKIP_UI_CHECKS").is_some() { - assert!(!default_bless, "cannot use RUSTC_BLESS and MIRI_SKIP_UI_CHECKS at the same time"); + assert!(!args.bless, "cannot use RUSTC_BLESS and MIRI_SKIP_UI_CHECKS at the same time"); config.output_conflict_handling = OutputConflictHandling::Ignore; } eprintln!(" Compiler: {}", config.program.display()); @@ -170,7 +198,7 @@ fn run_tests( // The files we're actually interested in (all `.rs` files). ui_test::default_file_filter, // This could be used to overwrite the `Config` on a per-test basis. - |_, _, _| {}, + |_, _| {}, ( match args.format { Format::Terse => status_emitter::Text::quiet(), @@ -286,50 +314,29 @@ fn main() -> Result<()> { ui(Mode::Pass, "tests/pass", &target, WithoutDependencies, tmpdir.path())?; ui(Mode::Pass, "tests/pass-dep", &target, WithDependencies, tmpdir.path())?; ui(Mode::Panic, "tests/panic", &target, WithDependencies, tmpdir.path())?; - ui( - Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled }, - "tests/fail", - &target, - WithoutDependencies, - tmpdir.path(), - )?; - ui( - Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled }, - "tests/fail-dep", - &target, - WithDependencies, - tmpdir.path(), - )?; - if cfg!(target_os = "linux") { + ui(Mode::Fail, "tests/fail", &target, WithoutDependencies, tmpdir.path())?; + ui(Mode::Fail, "tests/fail-dep", &target, WithDependencies, tmpdir.path())?; + if cfg!(unix) { ui(Mode::Pass, "tests/native-lib/pass", &target, WithoutDependencies, tmpdir.path())?; - ui( - Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled }, - "tests/native-lib/fail", - &target, - WithoutDependencies, - tmpdir.path(), - )?; + ui(Mode::Fail, "tests/native-lib/fail", &target, WithoutDependencies, tmpdir.path())?; } Ok(()) } -fn run_dep_mode(target: String, mut args: impl Iterator) -> Result<()> { - let path = args.next().expect("./miri run-dep must be followed by a file name"); - let mut config = miri_config( - &target, - "", - Mode::Yolo { rustfix: RustfixMode::Disabled }, - /* with dependencies */ true, - ); - config.program.args.clear(); // remove the `--error-format` that ui_test adds by default - let dep_args = config.build_dependencies()?; +fn run_dep_mode(target: String, args: impl Iterator) -> Result<()> { + let mut config = miri_config(&target, "", Mode::RunDep, /* with dependencies */ true); + config.comment_defaults.base().custom.remove("edition"); // `./miri` adds an `--edition` in `args`, so don't set it twice + config.fill_host_and_target()?; + config.program.args = args.collect(); - let mut cmd = config.program.build(&config.out_dir); - cmd.args(dep_args); + let test_config = TestConfig::one_off_runner(config.clone(), PathBuf::new()); - cmd.arg(path); + let build_manager = BuildManager::one_off(config); + let mut cmd = test_config.config.program.build(&test_config.config.out_dir); + cmd.arg("--target").arg(test_config.config.target.as_ref().unwrap()); + // Build dependencies + test_config.apply_custom(&mut cmd, &build_manager).unwrap(); - cmd.args(args); if cmd.spawn()?.wait()?.success() { Ok(()) } else { std::process::exit(1) } } diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml index addb36418d4b4..2d93777f61d3d 100644 --- a/src/tools/miri/triagebot.toml +++ b/src/tools/miri/triagebot.toml @@ -17,3 +17,15 @@ contributing_url = "https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.m [no-merges] exclude_titles = ["Rustup"] + +[review-submitted] +# This label is added when a "request changes" review is submitted. +reviewed_label = "S-waiting-on-author" +# These labels are removed when a "request changes" review is submitted. +review_labels = ["S-waiting-on-review"] + +[review-requested] +# Those labels are removed when PR author requests a review from an assignee +remove_labels = ["S-waiting-on-author"] +# Those labels are added when PR author requests a review from an assignee +add_labels = ["S-waiting-on-review"] diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 73389f930bda3..6211b5670aa69 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -6,7 +6,7 @@ use utils::io; use crate::bolt::{bolt_optimize, with_bolt_instrumented}; use crate::environment::{Environment, EnvironmentBuilder}; -use crate::exec::{cmd, Bootstrap}; +use crate::exec::{Bootstrap, cmd}; use crate::tests::run_tests; use crate::timer::Timer; use crate::training::{ diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 9dbba7a05001d..82c393d34a679 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -1,7 +1,7 @@ use anyhow::Context; use camino::{Utf8Path, Utf8PathBuf}; -use crate::environment::{executable_extension, Environment}; +use crate::environment::{Environment, executable_extension}; use crate::exec::cmd; use crate::utils::io::{copy_directory, find_file_in_dir, unpack_archive}; @@ -67,6 +67,7 @@ change-id = 115898 [build] rustc = "{rustc}" cargo = "{cargo}" +local-rebuild = true [target.{host_triple}] llvm-config = "{llvm_config}" @@ -102,13 +103,7 @@ llvm-config = "{llvm_config}" for test_path in env.skipped_tests() { args.extend(["--skip", test_path]); } - cmd(&args) - .env("COMPILETEST_FORCE_STAGE0", "1") - // Above we override the stage 0 compiler with previously compiled compiler, - // which can cause confusion in bootstrap's target sanity checks. - .env("BOOTSTRAP_SKIP_TARGET_SANITY", "1") - .run() - .context("Cannot execute tests") + cmd(&args).env("COMPILETEST_FORCE_STAGE0", "1").run().context("Cannot execute tests") } /// Tries to find the version of the dist artifacts (either nightly, beta, or 1.XY.Z). diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 97e8ec5c6edfb..30c79f9594744 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -3,8 +3,8 @@ use build_helper::{LLVM_PGO_CRATES, RUSTC_PGO_CRATES}; use camino::{Utf8Path, Utf8PathBuf}; use humansize::BINARY; -use crate::environment::{executable_extension, Environment}; -use crate::exec::{cmd, CmdBuilder}; +use crate::environment::{Environment, executable_extension}; +use crate::exec::{CmdBuilder, cmd}; use crate::utils::io::{count_files, delete_directory}; use crate::utils::with_log_group; diff --git a/src/tools/opt-dist/src/utils/artifact_size.rs b/src/tools/opt-dist/src/utils/artifact_size.rs index e51b5f06dfb38..74f7f75b9c014 100644 --- a/src/tools/opt-dist/src/utils/artifact_size.rs +++ b/src/tools/opt-dist/src/utils/artifact_size.rs @@ -11,7 +11,7 @@ use crate::utils::io::get_files_from_dir; pub fn print_binary_sizes(env: &Environment) -> anyhow::Result<()> { use std::fmt::Write; - use humansize::{format_size, BINARY}; + use humansize::{BINARY, format_size}; let root = env.build_artifacts().join("stage2"); diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index a0b96e25a0cba..6b58173b34304 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -15,7 +15,7 @@ use crate::{ /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. /// -/// # A [`Command`] must be executed +/// # A [`Command`] must be executed exactly once /// /// A [`Command`] is armed by a [`DropBomb`] on construction to enforce that it will be executed. If /// a [`Command`] is constructed but never executed, the drop bomb will explode and cause the test @@ -23,26 +23,73 @@ use crate::{ /// containing constructed but never executed commands is dangerous because it can give a false /// sense of confidence. /// +/// Each [`Command`] invocation can also only be executed once, because we want to enforce +/// `std{in,out,err}` config via [`std::process::Stdio`] but [`std::process::Stdio`] is not +/// cloneable. +/// +/// In this sense, [`Command`] exhibits linear type semantics but enforced at run-time. +/// /// [`run`]: Self::run /// [`run_fail`]: Self::run_fail /// [`run_unchecked`]: Self::run_unchecked #[derive(Debug)] pub struct Command { cmd: StdCommand, - stdin: Option>, + // Convience for providing a quick stdin buffer. + stdin_buf: Option>, + + // Configurations for child process's std{in,out,err} handles. + stdin: Option, + stdout: Option, + stderr: Option, + + // Emulate linear type semantics. drop_bomb: DropBomb, + already_executed: bool, } impl Command { #[track_caller] pub fn new>(program: P) -> Self { let program = program.as_ref(); - Self { cmd: StdCommand::new(program), stdin: None, drop_bomb: DropBomb::arm(program) } + Self { + cmd: StdCommand::new(program), + stdin_buf: None, + drop_bomb: DropBomb::arm(program), + stdin: None, + stdout: None, + stderr: None, + already_executed: false, + } } - /// Specify a stdin input - pub fn stdin>(&mut self, input: I) -> &mut Self { - self.stdin = Some(input.as_ref().to_vec().into_boxed_slice()); + /// Specify a stdin input buffer. This is a convenience helper, + pub fn stdin_buf>(&mut self, input: I) -> &mut Self { + self.stdin_buf = Some(input.as_ref().to_vec().into_boxed_slice()); + self + } + + /// Configuration for the child process’s standard input (stdin) handle. + /// + /// See [`std::process::Command::stdin`]. + pub fn stdin>(&mut self, cfg: T) -> &mut Self { + self.stdin = Some(cfg.into()); + self + } + + /// Configuration for the child process’s standard output (stdout) handle. + /// + /// See [`std::process::Command::stdout`]. + pub fn stdout>(&mut self, cfg: T) -> &mut Self { + self.stdout = Some(cfg.into()); + self + } + + /// Configuration for the child process’s standard error (stderr) handle. + /// + /// See [`std::process::Command::stderr`]. + pub fn stderr>(&mut self, cfg: T) -> &mut Self { + self.stderr = Some(cfg.into()); self } @@ -105,6 +152,8 @@ impl Command { } /// Run the constructed command and assert that it is successfully run. + /// + /// By default, std{in,out,err} are [`Stdio::piped()`]. #[track_caller] pub fn run(&mut self) -> CompletedProcess { let output = self.command_output(); @@ -115,6 +164,8 @@ impl Command { } /// Run the constructed command and assert that it does not successfully run. + /// + /// By default, std{in,out,err} are [`Stdio::piped()`]. #[track_caller] pub fn run_fail(&mut self) -> CompletedProcess { let output = self.command_output(); @@ -124,10 +175,10 @@ impl Command { output } - /// Run the command but do not check its exit status. - /// Only use if you explicitly don't care about the exit status. - /// Prefer to use [`Self::run`] and [`Self::run_fail`] - /// whenever possible. + /// Run the command but do not check its exit status. Only use if you explicitly don't care + /// about the exit status. + /// + /// Prefer to use [`Self::run`] and [`Self::run_fail`] whenever possible. #[track_caller] pub fn run_unchecked(&mut self) -> CompletedProcess { self.command_output() @@ -135,13 +186,19 @@ impl Command { #[track_caller] fn command_output(&mut self) -> CompletedProcess { + if self.already_executed { + panic!("command was already executed"); + } else { + self.already_executed = true; + } + self.drop_bomb.defuse(); // let's make sure we piped all the input and outputs - self.cmd.stdin(Stdio::piped()); - self.cmd.stdout(Stdio::piped()); - self.cmd.stderr(Stdio::piped()); + self.cmd.stdin(self.stdin.take().unwrap_or(Stdio::piped())); + self.cmd.stdout(self.stdout.take().unwrap_or(Stdio::piped())); + self.cmd.stderr(self.stderr.take().unwrap_or(Stdio::piped())); - let output = if let Some(input) = &self.stdin { + let output = if let Some(input) = &self.stdin_buf { let mut child = self.cmd.spawn().unwrap(); { diff --git a/src/tools/run-make-support/src/external_deps/cargo.rs b/src/tools/run-make-support/src/external_deps/cargo.rs new file mode 100644 index 0000000000000..e91d101cb995b --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/cargo.rs @@ -0,0 +1,8 @@ +use crate::command::Command; +use crate::env_var; + +/// Returns a command that can be used to invoke cargo. The cargo is provided by compiletest +/// through the `CARGO` env var. +pub fn cargo() -> Command { + Command::new(env_var("CARGO")) +} diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs index e9315856cd775..38a9ac923b4dc 100644 --- a/src/tools/run-make-support/src/external_deps/llvm.rs +++ b/src/tools/run-make-support/src/external_deps/llvm.rs @@ -54,6 +54,12 @@ pub fn llvm_dwarfdump() -> LlvmDwarfdump { LlvmDwarfdump::new() } +/// Construct a new `llvm-pdbutil` invocation. This assumes that `llvm-pdbutil` is available +/// at `$LLVM_BIN_DIR/llvm-pdbutil`. +pub fn llvm_pdbutil() -> LlvmPdbutil { + LlvmPdbutil::new() +} + /// A `llvm-readobj` invocation builder. #[derive(Debug)] #[must_use] @@ -110,6 +116,13 @@ pub struct LlvmDwarfdump { cmd: Command, } +/// A `llvm-pdbutil` invocation builder. +#[derive(Debug)] +#[must_use] +pub struct LlvmPdbutil { + cmd: Command, +} + crate::macros::impl_common_helpers!(LlvmReadobj); crate::macros::impl_common_helpers!(LlvmProfdata); crate::macros::impl_common_helpers!(LlvmFilecheck); @@ -118,6 +131,7 @@ crate::macros::impl_common_helpers!(LlvmAr); crate::macros::impl_common_helpers!(LlvmNm); crate::macros::impl_common_helpers!(LlvmBcanalyzer); crate::macros::impl_common_helpers!(LlvmDwarfdump); +crate::macros::impl_common_helpers!(LlvmPdbutil); /// Generate the path to the bin directory of LLVM. #[must_use] @@ -227,9 +241,10 @@ impl LlvmFilecheck { Self { cmd } } - /// Pipe a read file into standard input containing patterns that will be matched against the .patterns(path) call. - pub fn stdin>(&mut self, input: I) -> &mut Self { - self.cmd.stdin(input); + /// Provide a buffer representing standard input containing patterns that will be matched + /// against the `.patterns(path)` call. + pub fn stdin_buf>(&mut self, input: I) -> &mut Self { + self.cmd.stdin_buf(input); self } @@ -359,3 +374,19 @@ impl LlvmDwarfdump { self } } + +impl LlvmPdbutil { + /// Construct a new `llvm-pdbutil` invocation. This assumes that `llvm-pdbutil` is available + /// at `$LLVM_BIN_DIR/llvm-pdbutil`. + pub fn new() -> Self { + let llvm_pdbutil = llvm_bin_dir().join("llvm-pdbutil"); + let cmd = Command::new(llvm_pdbutil); + Self { cmd } + } + + /// Provide an input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } +} diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs index f7c84724d0e07..80c34a9070fcc 100644 --- a/src/tools/run-make-support/src/external_deps/mod.rs +++ b/src/tools/run-make-support/src/external_deps/mod.rs @@ -2,6 +2,7 @@ //! such as `cc` or `python`. pub mod c_build; +pub mod cargo; pub mod cc; pub mod clang; pub mod htmldocck; diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index cece58d29566c..35d983dc607fd 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -36,10 +36,13 @@ pub struct Rustc { crate::macros::impl_common_helpers!(Rustc); +pub fn rustc_path() -> String { + env_var("RUSTC") +} + #[track_caller] fn setup_common() -> Command { - let rustc = env_var("RUSTC"); - let mut cmd = Command::new(rustc); + let mut cmd = Command::new(rustc_path()); set_host_rpath(&mut cmd); cmd } @@ -291,9 +294,9 @@ impl Rustc { self } - /// Specify a stdin input - pub fn stdin>(&mut self, input: I) -> &mut Self { - self.cmd.stdin(input); + /// Specify a stdin input buffer. + pub fn stdin_buf>(&mut self, input: I) -> &mut Self { + self.cmd.stdin_buf(input); self } diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs index 96b1c719e2e3e..df5e5d8a2e84a 100644 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs @@ -85,9 +85,9 @@ impl Rustdoc { self } - /// Specify a stdin input - pub fn stdin>(&mut self, input: I) -> &mut Self { - self.cmd.stdin(input); + /// Specify a stdin input buffer. + pub fn stdin_buf>(&mut self, input: I) -> &mut Self { + self.cmd.stdin_buf(input); self } diff --git a/src/tools/run-make-support/src/fs.rs b/src/tools/run-make-support/src/fs.rs index 2c35ba52a629c..2ca55ad3b3af6 100644 --- a/src/tools/run-make-support/src/fs.rs +++ b/src/tools/run-make-support/src/fs.rs @@ -1,42 +1,6 @@ use std::io; use std::path::{Path, PathBuf}; -// FIXME(jieyouxu): modify create_symlink to panic on windows. - -/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. -#[cfg(target_family = "windows")] -pub fn create_symlink, Q: AsRef>(original: P, link: Q) { - if link.as_ref().exists() { - std::fs::remove_dir(link.as_ref()).unwrap(); - } - if original.as_ref().is_file() { - std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); - } else { - std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); - } -} - -/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. -#[cfg(target_family = "unix")] -pub fn create_symlink, Q: AsRef>(original: P, link: Q) { - if link.as_ref().exists() { - std::fs::remove_dir(link.as_ref()).unwrap(); - } - std::os::unix::fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); -} - /// Copy a directory into another. pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { fn copy_dir_all_inner(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { @@ -50,7 +14,31 @@ pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { if ty.is_dir() { copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?; } else if ty.is_symlink() { - copy_symlink(entry.path(), dst.join(entry.file_name()))?; + // Traverse symlink once to find path of target entity. + let target_path = std::fs::read_link(entry.path())?; + + let new_symlink_path = dst.join(entry.file_name()); + #[cfg(windows)] + { + use std::os::windows::fs::FileTypeExt; + if ty.is_symlink_dir() { + std::os::windows::fs::symlink_dir(&target_path, new_symlink_path)?; + } else { + // Target may be a file or another symlink, in any case we can use + // `symlink_file` here. + std::os::windows::fs::symlink_file(&target_path, new_symlink_path)?; + } + } + #[cfg(unix)] + { + std::os::unix::fs::symlink(target_path, new_symlink_path)?; + } + #[cfg(not(any(windows, unix)))] + { + // Technically there's also wasi, but I have no clue about wasi symlink + // semantics and which wasi targets / environment support symlinks. + unimplemented!("unsupported target"); + } } else { std::fs::copy(entry.path(), dst.join(entry.file_name()))?; } @@ -69,12 +57,6 @@ pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { } } -fn copy_symlink, Q: AsRef>(from: P, to: Q) -> io::Result<()> { - let target_path = std::fs::read_link(from).unwrap(); - create_symlink(target_path, to); - Ok(()) -} - /// Helper for reading entries in a given directory. pub fn read_dir_entries, F: FnMut(&Path)>(dir: P, mut callback: F) { for entry in read_dir(dir) { @@ -85,8 +67,17 @@ pub fn read_dir_entries, F: FnMut(&Path)>(dir: P, mut callback: F /// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message. #[track_caller] pub fn remove_file>(path: P) { - std::fs::remove_file(path.as_ref()) - .expect(&format!("the file in path \"{}\" could not be removed", path.as_ref().display())); + if let Err(e) = std::fs::remove_file(path.as_ref()) { + panic!("failed to remove file at `{}`: {e}", path.as_ref().display()); + } +} + +/// A wrapper around [`std::fs::remove_dir`] which includes the directory path in the panic message. +#[track_caller] +pub fn remove_dir>(path: P) { + if let Err(e) = std::fs::remove_dir(path.as_ref()) { + panic!("failed to remove directory at `{}`: {e}", path.as_ref().display()); + } } /// A wrapper around [`std::fs::copy`] which includes the file path in the panic message. @@ -165,13 +156,32 @@ pub fn create_dir_all>(path: P) { )); } -/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message. +/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message. Note +/// that this will traverse symlinks and will return metadata about the target file. Use +/// [`symlink_metadata`] if you don't want to traverse symlinks. +/// +/// See [`std::fs::metadata`] docs for more details. #[track_caller] pub fn metadata>(path: P) -> std::fs::Metadata { - std::fs::metadata(path.as_ref()).expect(&format!( - "the file's metadata in path \"{}\" could not be read", - path.as_ref().display() - )) + match std::fs::metadata(path.as_ref()) { + Ok(m) => m, + Err(e) => panic!("failed to read file metadata at `{}`: {e}", path.as_ref().display()), + } +} + +/// A wrapper around [`std::fs::symlink_metadata`] which includes the file path in the panic +/// message. Note that this will not traverse symlinks and will return metadata about the filesystem +/// entity itself. Use [`metadata`] if you want to traverse symlinks. +/// +/// See [`std::fs::symlink_metadata`] docs for more details. +#[track_caller] +pub fn symlink_metadata>(path: P) -> std::fs::Metadata { + match std::fs::symlink_metadata(path.as_ref()) { + Ok(m) => m, + Err(e) => { + panic!("failed to read file metadata (shallow) at `{}`: {e}", path.as_ref().display()) + } + } } /// A wrapper around [`std::fs::rename`] which includes the file path in the panic message. @@ -205,3 +215,73 @@ pub fn shallow_find_dir_entries>(dir: P) -> Vec { } output } + +/// Create a new symbolic link to a directory. +/// +/// # Removing the symlink +/// +/// - On Windows, a symlink-to-directory needs to be removed with a corresponding [`fs::remove_dir`] +/// and not [`fs::remove_file`]. +/// - On Unix, remove the symlink with [`fs::remove_file`]. +/// +/// [`fs::remove_dir`]: crate::fs::remove_dir +/// [`fs::remove_file`]: crate::fs::remove_file +pub fn symlink_dir, Q: AsRef>(original: P, link: Q) { + #[cfg(unix)] + { + if let Err(e) = std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) { + panic!( + "failed to create symlink: original=`{}`, link=`{}`: {e}", + original.as_ref().display(), + link.as_ref().display() + ); + } + } + #[cfg(windows)] + { + if let Err(e) = std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()) { + panic!( + "failed to create symlink-to-directory: original=`{}`, link=`{}`: {e}", + original.as_ref().display(), + link.as_ref().display() + ); + } + } + #[cfg(not(any(windows, unix)))] + { + unimplemented!("target family not currently supported") + } +} + +/// Create a new symbolic link to a file. +/// +/// # Removing the symlink +/// +/// On both Windows and Unix, a symlink-to-file needs to be removed with a corresponding +/// [`fs::remove_file`](crate::fs::remove_file) and not [`fs::remove_dir`](crate::fs::remove_dir). +pub fn symlink_file, Q: AsRef>(original: P, link: Q) { + #[cfg(unix)] + { + if let Err(e) = std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) { + panic!( + "failed to create symlink: original=`{}`, link=`{}`: {e}", + original.as_ref().display(), + link.as_ref().display() + ); + } + } + #[cfg(windows)] + { + if let Err(e) = std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()) { + panic!( + "failed to create symlink-to-file: original=`{}`, link=`{}`: {e}", + original.as_ref().display(), + link.as_ref().display() + ); + } + } + #[cfg(not(any(windows, unix)))] + { + unimplemented!("target family not currently supported") + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 989d00d4c2f97..15d813ccf5300 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -34,6 +34,7 @@ pub mod rfs { } // Re-exports of third-party library crates. +// tidy-alphabetical-start pub use bstr; pub use gimli; pub use libc; @@ -41,6 +42,7 @@ pub use object; pub use regex; pub use serde_json; pub use wasmparser; +// tidy-alphabetical-end // Re-exports of external dependencies. pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc}; @@ -48,6 +50,7 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust // These rely on external dependencies. pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc}; pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx}; +pub use cargo::cargo; pub use clang::{clang, Clang}; pub use htmldocck::htmldocck; pub use llvm::{ @@ -56,7 +59,7 @@ pub use llvm::{ LlvmProfdata, LlvmReadobj, }; pub use python::python_command; -pub use rustc::{aux_build, bare_rustc, rustc, Rustc}; +pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; /// [`diff`][mod@diff] is implemented in terms of the [similar] library. @@ -71,7 +74,7 @@ pub use env::{env_var, env_var_os, set_current_dir}; pub use run::{cmd, run, run_fail, run_with_args}; /// Helpers for checking target information. -pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname}; +pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os}; /// Helpers for building names of output artifacts that are potentially target-specific. pub use artifact_names::{ @@ -96,3 +99,4 @@ pub use assertion_helpers::{ pub use string::{ count_regex_matches_in_files_with_extension, invalid_utf8_contains, invalid_utf8_not_contains, }; +use crate::external_deps::cargo; diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index 5dcb0b83430f9..896abb73fc108 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -28,6 +28,24 @@ pub fn is_darwin() -> bool { target().contains("darwin") } +/// Get the target OS on Apple operating systems. +#[must_use] +pub fn apple_os() -> &'static str { + if target().contains("darwin") { + "macos" + } else if target().contains("ios") { + "ios" + } else if target().contains("tvos") { + "tvos" + } else if target().contains("watchos") { + "watchos" + } else if target().contains("visionos") { + "visionos" + } else { + panic!("not an Apple OS") + } +} + /// Check if `component` is within `LLVM_COMPONENTS` #[must_use] pub fn llvm_components_contain(component: &str) -> bool { diff --git a/src/tools/rust-analyzer/.typos.toml b/src/tools/rust-analyzer/.typos.toml index e7e764ce03517..febfb233bd979 100644 --- a/src/tools/rust-analyzer/.typos.toml +++ b/src/tools/rust-analyzer/.typos.toml @@ -15,6 +15,7 @@ extend-ignore-re = [ '"flate2"', "raison d'être", "inout", + "INOUT", "optin" ] diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 4e9319f13aa83..dc820fcb28d20 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -96,6 +96,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "cfg_aliases 0.2.1", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -167,6 +176,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chalk-derive" version = "0.98.0" @@ -982,7 +997,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lsp-server" -version = "0.7.6" +version = "0.7.7" dependencies = [ "crossbeam-channel", "ctrlc", @@ -994,9 +1009,9 @@ dependencies = [ [[package]] name = "lsp-server" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248f65b78f6db5d8e1b1604b4098a28b43d21a8eb1deeca22b1c421b276c7095" +checksum = "550446e84739dcaf6d48a4a093973850669e13e8a34d8f8d64851041be267cd9" dependencies = [ "crossbeam-channel", "log", @@ -1029,8 +1044,10 @@ version = "0.0.0" dependencies = [ "arrayvec", "cov-mark", + "expect-test", "intern", "parser", + "ra-ap-rustc_lexer", "rustc-hash", "smallvec", "span", @@ -1113,7 +1130,7 @@ checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.6.0", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", "libc", ] @@ -1468,9 +1485,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.63.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011c39d409940a890414e3a7b239762ac16d88029ad71b050a8374831b93790" +checksum = "2a8cb51bb4534ac3e9c74f1d9bd90e607e60f94f734b1cf1a66f753ad2af6ed7" dependencies = [ "bitflags 2.6.0", "ra-ap-rustc_index", @@ -1479,9 +1496,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index" -version = "0.63.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9027acdee649b0b27eb10b7db5be833efee3362d394935c5eed8f0745a9d43ce" +checksum = "8b640fba2b7ef4f875459e2e76daeb846ef341d1d376fa758962ac0eba79bce6" dependencies = [ "arrayvec", "ra-ap-rustc_index_macros", @@ -1490,9 +1507,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.63.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "540b86dc0384141ac8e825fc2874cd44bffd4277d99d8ec63ee416f1a98d5997" +checksum = "faef502419ba5ac9d3079b1a835c6e5b4e605388254bbe55eb5683936f541be9" dependencies = [ "proc-macro2", "quote", @@ -1501,9 +1518,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.63.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdf98bb457b47b9ae4aeebf867d0ca440c86925e0b6381658c4a02589748c9d" +checksum = "5da7f9d533b8d5be6704558da741ff20b982ad4647b1e9e08632853e4fecf9d5" dependencies = [ "unicode-properties", "unicode-xid", @@ -1511,9 +1528,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.63.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fe3556ab6311bb775220563a300e2bf62ec56404521fe0c511a583937683d5" +checksum = "94389cf81c651b1bda9ac45d3de6a2d851bb6fd4cb893875daa44e419c94205f" dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_lexer", @@ -1521,9 +1538,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.63.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1709080fdeb5db630e1c2644026c2962aaa32416cd92f0190c04b0c21e114b91" +checksum = "3679d8dd0114ed6000918309f843782738e51c99d8e4baec0d0f706e4d948819" dependencies = [ "ra-ap-rustc_index", "rustc-hash", @@ -1636,7 +1653,7 @@ dependencies = [ "intern", "itertools", "load-cargo", - "lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lsp-server 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types", "memchr", "mimalloc", @@ -1843,10 +1860,11 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smol_str" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +checksum = "66eaf762c5af19db3108300515c8aa7a50efc90ff745f4c62288052ebf9fdd25" dependencies = [ + "borsh", "serde", ] @@ -2607,6 +2625,7 @@ version = "0.1.0" dependencies = [ "anyhow", "directories", + "either", "flate2", "itertools", "proc-macro2", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index aa7bd2dc5fe8b..b4587a3796181 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -85,11 +85,11 @@ tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.63.0", default-features = false } -ra-ap-rustc_parse_format = { version = "0.63.0", default-features = false } -ra-ap-rustc_index = { version = "0.63.0", default-features = false } -ra-ap-rustc_abi = { version = "0.63.0", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.63.0", default-features = false } +ra-ap-rustc_lexer = { version = "0.68.0", default-features = false } +ra-ap-rustc_parse_format = { version = "0.68.0", default-features = false } +ra-ap-rustc_index = { version = "0.68.0", default-features = false } +ra-ap-rustc_abi = { version = "0.68.0", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.68.0", default-features = false } # local crates that aren't published to crates.io. These should not have versions. test-fixture = { path = "./crates/test-fixture" } @@ -145,7 +145,7 @@ smallvec = { version = "1.10.0", features = [ "union", "const_generics", ] } -smol_str = "0.2.1" +smol_str = "0.3.1" snap = "1.1.0" text-size = "1.1.1" tracing = "0.1.40" @@ -185,6 +185,7 @@ style = { level = "warn", priority = -1 } suspicious = { level = "warn", priority = -1 } ## allow following lints +too_long_first_doc_paragraph = "allow" # subjective single_match = "allow" # () makes a fine error in most cases diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs index a9d91d64ceb6d..4fb6654b612f7 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/change.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs @@ -3,11 +3,15 @@ use std::fmt; +use rustc_hash::FxHashMap; use salsa::Durability; use triomphe::Arc; use vfs::FileId; -use crate::{CrateGraph, SourceDatabaseFileInputExt, SourceRoot, SourceRootDatabase, SourceRootId}; +use crate::{ + CrateGraph, CrateId, CrateWorkspaceData, SourceDatabaseFileInputExt, SourceRoot, + SourceRootDatabase, SourceRootId, +}; /// Encapsulate a bunch of raw `.set` calls on the database. #[derive(Default)] @@ -15,6 +19,7 @@ pub struct FileChange { pub roots: Option>, pub files_changed: Vec<(FileId, Option)>, pub crate_graph: Option, + pub ws_data: Option>>, } impl fmt::Debug for FileChange { @@ -50,6 +55,10 @@ impl FileChange { self.crate_graph = Some(graph); } + pub fn set_ws_data(&mut self, data: FxHashMap>) { + self.ws_data = Some(data); + } + pub fn apply(self, db: &mut dyn SourceRootDatabase) { let _p = tracing::info_span!("FileChange::apply").entered(); if let Some(roots) = self.roots { @@ -74,6 +83,9 @@ impl FileChange { if let Some(crate_graph) = self.crate_graph { db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH); } + if let Some(data) = self.ws_data { + db.set_crate_workspace_data_with_durability(Arc::new(data), Durability::HIGH); + } } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 3616fa9fd8684..f5109339ad10d 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -374,37 +374,6 @@ impl CrateGraph { self.arena.alloc(data) } - /// Remove the crate from crate graph. If any crates depend on this crate, the dependency would be replaced - /// with the second input. - pub fn remove_and_replace( - &mut self, - id: CrateId, - replace_with: CrateId, - ) -> Result<(), CyclicDependenciesError> { - for (x, data) in self.arena.iter() { - if x == id { - continue; - } - for edge in &data.dependencies { - if edge.crate_id == id { - self.check_cycle_after_dependency(edge.crate_id, replace_with)?; - } - } - } - // if everything was ok, start to replace - for (x, data) in self.arena.iter_mut() { - if x == id { - continue; - } - for edge in &mut data.dependencies { - if edge.crate_id == id { - edge.crate_id = replace_with; - } - } - } - Ok(()) - } - pub fn add_dep( &mut self, from: CrateId, @@ -412,26 +381,17 @@ impl CrateGraph { ) -> Result<(), CyclicDependenciesError> { let _p = tracing::info_span!("add_dep").entered(); - self.check_cycle_after_dependency(from, dep.crate_id)?; - - self.arena[from].add_dep(dep); - Ok(()) - } - - /// Check if adding a dep from `from` to `to` creates a cycle. To figure - /// that out, look for a path in the *opposite* direction, from `to` to - /// `from`. - fn check_cycle_after_dependency( - &self, - from: CrateId, - to: CrateId, - ) -> Result<(), CyclicDependenciesError> { - if let Some(path) = self.find_path(&mut FxHashSet::default(), to, from) { + // Check if adding a dep from `from` to `to` creates a cycle. To figure + // that out, look for a path in the *opposite* direction, from `to` to + // `from`. + if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) { let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect(); let err = CyclicDependenciesError { path }; - assert!(err.from().0 == from && err.to().0 == to); + assert!(err.from().0 == from && err.to().0 == dep.crate_id); return Err(err); } + + self.arena[from].add_dep(dep); Ok(()) } @@ -531,22 +491,15 @@ impl CrateGraph { .for_each(|(_, data)| data.dependencies.sort_by_key(|dep| dep.crate_id)); } - /// Extends this crate graph by adding a complete disjoint second crate + /// Extends this crate graph by adding a complete second crate /// graph and adjust the ids in the [`ProcMacroPaths`] accordingly. /// - /// This will deduplicate the crates of the graph where possible. - /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id. - /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also - /// have the crate dependencies sorted. - /// - /// Returns a mapping from `other`'s crate ids to the new crate ids in `self`. + /// Returns a map mapping `other`'s IDs to the new IDs in `self`. pub fn extend( &mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths, - merge: impl Fn((CrateId, &mut CrateData), (CrateId, &CrateData)) -> bool, ) -> FxHashMap { - let m = self.len(); let topo = other.crates_in_topological_order(); let mut id_map: FxHashMap = FxHashMap::default(); for topo in topo { @@ -554,20 +507,13 @@ impl CrateGraph { crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); crate_data.dependencies.sort_by_key(|dep| dep.crate_id); - let res = self - .arena - .iter_mut() - .take(m) - .find_map(|(id, data)| merge((id, data), (topo, crate_data)).then_some(id)); - - let new_id = - if let Some(res) = res { res } else { self.arena.alloc(crate_data.clone()) }; + + let new_id = self.arena.alloc(crate_data.clone()); id_map.insert(topo, new_id); } *proc_macros = mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect(); - id_map } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 20ef45d0b3729..46e258d46f5c5 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -5,11 +5,12 @@ mod input; use std::panic; +use rustc_hash::FxHashMap; use salsa::Durability; use span::EditionedFileId; use syntax::{ast, Parse, SourceFile, SyntaxError}; use triomphe::Arc; -use vfs::FileId; +use vfs::{AbsPathBuf, FileId}; pub use crate::{ change::FileChange, @@ -74,19 +75,30 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug { #[salsa::input] fn crate_graph(&self) -> Arc; - // FIXME: Consider removing this, making HirDatabase::target_data_layout an input query - #[salsa::input] - fn data_layout(&self, krate: CrateId) -> TargetLayoutLoadResult; - #[salsa::input] - fn toolchain(&self, krate: CrateId) -> Option; + fn crate_workspace_data(&self) -> Arc>>; #[salsa::transparent] fn toolchain_channel(&self, krate: CrateId) -> Option; } +/// Crate related data shared by the whole workspace. +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub struct CrateWorkspaceData { + /// The working directory to run proc-macros in. This is usually the workspace root of cargo workspaces. + pub proc_macro_cwd: Option, + // FIXME: Consider removing this, making HirDatabase::target_data_layout an input query + pub data_layout: TargetLayoutLoadResult, + /// Toolchain version used to compile the crate. + pub toolchain: Option, +} + fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option { - db.toolchain(krate).as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre)) + db.crate_workspace_data() + .get(&krate)? + .toolchain + .as_ref() + .and_then(|v| ReleaseChannel::from_str(&v.pre)) } fn parse(db: &dyn SourceDatabase, file_id: EditionedFileId) -> Parse { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index dde1f142ab0c1..9535b5aea7c73 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -100,7 +100,14 @@ pub struct BodySourceMap { field_map_back: FxHashMap, pat_field_map_back: FxHashMap, - format_args_template_map: FxHashMap>, + template_map: Option< + Box<( + // format_args! + FxHashMap>, + // asm! + FxHashMap>>, + )>, + >, expansions: FxHashMap>, MacroFileId>, @@ -220,6 +227,17 @@ impl Body { pretty::print_expr_hir(db, self, owner, expr, edition) } + pub fn pretty_print_pat( + &self, + db: &dyn DefDatabase, + owner: DefWithBodyId, + pat: PatId, + oneline: bool, + edition: Edition, + ) -> String { + pretty::print_pat_hir(db, self, owner, pat, oneline, edition) + } + fn new( db: &dyn DefDatabase, owner: DefWithBodyId, @@ -426,7 +444,16 @@ impl BodySourceMap { node: InFile<&ast::FormatArgsExpr>, ) -> Option<&[(syntax::TextRange, Name)]> { let src = node.map(AstPtr::new).map(AstPtr::upcast::); - self.format_args_template_map.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref) + self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref) + } + + pub fn asm_template_args( + &self, + node: InFile<&ast::AsmExpr>, + ) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> { + let src = node.map(AstPtr::new).map(AstPtr::upcast::); + let expr = self.expr_map.get(&src)?; + Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref)) } /// Get a reference to the body source map's diagnostics. @@ -446,11 +473,14 @@ impl BodySourceMap { field_map_back, pat_field_map_back, expansions, - format_args_template_map, + template_map, diagnostics, binding_definitions, } = self; - format_args_template_map.shrink_to_fit(); + if let Some(template_map) = template_map { + template_map.0.shrink_to_fit(); + template_map.1.shrink_to_fit(); + } expr_map.shrink_to_fit(); expr_map_back.shrink_to_fit(); pat_map.shrink_to_fit(); @@ -463,4 +493,13 @@ impl BodySourceMap { diagnostics.shrink_to_fit(); binding_definitions.shrink_to_fit(); } + + pub fn template_map( + &self, + ) -> Option<&( + FxHashMap, Vec<(tt::TextRange, Name)>>, + FxHashMap, Vec>>, + )> { + self.template_map.as_deref() + } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index abf7895829206..9c547574ecb1f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -1,6 +1,8 @@ //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` //! representation. +mod asm; + use std::mem; use base_db::CrateId; @@ -35,8 +37,8 @@ use crate::{ FormatPlaceholder, FormatSign, FormatTrait, }, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind, - Expr, ExprId, InlineAsm, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, - OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement, + Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, OffsetOf, Pat, + PatId, RecordFieldPat, RecordLitField, Statement, }, item_scope::BuiltinShadowMode, lang_item::LangItem, @@ -693,10 +695,7 @@ impl ExprCollector<'_> { } } ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr), - ast::Expr::AsmExpr(e) => { - let e = self.collect_expr_opt(e.expr()); - self.alloc_expr(Expr::InlineAsm(InlineAsm { e }), syntax_ptr) - } + ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr), ast::Expr::OffsetOfExpr(e) => { let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty())); let fields = e.fields().map(|it| it.as_name()).collect(); @@ -737,7 +736,7 @@ impl ExprCollector<'_> { /// `try { ; }` into `': { ; ::std::ops::Try::from_output(()) }` /// and save the `` to use it as a break target for desugaring of the `?` operator. fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId { - let Some(try_from_output) = LangItem::TryTraitFromOutput.path(self.db, self.krate) else { + let Some(try_from_output) = self.lang_path(LangItem::TryTraitFromOutput) else { return self.collect_block(e); }; let label = self @@ -840,10 +839,10 @@ impl ExprCollector<'_> { fn collect_for_loop(&mut self, syntax_ptr: AstPtr, e: ast::ForExpr) -> ExprId { let Some((into_iter_fn, iter_next_fn, option_some, option_none)) = (|| { Some(( - LangItem::IntoIterIntoIter.path(self.db, self.krate)?, - LangItem::IteratorNext.path(self.db, self.krate)?, - LangItem::OptionSome.path(self.db, self.krate)?, - LangItem::OptionNone.path(self.db, self.krate)?, + self.lang_path(LangItem::IntoIterIntoIter)?, + self.lang_path(LangItem::IteratorNext)?, + self.lang_path(LangItem::OptionSome)?, + self.lang_path(LangItem::OptionNone)?, )) })() else { // Some of the needed lang items are missing, so we can't desugar @@ -896,6 +895,15 @@ impl ExprCollector<'_> { Expr::Match { expr: iter_next_expr, arms: Box::new([none_arm, some_arm]) }, syntax_ptr, ); + let loop_inner = self.alloc_expr( + Expr::Block { + id: None, + statements: Box::default(), + tail: Some(loop_inner), + label: None, + }, + syntax_ptr, + ); let loop_outer = self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr); let iter_binding = self.alloc_binding(iter_name, BindingAnnotation::Mutable); let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None }); @@ -923,10 +931,10 @@ impl ExprCollector<'_> { fn collect_try_operator(&mut self, syntax_ptr: AstPtr, e: ast::TryExpr) -> ExprId { let Some((try_branch, cf_continue, cf_break, try_from_residual)) = (|| { Some(( - LangItem::TryTraitBranch.path(self.db, self.krate)?, - LangItem::ControlFlowContinue.path(self.db, self.krate)?, - LangItem::ControlFlowBreak.path(self.db, self.krate)?, - LangItem::TryTraitFromResidual.path(self.db, self.krate)?, + self.lang_path(LangItem::TryTraitBranch)?, + self.lang_path(LangItem::ControlFlowContinue)?, + self.lang_path(LangItem::ControlFlowBreak)?, + self.lang_path(LangItem::TryTraitFromResidual)?, )) })() else { // Some of the needed lang items are missing, so we can't desugar @@ -1839,7 +1847,7 @@ impl ExprCollector<'_> { }, syntax_ptr, ); - self.source_map.format_args_template_map.insert(idx, mappings); + self.source_map.template_map.get_or_insert_with(Default::default).0.insert(idx, mappings); idx } @@ -2052,7 +2060,12 @@ impl ExprCollector<'_> { is_assignee_expr: false, }) } + // endregion: format + + fn lang_path(&self, lang: LangItem) -> Option { + lang.path(self.db, self.krate) + } } fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs new file mode 100644 index 0000000000000..4213370ac195a --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs @@ -0,0 +1,276 @@ +//! Lowering of inline assembly. +use hir_expand::name::Name; +use intern::Symbol; +use rustc_hash::{FxHashMap, FxHashSet}; +use syntax::{ + ast::{self, HasName, IsString}, + AstNode, AstPtr, AstToken, T, +}; +use tt::{TextRange, TextSize}; + +use crate::{ + body::lower::{ExprCollector, FxIndexSet}, + hir::{AsmOperand, AsmOptions, Expr, ExprId, InlineAsm, InlineAsmRegOrRegClass}, +}; + +impl ExprCollector<'_> { + pub(super) fn lower_inline_asm( + &mut self, + asm: ast::AsmExpr, + syntax_ptr: AstPtr, + ) -> ExprId { + let mut clobber_abis = FxIndexSet::default(); + let mut operands = vec![]; + let mut options = AsmOptions::empty(); + + let mut named_pos: FxHashMap = Default::default(); + let mut named_args: FxHashMap = Default::default(); + let mut reg_args: FxHashSet = Default::default(); + for piece in asm.asm_pieces() { + let slot = operands.len(); + let mut lower_reg = |reg: Option| { + let reg = reg?; + if let Some(string) = reg.string_token() { + reg_args.insert(slot); + Some(InlineAsmRegOrRegClass::Reg(Symbol::intern(string.text()))) + } else { + reg.name_ref().map(|name_ref| { + InlineAsmRegOrRegClass::RegClass(Symbol::intern(&name_ref.text())) + }) + } + }; + + let op = match piece { + ast::AsmPiece::AsmClobberAbi(clobber_abi) => { + if let Some(abi_name) = clobber_abi.string_token() { + clobber_abis.insert(Symbol::intern(abi_name.text())); + } + continue; + } + ast::AsmPiece::AsmOptions(opt) => { + opt.asm_options().for_each(|opt| { + options |= match opt.syntax().first_token().map_or(T![$], |it| it.kind()) { + T![att_syntax] => AsmOptions::ATT_SYNTAX, + T![may_unwind] => AsmOptions::MAY_UNWIND, + T![nomem] => AsmOptions::NOMEM, + T![noreturn] => AsmOptions::NORETURN, + T![nostack] => AsmOptions::NOSTACK, + T![preserves_flags] => AsmOptions::PRESERVES_FLAGS, + T![pure] => AsmOptions::PURE, + T![raw] => AsmOptions::RAW, + T![readonly] => AsmOptions::READONLY, + _ => return, + } + }); + continue; + } + ast::AsmPiece::AsmOperandNamed(op) => { + let name = op.name().map(|name| Symbol::intern(&name.text())); + if let Some(name) = &name { + named_args.insert(name.clone(), slot); + named_pos.insert(slot, name.clone()); + } + let Some(op) = op.asm_operand() else { continue }; + ( + name.map(Name::new_symbol_root), + match op { + ast::AsmOperand::AsmRegOperand(op) => { + let Some(dir_spec) = op.asm_dir_spec() else { + continue; + }; + let Some(reg) = lower_reg(op.asm_reg_spec()) else { + continue; + }; + if dir_spec.in_token().is_some() { + let expr = self.collect_expr_opt( + op.asm_operand_expr().and_then(|it| it.in_expr()), + ); + AsmOperand::In { reg, expr } + } else if dir_spec.out_token().is_some() { + let expr = op + .asm_operand_expr() + .and_then(|it| it.in_expr()) + .filter(|it| !matches!(it, ast::Expr::UnderscoreExpr(_))) + .map(|expr| self.collect_expr(expr)); + AsmOperand::Out { reg, expr, late: false } + } else if dir_spec.lateout_token().is_some() { + let expr = op + .asm_operand_expr() + .and_then(|it| it.in_expr()) + .filter(|it| !matches!(it, ast::Expr::UnderscoreExpr(_))) + .map(|expr| self.collect_expr(expr)); + + AsmOperand::Out { reg, expr, late: true } + } else if dir_spec.inout_token().is_some() { + let Some(op_expr) = op.asm_operand_expr() else { continue }; + let in_expr = self.collect_expr_opt(op_expr.in_expr()); + match op_expr.fat_arrow_token().is_some() { + true => { + let out_expr = op_expr + .out_expr() + .filter(|it| { + !matches!(it, ast::Expr::UnderscoreExpr(_)) + }) + .map(|expr| self.collect_expr(expr)); + + AsmOperand::SplitInOut { + reg, + in_expr, + out_expr, + late: false, + } + } + false => { + AsmOperand::InOut { reg, expr: in_expr, late: false } + } + } + } else if dir_spec.inlateout_token().is_some() { + let Some(op_expr) = op.asm_operand_expr() else { continue }; + let in_expr = self.collect_expr_opt(op_expr.in_expr()); + match op_expr.fat_arrow_token().is_some() { + true => { + let out_expr = op_expr + .out_expr() + .filter(|it| { + !matches!(it, ast::Expr::UnderscoreExpr(_)) + }) + .map(|expr| self.collect_expr(expr)); + + AsmOperand::SplitInOut { + reg, + in_expr, + out_expr, + late: true, + } + } + false => { + AsmOperand::InOut { reg, expr: in_expr, late: true } + } + } + } else { + continue; + } + } + ast::AsmOperand::AsmLabel(l) => { + AsmOperand::Label(self.collect_block_opt(l.block_expr())) + } + ast::AsmOperand::AsmConst(c) => { + AsmOperand::Const(self.collect_expr_opt(c.expr())) + } + ast::AsmOperand::AsmSym(s) => { + let Some(path) = + s.path().and_then(|p| self.expander.parse_path(self.db, p)) + else { + continue; + }; + AsmOperand::Sym(path) + } + }, + ) + } + }; + operands.push(op); + } + + let mut mappings = vec![]; + let mut curarg = 0; + if !options.contains(AsmOptions::RAW) { + // Don't treat raw asm as a format string. + asm.template() + .enumerate() + .filter_map(|(idx, it)| Some((idx, it.clone(), self.expand_macros_to_string(it)?))) + .for_each(|(idx, expr, (s, is_direct_literal))| { + mappings.resize_with(idx + 1, Vec::default); + let Ok(text) = s.value() else { + return; + }; + let mappings = &mut mappings[idx]; + let template_snippet = match expr { + ast::Expr::Literal(literal) => match literal.kind() { + ast::LiteralKind::String(s) => Some(s.text().to_owned()), + _ => None, + }, + _ => None, + }; + let str_style = match s.quote_offsets() { + Some(offsets) => { + let raw = usize::from(offsets.quotes.0.len()) - 1; + // subtract 1 for the `r` prefix + (raw != 0).then(|| raw - 1) + } + None => None, + }; + + let mut parser = rustc_parse_format::Parser::new( + &text, + str_style, + template_snippet, + false, + rustc_parse_format::ParseMode::InlineAsm, + ); + parser.curarg = curarg; + + let mut unverified_pieces = Vec::new(); + while let Some(piece) = parser.next() { + if !parser.errors.is_empty() { + break; + } else { + unverified_pieces.push(piece); + } + } + + curarg = parser.curarg; + + let to_span = |inner_span: rustc_parse_format::InnerSpan| { + is_direct_literal.then(|| { + TextRange::new( + inner_span.start.try_into().unwrap(), + inner_span.end.try_into().unwrap(), + ) - TextSize::from(str_style.map(|it| it + 1).unwrap_or(0) as u32 + 1) + }) + }; + for piece in unverified_pieces { + match piece { + rustc_parse_format::Piece::String(_) => {} + rustc_parse_format::Piece::NextArgument(arg) => { + // let span = arg_spans.next(); + + let (operand_idx, _name) = match arg.position { + rustc_parse_format::ArgumentIs(idx) + | rustc_parse_format::ArgumentImplicitlyIs(idx) => { + if idx >= operands.len() + || named_pos.contains_key(&idx) + || reg_args.contains(&idx) + { + (None, None) + } else { + (Some(idx), None) + } + } + rustc_parse_format::ArgumentNamed(name) => { + let name = Symbol::intern(name); + ( + named_args.get(&name).copied(), + Some(Name::new_symbol_root(name)), + ) + } + }; + + if let Some(operand_idx) = operand_idx { + if let Some(position_span) = to_span(arg.position_span) { + mappings.push((position_span, operand_idx)); + } + } + } + } + } + }) + }; + let idx = self.alloc_expr( + Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options }), + syntax_ptr, + ); + self.source_map.template_map.get_or_insert_with(Default::default).1.insert(idx, mappings); + idx + } +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index 55740a68acd6e..37167fcb8155b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -16,6 +16,13 @@ use crate::{ use super::*; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(super) enum LineFormat { + Oneline, + Newline, + Indentation, +} + pub(super) fn print_body_hir( db: &dyn DefDatabase, body: &Body, @@ -52,7 +59,14 @@ pub(super) fn print_body_hir( } }; - let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false, edition }; + let mut p = Printer { + db, + body, + buf: header, + indent_level: 0, + line_format: LineFormat::Newline, + edition, + }; if let DefWithBodyId::FunctionId(it) = owner { p.buf.push('('); let function_data = &db.function_data(it); @@ -95,12 +109,38 @@ pub(super) fn print_expr_hir( expr: ExprId, edition: Edition, ) -> String { - let mut p = - Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false, edition }; + let mut p = Printer { + db, + body, + buf: String::new(), + indent_level: 0, + line_format: LineFormat::Newline, + edition, + }; p.print_expr(expr); p.buf } +pub(super) fn print_pat_hir( + db: &dyn DefDatabase, + body: &Body, + _owner: DefWithBodyId, + pat: PatId, + oneline: bool, + edition: Edition, +) -> String { + let mut p = Printer { + db, + body, + buf: String::new(), + indent_level: 0, + line_format: if oneline { LineFormat::Oneline } else { LineFormat::Newline }, + edition, + }; + p.print_pat(pat); + p.buf +} + macro_rules! w { ($dst:expr, $($arg:tt)*) => { { let _ = write!($dst, $($arg)*); } @@ -109,10 +149,10 @@ macro_rules! w { macro_rules! wln { ($dst:expr) => { - { let _ = writeln!($dst); } + { $dst.newline(); } }; ($dst:expr, $($arg:tt)*) => { - { let _ = writeln!($dst, $($arg)*); } + { let _ = w!($dst, $($arg)*); $dst.newline(); } }; } @@ -121,24 +161,30 @@ struct Printer<'a> { body: &'a Body, buf: String, indent_level: usize, - needs_indent: bool, + line_format: LineFormat, edition: Edition, } impl Write for Printer<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { for line in s.split_inclusive('\n') { - if self.needs_indent { + if matches!(self.line_format, LineFormat::Indentation) { match self.buf.chars().rev().find(|ch| *ch != ' ') { Some('\n') | None => {} _ => self.buf.push('\n'), } self.buf.push_str(&" ".repeat(self.indent_level)); - self.needs_indent = false; } self.buf.push_str(line); - self.needs_indent = line.ends_with('\n'); + + if matches!(self.line_format, LineFormat::Newline | LineFormat::Indentation) { + self.line_format = if line.ends_with('\n') { + LineFormat::Indentation + } else { + LineFormat::Newline + }; + } } Ok(()) @@ -161,14 +207,28 @@ impl Printer<'_> { } } + // Add a newline if the current line is not empty. + // If the current line is empty, add a space instead. + // + // Do not use [`writeln!()`] or [`wln!()`] here, which will result in + // infinite recursive calls to this function. fn newline(&mut self) { - match self.buf.chars().rev().find_position(|ch| *ch != ' ') { - Some((_, '\n')) | None => {} - Some((idx, _)) => { - if idx != 0 { - self.buf.drain(self.buf.len() - idx..); + if matches!(self.line_format, LineFormat::Oneline) { + match self.buf.chars().last() { + Some(' ') | None => {} + Some(_) => { + w!(self, " "); + } + } + } else { + match self.buf.chars().rev().find_position(|ch| *ch != ' ') { + Some((_, '\n')) | None => {} + Some((idx, _)) => { + if idx != 0 { + self.buf.drain(self.buf.len() - idx..); + } + w!(self, "\n"); } - writeln!(self).unwrap() } } } @@ -539,12 +599,14 @@ impl Printer<'_> { w!(self, ")"); } Pat::Or(pats) => { + w!(self, "("); for (i, pat) in pats.iter().enumerate() { if i != 0 { w!(self, " | "); } self.print_pat(*pat); } + w!(self, ")"); } Pat::Record { path, args, ellipsis } => { match path { @@ -554,12 +616,37 @@ impl Printer<'_> { w!(self, " {{"); let edition = self.edition; + let oneline = matches!(self.line_format, LineFormat::Oneline); self.indented(|p| { - for arg in args.iter() { - w!(p, "{}: ", arg.name.display(self.db.upcast(), edition)); - p.print_pat(arg.pat); - wln!(p, ","); + for (idx, arg) in args.iter().enumerate() { + let field_name = arg.name.display(self.db.upcast(), edition).to_string(); + + let mut same_name = false; + if let Pat::Bind { id, subpat: None } = &self.body[arg.pat] { + if let Binding { name, mode: BindingAnnotation::Unannotated, .. } = + &self.body.bindings[*id] + { + if name.as_str() == field_name { + same_name = true; + } + } + } + + w!(p, "{}", field_name); + + if !same_name { + w!(p, ": "); + p.print_pat(arg.pat); + } + + // Do not print the extra comma if the line format is oneline + if oneline && idx == args.len() - 1 { + w!(p, " "); + } else { + wln!(p, ","); + } } + if *ellipsis { wln!(p, ".."); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index 38fc01d8fca5f..dd3e79c874d85 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -142,6 +142,41 @@ mod m { ); } +#[test] +fn desugar_for_loop() { + let (db, body, def) = lower( + r#" +//- minicore: iterator +fn main() { + for ident in 0..10 { + foo(); + bar() + } +} +"#, + ); + + expect![[r#" + fn main() -> () { + match builtin#lang(into_iter)( + (0) ..(10) , + ) { + mut 11 => loop { + match builtin#lang(next)( + &mut 11, + ) { + builtin#lang(None) => break, + builtin#lang(Some)(ident) => { + foo(); + bar() + }, + } + }, + } + }"#]] + .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) +} + #[test] fn desugar_builtin_format_args() { let (db, body, def) = lower( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs index a70710e565c27..ba54451e594f7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs @@ -14,6 +14,7 @@ use triomphe::Arc; use crate::{ builtin_type::{BuiltinInt, BuiltinUint}, db::DefDatabase, + hir::Expr, item_tree::{ AttrOwner, Field, FieldParent, FieldsShape, ItemTree, ModItem, RawVisibilityId, TreeId, }, @@ -317,6 +318,27 @@ impl EnumData { _ => IntegerType::Pointer(true), } } + + // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448) + pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { + self.variants.iter().all(|(v, _)| { + // The condition check order is slightly modified from rustc + // to improve performance by early returning with relatively fast checks + let variant = &db.enum_variant_data(*v).variant_data; + if !variant.fields().is_empty() { + return false; + } + // The outer if condition is whether this variant has const ctor or not + if !matches!(variant.kind(), StructKind::Unit) { + let body = db.body((*v).into()); + // A variant with explicit discriminant + if body.exprs[body.body_expr] != Expr::Missing { + return false; + } + } + true + }) + } } impl EnumVariantData { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 86fd092603ffd..d9358a28822e7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -307,7 +307,120 @@ pub struct OffsetOf { #[derive(Debug, Clone, PartialEq, Eq)] pub struct InlineAsm { - pub e: ExprId, + pub operands: Box<[(Option, AsmOperand)]>, + pub options: AsmOptions, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct AsmOptions(u16); +bitflags::bitflags! { + impl AsmOptions: u16 { + const PURE = 1 << 0; + const NOMEM = 1 << 1; + const READONLY = 1 << 2; + const PRESERVES_FLAGS = 1 << 3; + const NORETURN = 1 << 4; + const NOSTACK = 1 << 5; + const ATT_SYNTAX = 1 << 6; + const RAW = 1 << 7; + const MAY_UNWIND = 1 << 8; + } +} + +impl AsmOptions { + pub const COUNT: usize = Self::all().bits().count_ones() as usize; + + pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW); + pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN); + + pub fn human_readable_names(&self) -> Vec<&'static str> { + let mut options = vec![]; + + if self.contains(AsmOptions::PURE) { + options.push("pure"); + } + if self.contains(AsmOptions::NOMEM) { + options.push("nomem"); + } + if self.contains(AsmOptions::READONLY) { + options.push("readonly"); + } + if self.contains(AsmOptions::PRESERVES_FLAGS) { + options.push("preserves_flags"); + } + if self.contains(AsmOptions::NORETURN) { + options.push("noreturn"); + } + if self.contains(AsmOptions::NOSTACK) { + options.push("nostack"); + } + if self.contains(AsmOptions::ATT_SYNTAX) { + options.push("att_syntax"); + } + if self.contains(AsmOptions::RAW) { + options.push("raw"); + } + if self.contains(AsmOptions::MAY_UNWIND) { + options.push("may_unwind"); + } + + options + } +} + +impl std::fmt::Debug for AsmOptions { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + bitflags::parser::to_writer(self, f) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub enum AsmOperand { + In { + reg: InlineAsmRegOrRegClass, + expr: ExprId, + }, + Out { + reg: InlineAsmRegOrRegClass, + expr: Option, + late: bool, + }, + InOut { + reg: InlineAsmRegOrRegClass, + expr: ExprId, + late: bool, + }, + SplitInOut { + reg: InlineAsmRegOrRegClass, + in_expr: ExprId, + out_expr: Option, + late: bool, + }, + Label(ExprId), + Const(ExprId), + Sym(Path), +} + +impl AsmOperand { + pub fn reg(&self) -> Option<&InlineAsmRegOrRegClass> { + match self { + Self::In { reg, .. } + | Self::Out { reg, .. } + | Self::InOut { reg, .. } + | Self::SplitInOut { reg, .. } => Some(reg), + Self::Const { .. } | Self::Sym { .. } | Self::Label { .. } => None, + } + } + + pub fn is_clobber(&self) -> bool { + matches!(self, AsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(_), late: _, expr: None }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub enum InlineAsmRegOrRegClass { + Reg(Symbol), + RegClass(Symbol), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -372,7 +485,21 @@ impl Expr { match self { Expr::Missing => {} Expr::Path(_) | Expr::OffsetOf(_) => {} - Expr::InlineAsm(it) => f(it.e), + Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => f(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + f(*in_expr); + if let Some(out_expr) = out_expr { + f(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), Expr::If { condition, then_branch, else_branch } => { f(*condition); f(*then_branch); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index b6dbba12cd6d6..a3b48831a0b0f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -50,11 +50,7 @@ fn main() { let i: u64 = 3; let o: u64; unsafe { - builtin #asm ( { - $crate::format_args!("mov {0}, {1}"); - $crate::format_args!("add {0}, 5"); - } - ); + builtin #asm ("mov {0}, {1}", "add {0}, 5", out (reg)o, in (reg)i, ); } } "##]], @@ -532,3 +528,21 @@ fn main() { foobar; } "##]], ); } + +#[test] +fn test_quote_string() { + check( + r##" +#[rustc_builtin_macro] +macro_rules! stringify {} + +fn main() { stringify!("hello"); } +"##, + expect![[r##" +#[rustc_builtin_macro] +macro_rules! stringify {} + +fn main() { "\"hello\""; } +"##]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index fc1460870ceaf..85fb90fdfb69f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -389,7 +389,7 @@ m! { foo# bar } m! { Foo,# Bar } "#, - expect![[r##" + expect![[r#" macro_rules! m { ($($i:ident),*) => ($(mod $i {} )*); ($($i:ident)#*) => ($(fn $i() {} )*); @@ -404,27 +404,29 @@ fn bar() {} struct Foo; struct Bar; -"##]], +"#]], ); } #[test] fn test_match_group_pattern_with_multiple_defs() { + // FIXME: The pretty printer breaks by leaving whitespace here, +syntaxctxt is used to avoid that check( r#" macro_rules! m { ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } ); } +// +syntaxctxt m! { foo, bar } "#, expect![[r#" macro_rules! m { ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } ); } -impl Bar { - fn foo() {} - fn bar() {} -} +impl#\1# Bar#\1# {#\1# + fn#\1# foo#\0#(#\1#)#\1# {#\1#}#\1# + fn#\1# bar#\0#(#\1#)#\1# {#\1#}#\1# +}#\1# "#]], ); } @@ -480,12 +482,12 @@ macro_rules! m { } m!{#abc} "#, - expect![[r##" + expect![[r#" macro_rules! m { ($($i:ident)* #abc) => ( fn baz() { $($i ();)* } ); } fn baz() {} -"##]], +"#]], ) } @@ -1189,13 +1191,13 @@ macro_rules! m { m! { cfg(target_os = "windows") } m! { hello::world } "#, - expect![[r##" + expect![[r#" macro_rules! m { ($m:meta) => ( #[$m] fn bar() {} ) } #[cfg(target_os = "windows")] fn bar() {} #[hello::world] fn bar() {} -"##]], +"#]], ); } @@ -1213,7 +1215,7 @@ m! { */ } "#, - expect![[r##" + expect![[r#" macro_rules! m { ($(#[$m:meta])+) => ( $(#[$m])+ fn bar() {} ) } @@ -1221,7 +1223,7 @@ macro_rules! m { #[doc = r" MultiLines Doc "] fn bar() {} -"##]], +"#]], ); } @@ -1234,12 +1236,12 @@ macro_rules! m { } m! { #[doc = concat!("The `", "bla", "` lang item.")] } "#, - expect![[r##" + expect![[r#" macro_rules! m { (#[$m:meta]) => ( #[$m] fn bar() {} ) } #[doc = concat!("The `", "bla", "` lang item.")] fn bar() {} -"##]], +"#]], ); } @@ -1257,7 +1259,7 @@ m! { */ } "#, - expect![[r##" + expect![[r#" macro_rules! m { ($(#[$ m:meta])+) => ( $(#[$m])+ fn bar() {} ) } @@ -1265,7 +1267,7 @@ macro_rules! m { #[doc = r" 莊生曉夢迷蝴蝶,望帝春心託杜鵑。 "] fn bar() {} -"##]], +"#]], ); } @@ -1342,10 +1344,10 @@ fn test_tt_composite2() { macro_rules! m { ($($tt:tt)*) => { abs!(=> $($tt)*); } } m! {#} "#, - expect![[r##" + expect![[r#" macro_rules! m { ($($tt:tt)*) => { abs!(=> $($tt)*); } } abs!( = > #); -"##]], +"#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs index bf70119838766..1430e2a9a994c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs @@ -311,3 +311,150 @@ fn test() { "#]], ); } + +#[test] +fn concat() { + // FIXME: Should this error? rustc currently accepts it. + check( + r#" +macro_rules! m { + ( $a:ident, $b:literal ) => { + let ${concat($a, _, "123", _foo, $b, _, 123)}; + }; +} + +fn test() { + m!( abc, 456 ); + m!( def, "hello" ); +} +"#, + expect![[r#" +macro_rules! m { + ( $a:ident, $b:literal ) => { + let ${concat($a, _, "123", _foo, $b, _, 123)}; + }; +} + +fn test() { + let abc_123_foo456_123;; + let def_123_foohello_123;; +} +"#]], + ); +} + +#[test] +fn concat_less_than_two_elements() { + // FIXME: Should this error? rustc currently accepts it. + check( + r#" +macro_rules! m { + () => { + let ${concat(abc)}; + }; +} + +fn test() { + m!() +} +"#, + expect![[r#" +macro_rules! m { + () => { + let ${concat(abc)}; + }; +} + +fn test() { + /* error: macro definition has parse errors */ +} +"#]], + ); +} + +#[test] +fn concat_invalid_ident() { + // FIXME: Should this error? rustc currently accepts it. + check( + r#" +macro_rules! m { + () => { + let ${concat(abc, '"')}; + }; +} + +fn test() { + m!() +} +"#, + expect![[r#" +macro_rules! m { + () => { + let ${concat(abc, '"')}; + }; +} + +fn test() { + /* error: `${concat(..)}` is not generating a valid identifier */let __ra_concat_dummy; +} +"#]], + ); +} + +#[test] +fn concat_invalid_fragment() { + // FIXME: Should this error? rustc currently accepts it. + check( + r#" +macro_rules! m { + ( $e:expr ) => { + let ${concat(abc, $e)}; + }; +} + +fn test() { + m!(()) +} +"#, + expect![[r#" +macro_rules! m { + ( $e:expr ) => { + let ${concat(abc, $e)}; + }; +} + +fn test() { + /* error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` */let abc; +} +"#]], + ); +} + +#[test] +fn concat_repetition() { + // FIXME: Should this error? rustc currently accepts it. + check( + r#" +macro_rules! m { + ( $($i:ident)* ) => { + let ${concat(abc, $i)}; + }; +} + +fn test() { + m!(a b c) +} +"#, + expect![[r#" +macro_rules! m { + ( $($i:ident)* ) => { + let ${concat(abc, $i)}; + }; +} + +fn test() { + /* error: expected simple binding, found nested binding `i` */let abc; +} +"#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index 485f72e92ce1c..1bbed01443de8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -139,7 +139,7 @@ STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}} STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}} "#, - expect![[r##" + expect![[r#" macro_rules! STRUCT { ($(#[$attrs:meta])* struct $name:ident { $($field:ident: $ftype:ty,)+ @@ -194,7 +194,7 @@ impl Clone for D3DCONTENTPROTECTIONCAPS { } } } -"##]], +"#]], ); } @@ -214,7 +214,7 @@ macro_rules! int_base { } int_base!{Binary for isize as usize -> Binary} "#, - expect![[r##" + expect![[r#" macro_rules! int_base { ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { #[stable(feature = "rust1", since = "1.0.0")] @@ -230,7 +230,7 @@ macro_rules! int_base { Binary.fmt_int(*self as usize, f) } } -"##]], +"#]], ); } @@ -318,7 +318,7 @@ impl_fn_for_zst ! { } "#, - expect![[r##" + expect![[r#" macro_rules! impl_fn_for_zst { {$( $( #[$attr: meta] )* struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn = @@ -410,7 +410,7 @@ impl FnOnce<(char, )> for CharEscapeDefault { } } -"##]], +"#]], ); } @@ -511,7 +511,7 @@ cfg_if! { @__apply cfg(all(not(any(not(any(target_os = "solaris", target_os = "illumos")))))), } "#, - expect![[r##" + expect![[r#" macro_rules! cfg_if { ($(if #[cfg($($meta:meta),*)] { $($it:item)* } )else* else { $($it2:item)* }) => { @@ -534,7 +534,7 @@ __cfg_if_items! { } -"##]], +"#]], ); } @@ -618,7 +618,7 @@ RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID fn GetDataSize(&mut self) -> UINT }} "#, - expect![[r##" + expect![[r#" #[macro_export] macro_rules! RIDL { (interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) @@ -639,7 +639,7 @@ impl ID3D11Asynchronous { ((*self .lpVtbl).GetDataSize)(self ) } } -"##]], +"#]], ); } @@ -676,7 +676,7 @@ quick_error ! ( ); "#, - expect![[r##" + expect![[r#" macro_rules! quick_error { (SORT [enum $name:ident $( #[$meta:meta] )*] items [$($( #[$imeta:meta] )* @@ -697,7 +697,7 @@ macro_rules! quick_error { } quick_error!(ENUMINITION[enum Wrapped#[derive(Debug)]]body[]queue[ = > One: UNIT[] = > Two: TUPLE[s: String]]); -"##]], +"#]], ) } @@ -746,7 +746,7 @@ delegate_impl ! { [G, &'a mut G, deref] pub trait Data: GraphBase {@section type type NodeWeight;} } "#, - expect![[r##" + expect![[r#" macro_rules! delegate_impl { ([$self_type:ident, $self_wrap:ty, $self_map:ident] pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* { @@ -785,7 +785,7 @@ macro_rules! delegate_impl { } } impl <> Data for &'amut G where G: Data {} -"##]], +"#]], ); } @@ -959,14 +959,14 @@ macro_rules! with_std { with_std! {mod m;mod f;} "#, - expect![[r##" + expect![[r#" macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) } #[cfg(feature = "std")] mod m; #[cfg(feature = "std")] mod f; -"##]], +"#]], ) } @@ -1144,3 +1144,27 @@ mod any { "#]], ); } + +#[test] +fn regression_18148() { + check( + r#" +macro_rules! m { + ( $e:expr ) => {}; +} + +fn foo() { + m!(r#const); +} +"#, + expect![[r#" +macro_rules! m { + ( $e:expr ) => {}; +} + +fn foo() { + ; +} +"#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 7f761192517c4..450a15bd66e59 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -1,6 +1,6 @@ -//! This module contains tests for macro expansion. Effectively, it covers `tt`, -//! `mbe`, `proc_macro_api` and `hir_expand` crates. This might seem like a -//! wrong architecture at the first glance, but is intentional. +//! This module contains integration tests for macro expansion with name resolution. Effectively, it +//! covers `tt`, `mbe`, `proc_macro_api` and `hir_expand` crates. This might seem like a wrong +//! architecture at the first glance, but is intentional. //! //! Physically, macro expansion process is intertwined with name resolution. You //! can not expand *just* the syntax. So, to be able to write integration tests @@ -320,6 +320,7 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { _: Span, _: Span, _: Span, + _: Option, ) -> Result { let (parse, _) = syntax_bridge::token_tree_to_syntax_node( subtree, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index 6f605c0cb33db..c0178adc9a63a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -16,12 +16,12 @@ fn attribute_macro_attr_censoring() { #[attr1] #[proc_macros::identity] #[attr2] struct S; "#, - expect![[r##" + expect![[r#" #[attr1] #[proc_macros::identity] #[attr2] struct S; #[attr1] -#[attr2] struct S;"##]], +#[attr2] struct S;"#]], ); } @@ -39,7 +39,7 @@ fn derive_censoring() { #[attr2] struct S; "#, - expect![[r##" + expect![[r#" #[attr1] #[derive(Foo)] #[derive(proc_macros::DeriveIdentity)] @@ -49,7 +49,7 @@ struct S; #[attr1] #[derive(Bar)] -#[attr2] struct S;"##]], +#[attr2] struct S;"#]], ); } @@ -62,14 +62,14 @@ fn attribute_macro_syntax_completion_1() { #[proc_macros::identity_when_valid] fn foo() { bar.baz(); blub } "#, - expect![[r##" + expect![[r#" #[proc_macros::identity_when_valid] fn foo() { bar.baz(); blub } fn foo() { bar.baz(); blub -}"##]], +}"#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 11601c683e1ea..9bd7d38f0a64d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -69,7 +69,7 @@ use la_arena::Arena; use rustc_hash::{FxHashMap, FxHashSet}; use span::{Edition, EditionedFileId, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID}; use stdx::format_to; -use syntax::{ast, SmolStr}; +use syntax::{ast, AstNode, SmolStr, SyntaxNode}; use triomphe::Arc; use tt::TextRange; @@ -291,7 +291,7 @@ impl ModuleOrigin { /// Returns a node which defines this module. /// That is, a file or a `mod foo {}` with items. - fn definition_source(&self, db: &dyn DefDatabase) -> InFile { + pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile { match self { &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => { let sf = db.parse(definition).tree(); @@ -728,6 +728,16 @@ pub enum ModuleSource { BlockExpr(ast::BlockExpr), } +impl ModuleSource { + pub fn node(&self) -> SyntaxNode { + match self { + ModuleSource::SourceFile(it) => it.syntax().clone(), + ModuleSource::Module(it) => it.syntax().clone(), + ModuleSource::BlockExpr(it) => it.syntax().clone(), + } + } +} + /// See `sub_namespace_match()`. #[derive(Clone, Copy, PartialEq, Eq)] pub enum MacroSubNs { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 96db3db8f0d8a..e09ef4f205d3c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -221,7 +221,7 @@ struct DefCollector<'a> { deps: FxHashMap, glob_imports: FxHashMap>, unresolved_imports: Vec, - indeterminate_imports: Vec, + indeterminate_imports: Vec<(ImportDirective, PerNs)>, unresolved_macros: Vec, mod_dirs: FxHashMap, cfg_options: &'a CfgOptions, @@ -415,16 +415,6 @@ impl DefCollector<'_> { self.resolution_loop(); - // Resolve all indeterminate resolved imports again - // As some of the macros will expand newly import shadowing partial resolved imports - // FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports` - // correctly - let partial_resolved = self.indeterminate_imports.drain(..).map(|directive| { - ImportDirective { status: PartialResolvedImport::Unresolved, ..directive } - }); - self.unresolved_imports.extend(partial_resolved); - self.resolve_imports(); - let unresolved_imports = mem::take(&mut self.unresolved_imports); // show unresolved imports in completion, etc for directive in &unresolved_imports { @@ -749,9 +739,9 @@ impl DefCollector<'_> { .filter_map(|mut directive| { directive.status = self.resolve_import(directive.module_id, &directive.import); match directive.status { - PartialResolvedImport::Indeterminate(_) => { + PartialResolvedImport::Indeterminate(resolved) => { self.record_resolved_import(&directive); - self.indeterminate_imports.push(directive); + self.indeterminate_imports.push((directive, resolved)); res = ReachedFixedPoint::No; None } @@ -764,6 +754,33 @@ impl DefCollector<'_> { } }) .collect(); + + // Resolve all indeterminate resolved imports again + // As some of the macros will expand newly import shadowing partial resolved imports + // FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports` + // correctly + let mut indeterminate_imports = std::mem::take(&mut self.indeterminate_imports); + indeterminate_imports.retain_mut(|(directive, partially_resolved)| { + let partially_resolved = partially_resolved.availability(); + directive.status = self.resolve_import(directive.module_id, &directive.import); + match directive.status { + PartialResolvedImport::Indeterminate(import) + if partially_resolved != import.availability() => + { + self.record_resolved_import(directive); + res = ReachedFixedPoint::No; + false + } + PartialResolvedImport::Resolved(_) => { + self.record_resolved_import(directive); + res = ReachedFixedPoint::No; + false + } + _ => true, + } + }); + self.indeterminate_imports = indeterminate_imports; + res } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs index 19485c476f72d..3f3b98c6b5b5d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs @@ -3,6 +3,8 @@ //! //! `PerNs` (per namespace) captures this. +use bitflags::bitflags; + use crate::{ item_scope::{ImportId, ImportOrExternCrate, ItemInNs}, visibility::Visibility, @@ -16,6 +18,16 @@ pub enum Namespace { Macros, } +bitflags! { + /// Describes only the presence/absence of each namespace, without its value. + #[derive(Debug, PartialEq, Eq)] + pub(crate) struct NsAvailability : u32 { + const TYPES = 1 << 0; + const VALUES = 1 << 1; + const MACROS = 1 << 2; + } +} + #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] pub struct PerNs { pub types: Option<(ModuleDefId, Visibility, Option)>, @@ -24,6 +36,14 @@ pub struct PerNs { } impl PerNs { + pub(crate) fn availability(&self) -> NsAvailability { + let mut result = NsAvailability::empty(); + result.set(NsAvailability::TYPES, self.types.is_some()); + result.set(NsAvailability::VALUES, self.values.is_some()); + result.set(NsAvailability::MACROS, self.macros.is_some()); + result + } + pub fn none() -> PerNs { PerNs { types: None, values: None, macros: None } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin.rs index 252430e4e954a..7b9b7f36e2cdb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin.rs @@ -1,6 +1,6 @@ //! Builtin macros and attributes #[macro_use] -mod quote; +pub mod quote; mod attr_macro; mod derive_macro; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 795d9b14df961..d04225b87227b 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -119,9 +119,8 @@ register_builtin! { (module_path, ModulePath) => module_path_expand, (assert, Assert) => assert_expand, (stringify, Stringify) => stringify_expand, - (llvm_asm, LlvmAsm) => asm_expand, (asm, Asm) => asm_expand, - (global_asm, GlobalAsm) => global_asm_expand, + (global_asm, GlobalAsm) => asm_expand, (cfg, Cfg) => cfg_expand, (core_panic, CorePanic) => panic_expand, (std_panic, StdPanic) => panic_expand, @@ -324,40 +323,15 @@ fn asm_expand( tt: &tt::Subtree, span: Span, ) -> ExpandResult { - // We expand all assembly snippets to `format_args!` invocations to get format syntax - // highlighting for them. - let mut literals = Vec::new(); - for tt in tt.token_trees.chunks(2) { - match tt { - [tt::TokenTree::Leaf(tt::Leaf::Literal(lit))] - | [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] => - { - let dollar_krate = dollar_crate(span); - literals.push(quote!(span=>#dollar_krate::format_args!(#lit);)); - } - _ => break, - } - } - + let mut tt = tt.clone(); + tt.delimiter.kind = tt::DelimiterKind::Parenthesis; let pound = mk_pound(span); let expanded = quote! {span => - builtin #pound asm ( - {##literals} - ) + builtin #pound asm #tt }; ExpandResult::ok(expanded) } -fn global_asm_expand( - _db: &dyn ExpandDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, - span: Span, -) -> ExpandResult { - // Expand to nothing (at item-level) - ExpandResult::ok(quote! {span =>}) -} - fn cfg_expand( db: &dyn ExpandDatabase, id: MacroCallId, @@ -509,7 +483,7 @@ fn concat_expand( match it.kind { tt::LitKind::Char => { if let Ok(c) = unescape_char(it.symbol.as_str()) { - text.extend(c.escape_default()); + text.push(c); } record_span(it.span); } @@ -517,11 +491,11 @@ fn concat_expand( format_to!(text, "{}", it.symbol.as_str()) } tt::LitKind::Str => { - text.push_str(it.symbol.as_str()); + text.push_str(unescape_str(&it.symbol).as_str()); record_span(it.span); } tt::LitKind::StrRaw(_) => { - format_to!(text, "{}", it.symbol.as_str().escape_debug()); + format_to!(text, "{}", it.symbol.as_str()); record_span(it.span); } tt::LitKind::Byte @@ -839,7 +813,7 @@ fn include_str_expand( fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &Symbol) -> Option { let krate = db.lookup_intern_macro_call(arg_id).krate; - db.crate_graph()[krate].env.get(key.as_str()).map(|it| it.escape_debug().to_string()) + db.crate_graph()[krate].env.get(key.as_str()) } fn env_expand( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs index 5c33f817f9e44..418d8d9660b58 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs @@ -3,6 +3,7 @@ use intern::{sym, Symbol}; use span::Span; +use syntax::ToSmolStr; use tt::IdentIsRaw; use crate::name::Name; @@ -17,6 +18,7 @@ pub(crate) fn dollar_crate(span: Span) -> tt::Ident { // 2. #()* pattern repetition not supported now // * But we can do it manually, see `test_quote_derive_copy_hack` #[doc(hidden)] +#[macro_export] macro_rules! quote_impl__ { ($span:ident) => { Vec::<$crate::tt::TokenTree>::new() @@ -26,8 +28,8 @@ macro_rules! quote_impl__ { { let children = $crate::builtin::quote::__quote!($span $($tt)*); $crate::tt::Subtree { - delimiter: crate::tt::Delimiter { - kind: crate::tt::DelimiterKind::$delim, + delimiter: $crate::tt::Delimiter { + kind: $crate::tt::DelimiterKind::$delim, open: $span, close: $span, }, @@ -39,9 +41,9 @@ macro_rules! quote_impl__ { ( @PUNCT($span:ident) $first:literal ) => { { vec![ - crate::tt::Leaf::Punct(crate::tt::Punct { + $crate::tt::Leaf::Punct($crate::tt::Punct { char: $first, - spacing: crate::tt::Spacing::Alone, + spacing: $crate::tt::Spacing::Alone, span: $span, }).into() ] @@ -51,14 +53,14 @@ macro_rules! quote_impl__ { ( @PUNCT($span:ident) $first:literal, $sec:literal ) => { { vec![ - crate::tt::Leaf::Punct(crate::tt::Punct { + $crate::tt::Leaf::Punct($crate::tt::Punct { char: $first, - spacing: crate::tt::Spacing::Joint, + spacing: $crate::tt::Spacing::Joint, span: $span, }).into(), - crate::tt::Leaf::Punct(crate::tt::Punct { + $crate::tt::Leaf::Punct($crate::tt::Punct { char: $sec, - spacing: crate::tt::Spacing::Alone, + spacing: $crate::tt::Spacing::Alone, span: $span, }).into() ] @@ -97,7 +99,7 @@ macro_rules! quote_impl__ { // Ident ($span:ident $tt:ident ) => { vec![ { - crate::tt::Leaf::Ident(crate::tt::Ident { + $crate::tt::Leaf::Ident($crate::tt::Ident { sym: intern::Symbol::intern(stringify!($tt)), span: $span, is_raw: tt::IdentIsRaw::No, @@ -108,6 +110,7 @@ macro_rules! quote_impl__ { // Puncts // FIXME: Not all puncts are handled ($span:ident -> ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '-', '>')}; + ($span:ident => ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '=', '>')}; ($span:ident & ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '&')}; ($span:ident , ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ',')}; ($span:ident : ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ':')}; @@ -117,6 +120,9 @@ macro_rules! quote_impl__ { ($span:ident < ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '<')}; ($span:ident > ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '>')}; ($span:ident ! ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '!')}; + ($span:ident # ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '#')}; + ($span:ident $ ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '$')}; + ($span:ident * ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '*')}; ($span:ident $first:tt $($tail:tt)+ ) => { { @@ -128,18 +134,19 @@ macro_rules! quote_impl__ { } }; } -pub(super) use quote_impl__ as __quote; +pub use quote_impl__ as __quote; /// FIXME: /// It probably should implement in proc-macro -macro_rules! quote_impl { +#[macro_export] +macro_rules! quote { ($span:ident=> $($tt:tt)* ) => { $crate::builtin::quote::IntoTt::to_subtree($crate::builtin::quote::__quote!($span $($tt)*), $span) } } -pub(super) use quote_impl as quote; +pub(super) use quote; -pub(crate) trait IntoTt { +pub trait IntoTt { fn to_subtree(self, span: Span) -> crate::tt::Subtree; fn to_tokens(self) -> Vec; } @@ -167,7 +174,7 @@ impl IntoTt for crate::tt::Subtree { } } -pub(crate) trait ToTokenTree { +pub trait ToTokenTree { fn to_token(self, span: Span) -> crate::tt::TokenTree; } @@ -211,8 +218,8 @@ impl_to_to_tokentrees! { _span: crate::tt::Literal => self { self }; _span: crate::tt::Ident => self { self }; _span: crate::tt::Punct => self { self }; - span: &str => self { crate::tt::Literal{symbol: Symbol::intern(self), span, kind: tt::LitKind::Str, suffix: None }}; - span: String => self { crate::tt::Literal{symbol: Symbol::intern(&self), span, kind: tt::LitKind::Str, suffix: None }}; + span: &str => self { crate::tt::Literal{symbol: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix: None }}; + span: String => self { crate::tt::Literal{symbol: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix: None }}; span: Name => self { let (is_raw, s) = IdentIsRaw::split_from_symbol(self.as_str()); crate::tt::Ident{sym: Symbol::intern(s), span, is_raw } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs index 147cf912da1ef..01a3103af82d4 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs @@ -6,7 +6,7 @@ use cfg::{CfgAtom, CfgExpr}; use intern::{sym, Symbol}; use rustc_hash::FxHashSet; use syntax::{ - ast::{self, Attr, HasAttrs, Meta, VariantList}, + ast::{self, Attr, HasAttrs, Meta, TokenTree, VariantList}, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, T, }; use tracing::{debug, warn}; @@ -17,7 +17,7 @@ fn check_cfg(db: &dyn ExpandDatabase, attr: &Attr, krate: CrateId) -> Option Optio if !attr.simple_name().as_deref().map(|v| v == "cfg_attr")? { return None; } - let cfg_expr = parse_from_attr_meta(attr.meta()?)?; + check_cfg_attr_value(db, &attr.token_tree()?, krate) +} + +pub fn check_cfg_attr_value( + db: &dyn ExpandDatabase, + attr: &TokenTree, + krate: CrateId, +) -> Option { + let cfg_expr = parse_from_attr_token_tree(attr)?; let enabled = db.crate_graph()[krate].cfg_options.check(&cfg_expr) != Some(false); Some(enabled) } @@ -238,8 +246,7 @@ pub(crate) fn process_cfg_attrs( Some(remove) } /// Parses a `cfg` attribute from the meta -fn parse_from_attr_meta(meta: Meta) -> Option { - let tt = meta.token_tree()?; +fn parse_from_attr_token_tree(tt: &TokenTree) -> Option { let mut iter = tt .token_trees_and_tokens() .filter(is_not_whitespace) @@ -328,7 +335,7 @@ mod tests { use expect_test::{expect, Expect}; use syntax::{ast::Attr, AstNode, SourceFile}; - use crate::cfg_process::parse_from_attr_meta; + use crate::cfg_process::parse_from_attr_token_tree; fn check_dnf_from_syntax(input: &str, expect: Expect) { let parse = SourceFile::parse(input, span::Edition::CURRENT); @@ -342,7 +349,7 @@ mod tests { let node = node.clone_subtree(); assert_eq!(node.syntax().text_range().start(), 0.into()); - let cfg = parse_from_attr_meta(node.meta().unwrap()).unwrap(); + let cfg = parse_from_attr_token_tree(&node.meta().unwrap().token_tree().unwrap()).unwrap(); let actual = format!("#![cfg({})]", DnfExpr::new(&cfg)); expect.assert_eq(&actual); } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs index 8b3f69db0277c..de3a7b9f5615e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs @@ -1,10 +1,10 @@ //! Defines a unit of change that can applied to the database to get the next //! state. Changes are transactional. use base_db::{ - salsa::Durability, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootDatabase, - TargetLayoutLoadResult, Version, + salsa::Durability, CrateGraph, CrateId, CrateWorkspaceData, FileChange, SourceRoot, + SourceRootDatabase, }; -use la_arena::RawIdx; +use rustc_hash::FxHashMap; use span::FileId; use triomphe::Arc; @@ -14,8 +14,6 @@ use crate::{db::ExpandDatabase, proc_macro::ProcMacros}; pub struct ChangeWithProcMacros { pub source_change: FileChange, pub proc_macros: Option, - pub toolchains: Option>>, - pub target_data_layouts: Option>, } impl ChangeWithProcMacros { @@ -28,46 +26,25 @@ impl ChangeWithProcMacros { if let Some(proc_macros) = self.proc_macros { db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH); } - if let Some(target_data_layouts) = self.target_data_layouts { - for (id, val) in target_data_layouts.into_iter().enumerate() { - db.set_data_layout_with_durability( - CrateId::from_raw(RawIdx::from(id as u32)), - val, - Durability::HIGH, - ); - } - } - if let Some(toolchains) = self.toolchains { - for (id, val) in toolchains.into_iter().enumerate() { - db.set_toolchain_with_durability( - CrateId::from_raw(RawIdx::from(id as u32)), - val, - Durability::HIGH, - ); - } - } } pub fn change_file(&mut self, file_id: FileId, new_text: Option) { self.source_change.change_file(file_id, new_text) } - pub fn set_crate_graph(&mut self, graph: CrateGraph) { - self.source_change.set_crate_graph(graph) + pub fn set_crate_graph( + &mut self, + graph: CrateGraph, + ws_data: FxHashMap>, + ) { + self.source_change.set_crate_graph(graph); + self.source_change.set_ws_data(ws_data); } pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) { self.proc_macros = Some(proc_macros); } - pub fn set_toolchains(&mut self, toolchains: Vec>) { - self.toolchains = Some(toolchains); - } - - pub fn set_target_data_layouts(&mut self, target_data_layouts: Vec) { - self.target_data_layouts = Some(target_data_layouts); - } - pub fn set_roots(&mut self, roots: Vec) { self.source_change.set_roots(roots) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index b1a6eed2fbc71..86dd4aef090ff 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -1,4 +1,4 @@ -//! Compiled declarative macro expanders (`macro_rules!`` and `macro`) +//! Compiled declarative macro expanders (`macro_rules!` and `macro`) use base_db::CrateId; use intern::sym; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index ee15b1b5ce9d5..5c25a55362e64 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -464,6 +464,9 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // Used by the `rustc::potential_query_instability` lint to warn methods which // might not be stable during incremental compilation. rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + // Used by the `rustc::untracked_query_information` lint to warn methods which + // might break incremental compilation. + rustc_attr!(rustc_lint_untracked_query_information, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), // Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints // to assist in changes to diagnostic APIs. rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 19c3c9c43f104..95380979492a2 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -21,6 +21,7 @@ pub mod span_map; mod cfg_process; mod fixup; +mod prettify_macro_expansion_; use attrs::collect_attrs; use rustc_hash::FxHashMap; @@ -51,7 +52,11 @@ use crate::{ span_map::{ExpansionSpanMap, SpanMap}, }; -pub use crate::files::{AstId, ErasedAstId, FileRange, InFile, InMacroFile, InRealFile}; +pub use crate::{ + cfg_process::check_cfg_attr_value, + files::{AstId, ErasedAstId, FileRange, InFile, InMacroFile, InRealFile}, + prettify_macro_expansion_::prettify_macro_expansion, +}; pub use mbe::{DeclarativeMacro, ValueResult}; pub use span::{HirFileId, MacroCallId, MacroFileId}; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs new file mode 100644 index 0000000000000..d928cafdefc0c --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs @@ -0,0 +1,60 @@ +//! Pretty printing of macros output. + +use base_db::CrateId; +use rustc_hash::FxHashMap; +use syntax::NodeOrToken; +use syntax::{ast::make, SyntaxNode}; + +use crate::{db::ExpandDatabase, span_map::ExpansionSpanMap}; + +/// Inserts whitespace and replaces `$crate` in macro expansions. +#[expect(deprecated)] +pub fn prettify_macro_expansion( + db: &dyn ExpandDatabase, + syn: SyntaxNode, + span_map: &ExpansionSpanMap, + target_crate_id: CrateId, +) -> SyntaxNode { + let crate_graph = db.crate_graph(); + let target_crate = &crate_graph[target_crate_id]; + let mut syntax_ctx_id_to_dollar_crate_replacement = FxHashMap::default(); + syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(syn, &mut |dollar_crate| { + let ctx = span_map.span_at(dollar_crate.text_range().start()).ctx; + let replacement = + syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| { + let ctx_data = db.lookup_intern_syntax_context(ctx); + let macro_call_id = + ctx_data.outer_expn.expect("`$crate` cannot come from `SyntaxContextId::ROOT`"); + let macro_call = db.lookup_intern_macro_call(macro_call_id); + let macro_def_crate = macro_call.def.krate; + // First, if this is the same crate as the macro, nothing will work but `crate`. + // If not, if the target trait has the macro's crate as a dependency, using the dependency name + // will work in inserted code and match the user's expectation. + // If not, the crate's display name is what the dependency name is likely to be once such dependency + // is inserted, and also understandable to the user. + // Lastly, if nothing else found, resort to leaving `$crate`. + if target_crate_id == macro_def_crate { + make::tokens::crate_kw() + } else if let Some(dep) = + target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate) + { + make::tokens::ident(&dep.name) + } else if let Some(crate_name) = &crate_graph[macro_def_crate].display_name { + make::tokens::ident(crate_name.crate_name()) + } else { + return dollar_crate.clone(); + } + }); + if replacement.text() == "$crate" { + // The parent may have many children, and looking for the token may yield incorrect results. + return dollar_crate.clone(); + } + // We need to `clone_subtree()` but rowan doesn't provide such operation for tokens. + let parent = replacement.parent().unwrap().clone_subtree().clone_for_update(); + parent + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .find(|it| it.kind() == replacement.kind()) + .unwrap() + }) +} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs index 26bb3a3edda4d..fe09f0307c9ec 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs @@ -29,6 +29,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe { def_site: Span, call_site: Span, mixed_site: Span, + current_dir: Option, ) -> Result; } @@ -234,8 +235,18 @@ impl CustomProcMacroExpander { let krate_graph = db.crate_graph(); // Proc macros have access to the environment variables of the invoking crate. let env = &krate_graph[calling_crate].env; - match proc_macro.expander.expand(tt, attr_arg, env, def_site, call_site, mixed_site) - { + match proc_macro.expander.expand( + tt, + attr_arg, + env, + def_site, + call_site, + mixed_site, + db.crate_workspace_data()[&calling_crate] + .proc_macro_cwd + .as_ref() + .map(ToString::to_string), + ) { Ok(t) => ExpandResult::ok(t), Err(err) => match err { // Don't discard the item in case something unexpected happened while expanding attributes diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index a3e4da5d1afd7..e74e3d789883e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -381,9 +381,9 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { TyKind::Error.intern(Interner) } - fn is_object_safe(&self, _trait_id: chalk_ir::TraitId) -> bool { - // FIXME: implement actual object safety - true + fn is_object_safe(&self, trait_id: chalk_ir::TraitId) -> bool { + let trait_ = from_chalk_trait_id(trait_id); + crate::object_safety::object_safety(self.db, trait_).is_none() } fn closure_kind( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index 8b6cde975f63e..968a828e9dfef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -11,7 +11,7 @@ use hir_def::{ ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId, }; use hir_expand::Lookup; -use stdx::never; +use stdx::{never, IsNoneOr}; use triomphe::Arc; use crate::{ @@ -184,6 +184,22 @@ pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option { } } +pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option { + match &c.data(Interner).value { + chalk_ir::ConstValue::BoundVar(_) => None, + chalk_ir::ConstValue::InferenceVar(_) => None, + chalk_ir::ConstValue::Placeholder(_) => None, + chalk_ir::ConstValue::Concrete(c) => match &c.interned { + ConstScalar::Bytes(it, _) => Some(i128::from_le_bytes(pad16(it, true))), + ConstScalar::UnevaluatedConst(c, subst) => { + let ec = db.const_eval(*c, subst.clone(), None).ok()?; + try_const_isize(db, &ec) + } + _ => None, + }, + } +} + pub(crate) fn const_eval_recover( _: &dyn HirDatabase, _: &Cycle, @@ -256,8 +272,8 @@ pub(crate) fn const_eval_discriminant_variant( ) -> Result { let def = variant_id.into(); let body = db.body(def); + let loc = variant_id.lookup(db.upcast()); if body.exprs[body.body_expr] == Expr::Missing { - let loc = variant_id.lookup(db.upcast()); let prev_idx = loc.index.checked_sub(1); let value = match prev_idx { Some(prev_idx) => { @@ -269,13 +285,21 @@ pub(crate) fn const_eval_discriminant_variant( }; return Ok(value); } + + let repr = db.enum_data(loc.parent).repr; + let is_signed = IsNoneOr::is_none_or(repr.and_then(|repr| repr.int), |int| int.is_signed()); + let mir_body = db.monomorphized_mir_body( def, Substitution::empty(Interner), db.trait_environment_for_body(def), )?; let c = interpret_mir(db, mir_body, false, None).0?; - let c = try_const_usize(db, &c).unwrap() as i128; + let c = if is_signed { + try_const_isize(db, &c).unwrap() + } else { + try_const_usize(db, &c).unwrap() as i128 + }; Ok(c) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 86228250c2005..7093fcadcb030 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -186,7 +186,13 @@ fn floating_point() { #[test] fn casts() { - check_number(r#"const GOAL: usize = 12 as *const i32 as usize"#, 12); + check_number( + r#" + //- minicore: sized + const GOAL: usize = 12 as *const i32 as usize + "#, + 12, + ); check_number( r#" //- minicore: coerce_unsized, index, slice @@ -204,7 +210,7 @@ fn casts() { r#" //- minicore: coerce_unsized, index, slice const GOAL: i16 = { - let a = &mut 5; + let a = &mut 5_i16; let z = a as *mut _; unsafe { *z } }; @@ -244,7 +250,13 @@ fn casts() { "#, 4, ); - check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12); + check_number( + r#" + //- minicore: sized + const GOAL: i32 = -12i8 as i32 + "#, + -12, + ); } #[test] @@ -1544,7 +1556,7 @@ fn builtin_derive_macro() { Bar, } #[derive(Clone)] - struct X(i32, Z, i64) + struct X(i32, Z, i64); #[derive(Clone)] struct Y { field1: i32, @@ -1562,20 +1574,20 @@ fn builtin_derive_macro() { ); check_number( r#" - //- minicore: default, derive, builtin_impls - #[derive(Default)] - struct X(i32, Y, i64) - #[derive(Default)] - struct Y { - field1: i32, - field2: u8, - } +//- minicore: default, derive, builtin_impls +#[derive(Default)] +struct X(i32, Y, i64); +#[derive(Default)] +struct Y { + field1: i32, + field2: u8, +} - const GOAL: u8 = { - let x = X::default(); - x.1.field2 - }; - "#, +const GOAL: u8 = { + let x = X::default(); + x.1.field2 +}; +"#, 0, ); } @@ -1911,6 +1923,7 @@ fn function_pointer() { ); check_number( r#" + //- minicore: sized fn add2(x: u8) -> u8 { x + 2 } @@ -2007,7 +2020,7 @@ fn function_traits() { ); check_number( r#" - //- minicore: coerce_unsized, fn + //- minicore: coerce_unsized, fn, dispatch_from_dyn fn add2(x: u8) -> u8 { x + 2 } @@ -2062,7 +2075,7 @@ fn function_traits() { fn dyn_trait() { check_number( r#" - //- minicore: coerce_unsized, index, slice + //- minicore: coerce_unsized, index, slice, dispatch_from_dyn trait Foo { fn foo(&self) -> u8 { 10 } } @@ -2085,7 +2098,7 @@ fn dyn_trait() { ); check_number( r#" - //- minicore: coerce_unsized, index, slice + //- minicore: coerce_unsized, index, slice, dispatch_from_dyn trait Foo { fn foo(&self) -> i32 { 10 } } @@ -2109,7 +2122,7 @@ fn dyn_trait() { ); check_number( r#" - //- minicore: coerce_unsized, index, slice + //- minicore: coerce_unsized, index, slice, dispatch_from_dyn trait A { fn x(&self) -> i32; } @@ -2422,6 +2435,7 @@ fn statics() { fn extern_weak_statics() { check_number( r#" + //- minicore: sized extern "C" { #[linkage = "extern_weak"] static __dso_handle: *mut u8; @@ -2716,6 +2730,7 @@ fn const_trait_assoc() { ); check_number( r#" + //- minicore: sized struct S(*mut T); trait MySized: Sized { @@ -2813,7 +2828,7 @@ fn type_error() { y.0 }; "#, - |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))), + |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::HasErrors)), ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index 5972b80d1696b..c5706172b20c4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -89,7 +89,7 @@ fn size_of_val() { ); check_number( r#" - //- minicore: coerce_unsized, fmt, builtin_impls + //- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn extern "rust-intrinsic" { pub fn size_of_val(_: *const T) -> usize; } @@ -311,6 +311,7 @@ fn saturating() { fn allocator() { check_number( r#" + //- minicore: sized extern "Rust" { #[rustc_allocator] fn __rust_alloc(size: usize, align: usize) -> *mut u8; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 9a1f2158bf753..ce5a821ea2bc4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -11,7 +11,7 @@ use base_db::{ use hir_def::{ db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, - LifetimeParamId, LocalFieldId, StaticId, TypeAliasId, TypeOrConstParamId, VariantId, + LifetimeParamId, LocalFieldId, StaticId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId, }; use la_arena::ArenaMap; use smallvec::SmallVec; @@ -24,6 +24,7 @@ use crate::{ lower::{GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, + object_safety::ObjectSafetyViolation, Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner, PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, }; @@ -107,6 +108,9 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::layout::target_data_layout_query)] fn target_data_layout(&self, krate: CrateId) -> Result, Arc>; + #[salsa::invoke(crate::object_safety::object_safety_of_trait_query)] + fn object_safety_of_trait(&self, trait_: TraitId) -> Option; + #[salsa::invoke(crate::lower::ty_query)] #[salsa::cycle(crate::lower::ty_recover)] fn ty(&self, def: TyDefId) -> Binders; @@ -150,6 +154,9 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; + #[salsa::invoke(crate::lower::generic_predicates_without_parent_query)] + fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates; + #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 024fc32f86370..82517e6991752 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -16,13 +16,13 @@ mod case_conv; use std::fmt; use hir_def::{ - data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, AttrDefId, ConstId, - EnumId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, - StaticId, StructId, TraitId, TypeAliasId, + data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, ConstId, EnumId, + EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId, + StructId, TraitId, TypeAliasId, }; use hir_expand::{ name::{AsName, Name}, - HirFileId, HirFileIdExt, MacroFileIdExt, + HirFileId, HirFileIdExt, }; use intern::sym; use stdx::{always, never}; @@ -36,14 +36,6 @@ use crate::db::HirDatabase; use self::case_conv::{to_camel_case, to_lower_snake_case, to_upper_snake_case}; -mod allow { - pub(super) const BAD_STYLE: &str = "bad_style"; - pub(super) const NONSTANDARD_STYLE: &str = "nonstandard_style"; - pub(super) const NON_SNAKE_CASE: &str = "non_snake_case"; - pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals"; - pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; -} - pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec { let _p = tracing::info_span!("incorrect_case").entered(); let mut validator = DeclValidator::new(db); @@ -160,92 +152,7 @@ impl<'a> DeclValidator<'a> { } } - /// Checks whether not following the convention is allowed for this item. - fn allowed(&self, id: AttrDefId, allow_name: &str, recursing: bool) -> bool { - let is_allowed = |def_id| { - let attrs = self.db.attrs(def_id); - // don't bug the user about directly no_mangle annotated stuff, they can't do anything about it - (!recursing && attrs.by_key(&sym::no_mangle).exists()) - || attrs.by_key(&sym::allow).tt_values().any(|tt| { - let allows = tt.to_string(); - allows.contains(allow_name) - || allows.contains(allow::BAD_STYLE) - || allows.contains(allow::NONSTANDARD_STYLE) - }) - }; - let db = self.db.upcast(); - let file_id_is_derive = || { - match id { - AttrDefId::ModuleId(m) => { - m.def_map(db)[m.local_id].origin.file_id().map(Into::into) - } - AttrDefId::FunctionId(f) => Some(f.lookup(db).id.file_id()), - AttrDefId::StaticId(sid) => Some(sid.lookup(db).id.file_id()), - AttrDefId::ConstId(cid) => Some(cid.lookup(db).id.file_id()), - AttrDefId::TraitId(tid) => Some(tid.lookup(db).id.file_id()), - AttrDefId::TraitAliasId(taid) => Some(taid.lookup(db).id.file_id()), - AttrDefId::ImplId(iid) => Some(iid.lookup(db).id.file_id()), - AttrDefId::ExternBlockId(id) => Some(id.lookup(db).id.file_id()), - AttrDefId::ExternCrateId(id) => Some(id.lookup(db).id.file_id()), - AttrDefId::UseId(id) => Some(id.lookup(db).id.file_id()), - // These warnings should not explore macro definitions at all - AttrDefId::MacroId(_) => None, - AttrDefId::AdtId(aid) => match aid { - AdtId::StructId(sid) => Some(sid.lookup(db).id.file_id()), - AdtId::EnumId(eid) => Some(eid.lookup(db).id.file_id()), - // Unions aren't yet supported - AdtId::UnionId(_) => None, - }, - AttrDefId::FieldId(_) => None, - AttrDefId::EnumVariantId(_) => None, - AttrDefId::TypeAliasId(_) => None, - AttrDefId::GenericParamId(_) => None, - } - .map_or(false, |file_id| { - matches!(file_id.macro_file(), Some(file_id) if file_id.is_custom_derive(db.upcast()) || file_id.is_builtin_derive(db.upcast())) - }) - }; - - let parent = || { - match id { - AttrDefId::ModuleId(m) => m.containing_module(db).map(|v| v.into()), - AttrDefId::FunctionId(f) => Some(f.lookup(db).container.into()), - AttrDefId::StaticId(sid) => Some(sid.lookup(db).container.into()), - AttrDefId::ConstId(cid) => Some(cid.lookup(db).container.into()), - AttrDefId::TraitId(tid) => Some(tid.lookup(db).container.into()), - AttrDefId::TraitAliasId(taid) => Some(taid.lookup(db).container.into()), - AttrDefId::ImplId(iid) => Some(iid.lookup(db).container.into()), - AttrDefId::ExternBlockId(id) => Some(id.lookup(db).container.into()), - AttrDefId::ExternCrateId(id) => Some(id.lookup(db).container.into()), - AttrDefId::UseId(id) => Some(id.lookup(db).container.into()), - // These warnings should not explore macro definitions at all - AttrDefId::MacroId(_) => None, - AttrDefId::AdtId(aid) => match aid { - AdtId::StructId(sid) => Some(sid.lookup(db).container.into()), - AdtId::EnumId(eid) => Some(eid.lookup(db).container.into()), - // Unions aren't yet supported - AdtId::UnionId(_) => None, - }, - AttrDefId::FieldId(_) => None, - AttrDefId::EnumVariantId(_) => None, - AttrDefId::TypeAliasId(_) => None, - AttrDefId::GenericParamId(_) => None, - } - .is_some_and(|mid| self.allowed(mid, allow_name, true)) - }; - is_allowed(id) - // FIXME: this is a hack to avoid false positives in derive macros currently - || file_id_is_derive() - // go upwards one step or give up - || parent() - } - fn validate_module(&mut self, module_id: ModuleId) { - // Check whether non-snake case identifiers are allowed for this module. - if self.allowed(module_id.into(), allow::NON_SNAKE_CASE, false) { - return; - } - // Check the module name. let Some(module_name) = module_id.name(self.db.upcast()) else { return }; let Some(module_name_replacement) = @@ -270,11 +177,6 @@ impl<'a> DeclValidator<'a> { } fn validate_trait(&mut self, trait_id: TraitId) { - // Check whether non-snake case identifiers are allowed for this trait. - if self.allowed(trait_id.into(), allow::NON_CAMEL_CASE_TYPES, false) { - return; - } - // Check the trait name. let data = self.db.trait_data(trait_id); self.create_incorrect_case_diagnostic_for_item_name( @@ -292,21 +194,24 @@ impl<'a> DeclValidator<'a> { return; } - // Check whether non-snake case identifiers are allowed for this function. - if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) { - return; - } - // Check the function name. // Skipped if function is an associated item of a trait implementation. if !self.is_trait_impl_container(container) { let data = self.db.function_data(func); - self.create_incorrect_case_diagnostic_for_item_name( - func, - &data.name, - CaseType::LowerSnakeCase, - IdentType::Function, - ); + + // Don't run the lint on extern "[not Rust]" fn items with the + // #[no_mangle] attribute. + let no_mangle = data.attrs.by_key(&sym::no_mangle).exists(); + if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) { + cov_mark::hit!(extern_func_no_mangle_ignored); + } else { + self.create_incorrect_case_diagnostic_for_item_name( + func, + &data.name, + CaseType::LowerSnakeCase, + IdentType::Function, + ); + } } else { cov_mark::hit!(trait_impl_assoc_func_name_incorrect_case_ignored); } @@ -389,17 +294,13 @@ impl<'a> DeclValidator<'a> { fn validate_struct(&mut self, struct_id: StructId) { // Check the structure name. - let non_camel_case_allowed = - self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES, false); - if !non_camel_case_allowed { - let data = self.db.struct_data(struct_id); - self.create_incorrect_case_diagnostic_for_item_name( - struct_id, - &data.name, - CaseType::UpperCamelCase, - IdentType::Structure, - ); - } + let data = self.db.struct_data(struct_id); + self.create_incorrect_case_diagnostic_for_item_name( + struct_id, + &data.name, + CaseType::UpperCamelCase, + IdentType::Structure, + ); // Check the field names. self.validate_struct_fields(struct_id); @@ -407,10 +308,6 @@ impl<'a> DeclValidator<'a> { /// Check incorrect names for struct fields. fn validate_struct_fields(&mut self, struct_id: StructId) { - if self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false) { - return; - } - let data = self.db.struct_data(struct_id); let VariantData::Record(fields) = data.variant_data.as_ref() else { return; @@ -484,11 +381,6 @@ impl<'a> DeclValidator<'a> { fn validate_enum(&mut self, enum_id: EnumId) { let data = self.db.enum_data(enum_id); - // Check whether non-camel case names are allowed for this enum. - if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) { - return; - } - // Check the enum name. self.create_incorrect_case_diagnostic_for_item_name( enum_id, @@ -653,10 +545,6 @@ impl<'a> DeclValidator<'a> { return; } - if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { - return; - } - let data = self.db.const_data(const_id); let Some(name) = &data.name else { return; @@ -676,10 +564,6 @@ impl<'a> DeclValidator<'a> { return; } - if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { - return; - } - self.create_incorrect_case_diagnostic_for_item_name( static_id, &data.name, @@ -695,11 +579,6 @@ impl<'a> DeclValidator<'a> { return; } - // Check whether non-snake case identifiers are allowed for this type alias. - if self.allowed(type_alias_id.into(), allow::NON_CAMEL_CASE_TYPES, false) { - return; - } - // Check the type alias name. let data = self.db.type_alias_data(type_alias_id); self.create_incorrect_case_diagnostic_for_item_name( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 3f54cdd20cee3..ff45c725c73cd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -5,6 +5,7 @@ use hir_def::{ body::Body, hir::{Expr, ExprId, UnaryOp}, resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, + type_ref::Rawness, DefWithBodyId, }; @@ -12,7 +13,10 @@ use crate::{ db::HirDatabase, utils::is_fn_unsafe_to_call, InferenceResult, Interner, TyExt, TyKind, }; -pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { +/// Returns `(unsafe_exprs, fn_is_unsafe)`. +/// +/// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`. +pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec, bool) { let _p = tracing::info_span!("missing_unsafe").entered(); let mut res = Vec::new(); @@ -23,9 +27,6 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { | DefWithBodyId::VariantId(_) | DefWithBodyId::InTypeConstId(_) => false, }; - if is_unsafe { - return res; - } let body = db.body(def); let infer = db.infer(def); @@ -35,7 +36,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { } }); - res + (res, is_unsafe) } pub struct UnsafeExpr { @@ -87,12 +88,20 @@ fn walk_unsafe( let g = resolver.update_to_inner_scope(db.upcast(), def, current); let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path); if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { - if db.static_data(id).mutable { + let static_data = db.static_data(id); + if static_data.mutable || static_data.is_extern { unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); } } resolver.reset_to_guard(g); } + Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { + if let Expr::Path(_) = body.exprs[*expr] { + // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, + // see https://github.com/rust-lang/rust/pull/125834. + return; + } + } Expr::MethodCall { .. } => { if infer .method_resolution(current) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index a96c101a388be..89ca707c2e697 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -225,6 +225,23 @@ impl Generics { } } +pub(crate) fn trait_self_param_idx(db: &dyn DefDatabase, def: GenericDefId) -> Option { + match def { + GenericDefId::TraitId(_) | GenericDefId::TraitAliasId(_) => { + let params = db.generic_params(def); + params.trait_self_param().map(|idx| idx.into_raw().into_u32() as usize) + } + GenericDefId::ImplId(_) => None, + _ => { + let parent_def = parent_generic_def(db, def)?; + let parent_params = db.generic_params(parent_def); + let parent_self_idx = parent_params.trait_self_param()?.into_raw().into_u32() as usize; + let self_params = db.generic_params(def); + Some(self_params.len() + parent_self_idx) + } + } +} + fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { let container = match def { GenericDefId::FunctionId(it) => it.lookup(db).container, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 062ea278151bb..8bc3c50725d99 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -13,7 +13,7 @@ //! to certain types. To record this, we use the union-find implementation from //! the `ena` crate, which is extracted from rustc. -mod cast; +pub(crate) mod cast; pub(crate) mod closure; mod coerce; mod expr; @@ -76,7 +76,7 @@ pub use coerce::could_coerce; #[allow(unreachable_pub)] pub use unify::{could_unify, could_unify_deeply}; -use cast::CastCheck; +use cast::{CastCheck, CastError}; pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; /// The entry point of type inference. @@ -254,6 +254,16 @@ pub enum InferenceDiagnostic { expr: ExprId, expected: Ty, }, + CastToUnsized { + expr: ExprId, + cast_ty: Ty, + }, + InvalidCast { + expr: ExprId, + error: CastError, + expr_ty: Ty, + cast_ty: Ty, + }, } /// A mismatch between an expected and an inferred type. @@ -456,6 +466,7 @@ pub struct InferenceResult { pub(crate) closure_info: FxHashMap, FnTrait)>, // FIXME: remove this field pub mutated_bindings_in_closure: FxHashSet, + pub coercion_casts: FxHashSet, } impl InferenceResult { @@ -666,7 +677,7 @@ impl<'a> InferenceContext<'a> { let InferenceContext { mut table, mut result, - deferred_cast_checks, + mut deferred_cast_checks, tuple_field_accesses_rev, .. } = self; @@ -695,15 +706,25 @@ impl<'a> InferenceContext<'a> { closure_info: _, mutated_bindings_in_closure: _, tuple_field_access_types: _, + coercion_casts, } = &mut result; - table.fallback_if_possible(); // Comment from rustc: // 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. - for cast in deferred_cast_checks { - cast.check(&mut table); + let mut apply_adjustments = |expr, adj| { + expr_adjustments.insert(expr, adj); + }; + let mut set_coercion_cast = |expr| { + coercion_casts.insert(expr); + }; + for cast in deferred_cast_checks.iter_mut() { + if let Err(diag) = + cast.check(&mut table, &mut apply_adjustments, &mut set_coercion_cast) + { + diagnostics.push(diag); + } } // FIXME resolve obligations as well (use Guidance if necessary) @@ -732,7 +753,7 @@ impl<'a> InferenceContext<'a> { *has_errors = *has_errors || ty.contains_unknown(); } - *has_errors = !type_mismatches.is_empty(); + *has_errors |= !type_mismatches.is_empty(); type_mismatches.retain(|_, mismatch| { mismatch.expected = table.resolve_completely(mismatch.expected.clone()); @@ -775,20 +796,30 @@ impl<'a> InferenceContext<'a> { }); for (_, subst) in method_resolutions.values_mut() { *subst = table.resolve_completely(subst.clone()); + *has_errors = + *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); } for (_, subst) in assoc_resolutions.values_mut() { *subst = table.resolve_completely(subst.clone()); + *has_errors = + *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); } for adjustment in expr_adjustments.values_mut().flatten() { adjustment.target = table.resolve_completely(adjustment.target.clone()); + *has_errors = *has_errors || adjustment.target.contains_unknown(); } for adjustment in pat_adjustments.values_mut().flatten() { *adjustment = table.resolve_completely(adjustment.clone()); + *has_errors = *has_errors || adjustment.contains_unknown(); } result.tuple_field_access_types = tuple_field_accesses_rev .into_iter() .enumerate() .map(|(idx, subst)| (TupleId(idx as u32), table.resolve_completely(subst))) + .inspect(|(_, subst)| { + *has_errors = + *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); + }) .collect(); result } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index 060b5f36f292d..caa3960a227cf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -1,47 +1,451 @@ //! Type cast logic. Basically coercion + additional casts. -use crate::{infer::unify::InferenceTable, Interner, Ty, TyExt, TyKind}; +use chalk_ir::{Mutability, Scalar, TyVariableKind, UintTy}; +use hir_def::{hir::ExprId, AdtId}; +use stdx::never; + +use crate::{ + infer::unify::InferenceTable, Adjustment, Binders, DynTy, InferenceDiagnostic, Interner, + PlaceholderIndex, QuantifiedWhereClauses, Ty, TyExt, TyKind, TypeFlags, WhereClause, +}; + +#[derive(Debug)] +pub(crate) enum Int { + I, + U(UintTy), + Bool, + Char, + CEnum, + InferenceVar, +} + +#[derive(Debug)] +pub(crate) enum CastTy { + Int(Int), + Float, + FnPtr, + Ptr(Ty, Mutability), + // `DynStar` is Not supported yet in r-a +} + +impl CastTy { + pub(crate) fn from_ty(table: &mut InferenceTable<'_>, t: &Ty) -> Option { + match t.kind(Interner) { + TyKind::Scalar(Scalar::Bool) => Some(Self::Int(Int::Bool)), + TyKind::Scalar(Scalar::Char) => Some(Self::Int(Int::Char)), + TyKind::Scalar(Scalar::Int(_)) => Some(Self::Int(Int::I)), + TyKind::Scalar(Scalar::Uint(it)) => Some(Self::Int(Int::U(*it))), + TyKind::InferenceVar(_, TyVariableKind::Integer) => Some(Self::Int(Int::InferenceVar)), + TyKind::InferenceVar(_, TyVariableKind::Float) => Some(Self::Float), + TyKind::Scalar(Scalar::Float(_)) => Some(Self::Float), + TyKind::Adt(..) => { + let (AdtId::EnumId(id), _) = t.as_adt()? else { + return None; + }; + let enum_data = table.db.enum_data(id); + if enum_data.is_payload_free(table.db.upcast()) { + Some(Self::Int(Int::CEnum)) + } else { + None + } + } + TyKind::Raw(m, ty) => Some(Self::Ptr(table.resolve_ty_shallow(ty), *m)), + TyKind::Function(_) => Some(Self::FnPtr), + _ => None, + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum CastError { + Unknown, + CastToBool, + CastToChar, + DifferingKinds, + SizedUnsizedCast, + IllegalCast, + IntToFatCast, + NeedDeref, + NeedViaPtr, + NeedViaThinPtr, + NeedViaInt, + NonScalar, + UnknownCastPtrKind, + UnknownExprPtrKind, +} + +impl CastError { + fn into_diagnostic(self, expr: ExprId, expr_ty: Ty, cast_ty: Ty) -> InferenceDiagnostic { + InferenceDiagnostic::InvalidCast { expr, error: self, expr_ty, cast_ty } + } +} #[derive(Clone, Debug)] pub(super) struct CastCheck { + expr: ExprId, + source_expr: ExprId, expr_ty: Ty, cast_ty: Ty, } impl CastCheck { - pub(super) fn new(expr_ty: Ty, cast_ty: Ty) -> Self { - Self { expr_ty, cast_ty } + pub(super) fn new(expr: ExprId, source_expr: ExprId, expr_ty: Ty, cast_ty: Ty) -> Self { + Self { expr, source_expr, expr_ty, cast_ty } } - pub(super) fn check(self, table: &mut InferenceTable<'_>) { - // FIXME: This function currently only implements the bits that influence the type - // inference. We should return the adjustments on success and report diagnostics on error. - let expr_ty = table.resolve_ty_shallow(&self.expr_ty); - let cast_ty = table.resolve_ty_shallow(&self.cast_ty); + pub(super) fn check( + &mut self, + table: &mut InferenceTable<'_>, + apply_adjustments: &mut F, + set_coercion_cast: &mut G, + ) -> Result<(), InferenceDiagnostic> + where + F: FnMut(ExprId, Vec), + G: FnMut(ExprId), + { + table.resolve_obligations_as_possible(); + self.expr_ty = table.resolve_ty_shallow(&self.expr_ty); + self.cast_ty = table.resolve_ty_shallow(&self.cast_ty); + + if self.expr_ty.contains_unknown() || self.cast_ty.contains_unknown() { + return Ok(()); + } + + if !self.cast_ty.data(Interner).flags.contains(TypeFlags::HAS_TY_INFER) + && !table.is_sized(&self.cast_ty) + { + return Err(InferenceDiagnostic::CastToUnsized { + expr: self.expr, + cast_ty: self.cast_ty.clone(), + }); + } - if table.coerce(&expr_ty, &cast_ty).is_ok() { - return; + // Chalk doesn't support trait upcasting and fails to solve some obvious goals + // when the trait environment contains some recursive traits (See issue #18047) + // We skip cast checks for such cases for now, until the next-gen solver. + if contains_dyn_trait(&self.cast_ty) { + return Ok(()); } - if check_ref_to_ptr_cast(expr_ty, cast_ty, table) { - // Note that this type of cast is actually split into a coercion to a - // pointer type and a cast: - // &[T; N] -> *[T; N] -> *T + if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty) { + apply_adjustments(self.source_expr, adj); + set_coercion_cast(self.source_expr); + return Ok(()); } - // FIXME: Check other kinds of non-coercion casts and report error if any? + self.do_check(table, apply_adjustments) + .map_err(|e| e.into_diagnostic(self.expr, self.expr_ty.clone(), self.cast_ty.clone())) + } + + fn do_check( + &self, + table: &mut InferenceTable<'_>, + apply_adjustments: &mut F, + ) -> Result<(), CastError> + where + F: FnMut(ExprId, Vec), + { + let (t_from, t_cast) = + match (CastTy::from_ty(table, &self.expr_ty), CastTy::from_ty(table, &self.cast_ty)) { + (Some(t_from), Some(t_cast)) => (t_from, t_cast), + (None, Some(t_cast)) => match self.expr_ty.kind(Interner) { + TyKind::FnDef(..) => { + let sig = self.expr_ty.callable_sig(table.db).expect("FnDef had no sig"); + let sig = table.normalize_associated_types_in(sig); + let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner); + if let Ok((adj, _)) = table.coerce(&self.expr_ty, &fn_ptr) { + apply_adjustments(self.source_expr, adj); + } else { + return Err(CastError::IllegalCast); + } + + (CastTy::FnPtr, t_cast) + } + TyKind::Ref(mutbl, _, inner_ty) => { + let inner_ty = table.resolve_ty_shallow(inner_ty); + return match t_cast { + CastTy::Int(_) | CastTy::Float => match inner_ty.kind(Interner) { + TyKind::Scalar( + Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_), + ) + | TyKind::InferenceVar( + _, + TyVariableKind::Integer | TyVariableKind::Float, + ) => Err(CastError::NeedDeref), + + _ => Err(CastError::NeedViaPtr), + }, + // array-ptr-cast + CastTy::Ptr(t, m) => { + let t = table.resolve_ty_shallow(&t); + if !table.is_sized(&t) { + return Err(CastError::IllegalCast); + } + self.check_ref_cast( + table, + &inner_ty, + *mutbl, + &t, + m, + apply_adjustments, + ) + } + _ => Err(CastError::NonScalar), + }; + } + _ => return Err(CastError::NonScalar), + }, + _ => return Err(CastError::NonScalar), + }; + + // rustc checks whether the `expr_ty` is foreign adt with `non_exhaustive` sym + + match (t_from, t_cast) { + (_, CastTy::Int(Int::CEnum) | CastTy::FnPtr) => Err(CastError::NonScalar), + (_, CastTy::Int(Int::Bool)) => Err(CastError::CastToBool), + (CastTy::Int(Int::U(UintTy::U8)), CastTy::Int(Int::Char)) => Ok(()), + (_, CastTy::Int(Int::Char)) => Err(CastError::CastToChar), + (CastTy::Int(Int::Bool | Int::CEnum | Int::Char), CastTy::Float) => { + Err(CastError::NeedViaInt) + } + (CastTy::Int(Int::Bool | Int::CEnum | Int::Char) | CastTy::Float, CastTy::Ptr(..)) + | (CastTy::Ptr(..) | CastTy::FnPtr, CastTy::Float) => Err(CastError::IllegalCast), + (CastTy::Ptr(src, _), CastTy::Ptr(dst, _)) => { + self.check_ptr_ptr_cast(table, &src, &dst) + } + (CastTy::Ptr(src, _), CastTy::Int(_)) => self.check_ptr_addr_cast(table, &src), + (CastTy::Int(_), CastTy::Ptr(dst, _)) => self.check_addr_ptr_cast(table, &dst), + (CastTy::FnPtr, CastTy::Ptr(dst, _)) => self.check_fptr_ptr_cast(table, &dst), + (CastTy::Int(Int::CEnum), CastTy::Int(_)) => Ok(()), + (CastTy::Int(Int::Char | Int::Bool), CastTy::Int(_)) => Ok(()), + (CastTy::Int(_) | CastTy::Float, CastTy::Int(_) | CastTy::Float) => Ok(()), + (CastTy::FnPtr, CastTy::Int(_)) => Ok(()), + } + } + + fn check_ref_cast( + &self, + table: &mut InferenceTable<'_>, + t_expr: &Ty, + m_expr: Mutability, + t_cast: &Ty, + m_cast: Mutability, + apply_adjustments: &mut F, + ) -> Result<(), CastError> + where + F: FnMut(ExprId, Vec), + { + // Mutability order is opposite to rustc. `Mut < Not` + if m_expr <= m_cast { + if let TyKind::Array(ety, _) = t_expr.kind(Interner) { + // Coerce to a raw pointer so that we generate RawPtr in MIR. + let array_ptr_type = TyKind::Raw(m_expr, t_expr.clone()).intern(Interner); + if let Ok((adj, _)) = table.coerce(&self.expr_ty, &array_ptr_type) { + apply_adjustments(self.source_expr, adj); + } else { + never!( + "could not cast from reference to array to pointer to array ({:?} to {:?})", + self.expr_ty, + array_ptr_type + ); + } + + // This is a less strict condition than rustc's `demand_eqtype`, + // but false negative is better than false positive + if table.coerce(ety, t_cast).is_ok() { + return Ok(()); + } + } + } + + Err(CastError::IllegalCast) + } + + fn check_ptr_ptr_cast( + &self, + table: &mut InferenceTable<'_>, + src: &Ty, + dst: &Ty, + ) -> Result<(), CastError> { + let src_kind = pointer_kind(src, table).map_err(|_| CastError::Unknown)?; + let dst_kind = pointer_kind(dst, table).map_err(|_| CastError::Unknown)?; + + match (src_kind, dst_kind) { + (Some(PointerKind::Error), _) | (_, Some(PointerKind::Error)) => Ok(()), + (_, None) => Err(CastError::UnknownCastPtrKind), + (_, Some(PointerKind::Thin)) => Ok(()), + (None, _) => Err(CastError::UnknownExprPtrKind), + (Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast), + (Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => { + let principal = |tty: &Binders| { + tty.skip_binders().as_slice(Interner).first().and_then(|pred| { + if let WhereClause::Implemented(tr) = pred.skip_binders() { + Some(tr.trait_id) + } else { + None + } + }) + }; + match (principal(&src_tty), principal(&dst_tty)) { + (Some(src_principal), Some(dst_principal)) => { + if src_principal == dst_principal { + return Ok(()); + } + let src_principal = + table.db.trait_datum(table.trait_env.krate, src_principal); + let dst_principal = + table.db.trait_datum(table.trait_env.krate, dst_principal); + if src_principal.is_auto_trait() && dst_principal.is_auto_trait() { + Ok(()) + } else { + Err(CastError::DifferingKinds) + } + } + _ => Err(CastError::Unknown), + } + } + (Some(src_kind), Some(dst_kind)) if src_kind == dst_kind => Ok(()), + (_, _) => Err(CastError::DifferingKinds), + } + } + + fn check_ptr_addr_cast( + &self, + table: &mut InferenceTable<'_>, + expr_ty: &Ty, + ) -> Result<(), CastError> { + match pointer_kind(expr_ty, table).map_err(|_| CastError::Unknown)? { + None => Err(CastError::UnknownExprPtrKind), + Some(PointerKind::Error) => Ok(()), + Some(PointerKind::Thin) => Ok(()), + _ => Err(CastError::NeedViaThinPtr), + } + } + + fn check_addr_ptr_cast( + &self, + table: &mut InferenceTable<'_>, + cast_ty: &Ty, + ) -> Result<(), CastError> { + match pointer_kind(cast_ty, table).map_err(|_| CastError::Unknown)? { + None => Err(CastError::UnknownCastPtrKind), + Some(PointerKind::Error) => Ok(()), + Some(PointerKind::Thin) => Ok(()), + Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast), + Some(PointerKind::Length) => Err(CastError::IntToFatCast), + Some(PointerKind::OfAlias | PointerKind::OfParam(_)) => Err(CastError::IntToFatCast), + } + } + + fn check_fptr_ptr_cast( + &self, + table: &mut InferenceTable<'_>, + cast_ty: &Ty, + ) -> Result<(), CastError> { + match pointer_kind(cast_ty, table).map_err(|_| CastError::Unknown)? { + None => Err(CastError::UnknownCastPtrKind), + Some(PointerKind::Error) => Ok(()), + Some(PointerKind::Thin) => Ok(()), + _ => Err(CastError::IllegalCast), + } } } -fn check_ref_to_ptr_cast(expr_ty: Ty, cast_ty: Ty, table: &mut InferenceTable<'_>) -> bool { - let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else { - return false; - }; - let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else { - return false; - }; - let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else { - return false; +#[derive(PartialEq, Eq)] +enum PointerKind { + // thin pointer + Thin, + // trait object + VTable(Binders), + // slice + Length, + OfAlias, + OfParam(PlaceholderIndex), + Error, +} + +fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result, ()> { + let ty = table.resolve_ty_shallow(ty); + + if table.is_sized(&ty) { + return Ok(Some(PointerKind::Thin)); + } + + match ty.kind(Interner) { + TyKind::Slice(_) | TyKind::Str => Ok(Some(PointerKind::Length)), + TyKind::Dyn(DynTy { bounds, .. }) => Ok(Some(PointerKind::VTable(bounds.clone()))), + TyKind::Adt(chalk_ir::AdtId(id), subst) => { + let AdtId::StructId(id) = *id else { + never!("`{:?}` should be sized but is not?", ty); + return Err(()); + }; + + let struct_data = table.db.struct_data(id); + if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() { + let last_field_ty = + table.db.field_types(id.into())[last_field].clone().substitute(Interner, subst); + pointer_kind(&last_field_ty, table) + } else { + Ok(Some(PointerKind::Thin)) + } + } + TyKind::Tuple(_, subst) => { + match subst.iter(Interner).last().and_then(|arg| arg.ty(Interner)) { + None => Ok(Some(PointerKind::Thin)), + Some(ty) => pointer_kind(ty, table), + } + } + TyKind::Foreign(_) => Ok(Some(PointerKind::Thin)), + TyKind::Alias(_) | TyKind::AssociatedType(..) | TyKind::OpaqueType(..) => { + Ok(Some(PointerKind::OfAlias)) + } + TyKind::Error => Ok(Some(PointerKind::Error)), + TyKind::Placeholder(idx) => Ok(Some(PointerKind::OfParam(*idx))), + TyKind::BoundVar(_) | TyKind::InferenceVar(..) => Ok(None), + TyKind::Scalar(_) + | TyKind::Array(..) + | TyKind::CoroutineWitness(..) + | TyKind::Raw(..) + | TyKind::Ref(..) + | TyKind::FnDef(..) + | TyKind::Function(_) + | TyKind::Closure(..) + | TyKind::Coroutine(..) + | TyKind::Never => { + never!("`{:?}` should be sized but is not?", ty); + Err(()) + } + } +} + +fn contains_dyn_trait(ty: &Ty) -> bool { + use std::ops::ControlFlow; + + use chalk_ir::{ + visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, + DebruijnIndex, }; - table.coerce(expr_elt_ty, cast_inner_ty).is_ok() + + struct DynTraitVisitor; + + impl TypeVisitor for DynTraitVisitor { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor { + self + } + + fn interner(&self) -> Interner { + Interner + } + + fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow { + match ty.kind(Interner) { + TyKind::Dyn(_) => ControlFlow::Break(()), + _ => ty.super_visit_with(self.as_dyn(), outer_binder), + } + } + } + + ty.visit_with(DynTraitVisitor.as_dyn(), DebruijnIndex::INNERMOST).is_break() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 36327d1d49c0a..5cad08b93956e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -10,7 +10,10 @@ use chalk_ir::{ use either::Either; use hir_def::{ data::adt::VariantData, - hir::{Array, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement, UnaryOp}, + hir::{ + Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement, + UnaryOp, + }, lang_item::LangItem, resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, @@ -666,7 +669,21 @@ impl InferenceContext<'_> { fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) { match &self.body[tgt_expr] { Expr::OffsetOf(_) => (), - Expr::InlineAsm(e) => self.walk_expr_without_adjust(e.e), + Expr::InlineAsm(e) => e.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => self.walk_expr_without_adjust(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + self.walk_expr_without_adjust(*in_expr); + if let Some(out_expr) = out_expr { + self.walk_expr_without_adjust(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), Expr::If { condition, then_branch, else_branch } => { self.consume_expr(*condition); self.consume_expr(*then_branch); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 89d92ea9af0b9..a04e7b17ae6e1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -9,7 +9,8 @@ use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKin use either::Either; use hir_def::{ hir::{ - ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp, + ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, LabelId, + Literal, Statement, UnaryOp, }, lang_item::{LangItem, LangItemTarget}, path::{GenericArg, GenericArgs, Path}, @@ -41,9 +42,9 @@ use crate::{ primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, - Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnAbi, FnPointer, FnSig, - FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, - TyExt, TyKind, + Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, FnAbi, FnPointer, + FnSig, FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, + TyBuilder, TyExt, TyKind, }; use super::{ @@ -610,7 +611,12 @@ impl InferenceContext<'_> { Expr::Cast { expr, type_ref } => { let cast_ty = self.make_ty(type_ref); let expr_ty = self.infer_expr(*expr, &Expectation::Castable(cast_ty.clone())); - self.deferred_cast_checks.push(CastCheck::new(expr_ty, cast_ty.clone())); + self.deferred_cast_checks.push(CastCheck::new( + tgt_expr, + *expr, + expr_ty, + cast_ty.clone(), + )); cast_ty } Expr::Ref { expr, rawness, mutability } => { @@ -845,7 +851,7 @@ impl InferenceContext<'_> { }; for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { - self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); + *ty = self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); } TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner) @@ -889,21 +895,52 @@ impl InferenceContext<'_> { TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty))) .intern(Interner) } - None => self.table.new_integer_var(), + None => { + let expected_ty = expected.to_option(&mut self.table); + let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) { + Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty, + Some(TyKind::Scalar(Scalar::Char)) => { + Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner)) + } + Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => { + Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner)) + } + _ => None, + }; + opt_ty.unwrap_or_else(|| self.table.new_integer_var()) + } }, Literal::Uint(_v, ty) => match ty { Some(int_ty) => { TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty))) .intern(Interner) } - None => self.table.new_integer_var(), + None => { + let expected_ty = expected.to_option(&mut self.table); + let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) { + Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty, + Some(TyKind::Scalar(Scalar::Char)) => { + Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner)) + } + Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => { + Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner)) + } + _ => None, + }; + opt_ty.unwrap_or_else(|| self.table.new_integer_var()) + } }, Literal::Float(_v, ty) => match ty { Some(float_ty) => { TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty))) .intern(Interner) } - None => self.table.new_float_var(), + None => { + let opt_ty = expected.to_option(&mut self.table).filter(|ty| { + matches!(ty.kind(Interner), TyKind::Scalar(Scalar::Float(_))) + }); + opt_ty.unwrap_or_else(|| self.table.new_float_var()) + } }, }, Expr::Underscore => { @@ -919,9 +956,61 @@ impl InferenceContext<'_> { expected } Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner), - Expr::InlineAsm(it) => { - self.infer_expr_no_expect(it.e); - self.result.standard_types.unit.clone() + Expr::InlineAsm(asm) => { + let mut check_expr_asm_operand = |expr, is_input: bool| { + let ty = self.infer_expr_no_expect(expr); + + // If this is an input value, we require its type to be fully resolved + // at this point. This allows us to provide helpful coercions which help + // pass the type candidate list in a later pass. + // + // We don't require output types to be resolved at this point, which + // allows them to be inferred based on how they are used later in the + // function. + if is_input { + let ty = self.resolve_ty_shallow(&ty); + match ty.kind(Interner) { + TyKind::FnDef(def, parameters) => { + let fnptr_ty = TyKind::Function( + CallableSig::from_def(self.db, *def, parameters).to_fn_ptr(), + ) + .intern(Interner); + _ = self.coerce(Some(expr), &ty, &fnptr_ty); + } + TyKind::Ref(mutbl, _, base_ty) => { + let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner); + _ = self.coerce(Some(expr), &ty, &ptr_ty); + } + _ => {} + } + } + }; + + let diverge = asm.options.contains(AsmOptions::NORETURN); + asm.operands.iter().for_each(|(_, operand)| match *operand { + AsmOperand::In { expr, .. } => check_expr_asm_operand(expr, true), + AsmOperand::Out { expr: Some(expr), .. } | AsmOperand::InOut { expr, .. } => { + check_expr_asm_operand(expr, false) + } + AsmOperand::Out { expr: None, .. } => (), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + check_expr_asm_operand(in_expr, true); + if let Some(out_expr) = out_expr { + check_expr_asm_operand(out_expr, false); + } + } + // FIXME + AsmOperand::Label(_) => (), + // FIXME + AsmOperand::Const(_) => (), + // FIXME + AsmOperand::Sym(_) => (), + }); + if diverge { + self.result.standard_types.never.clone() + } else { + self.result.standard_types.unit.clone() + } } }; // use a new type variable if we got unknown here diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 7fed5f0203bad..8e52725e53600 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -3,7 +3,9 @@ use chalk_ir::{cast::Cast, Mutability}; use hir_def::{ - hir::{Array, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp}, + hir::{ + Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp, + }, lang_item::LangItem, }; use hir_expand::name::Name; @@ -39,7 +41,25 @@ impl InferenceContext<'_> { fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) { match &self.body[tgt_expr] { Expr::Missing => (), - Expr::InlineAsm(e) => self.infer_mut_expr_without_adjust(e.e, Mutability::Not), + Expr::InlineAsm(e) => { + e.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => { + self.infer_mut_expr_without_adjust(*expr, Mutability::Not) + } + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + self.infer_mut_expr_without_adjust(*in_expr, Mutability::Not); + if let Some(out_expr) = out_expr { + self.infer_mut_expr_without_adjust(*out_expr, Mutability::Not); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Label(_) + | AsmOperand::Sym(_) + | AsmOperand::Const(_) => (), + }); + } Expr::OffsetOf(_) => (), &Expr::If { condition, then_branch, else_branch } => { self.infer_mut_expr(condition, Mutability::Not); @@ -129,7 +149,7 @@ impl InferenceContext<'_> { target, }) = base_adjustments { - // For assignee exprs `IndexMut` obiligations are already applied + // For assignee exprs `IndexMut` obligations are already applied if !is_assignee_expr { if let TyKind::Ref(_, _, ty) = target.kind(Interner) { base_ty = Some(ty.clone()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 0b44bbec70f75..e4841c7b15b60 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -247,8 +247,12 @@ impl InferenceContext<'_> { &self.resolver, self.owner.into(), ); - let trait_ref = - ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); + let trait_ref = ctx.lower_trait_ref_from_resolved_path( + trait_, + resolved_segment, + self.table.new_type_var(), + ); + self.resolve_trait_assoc_item(trait_ref, segment, id) } (def, _) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index c0f5ddddcbe3e..7300453ff0014 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -9,6 +9,7 @@ use chalk_ir::{ use chalk_solve::infer::ParameterEnaVariableExt; use either::Either; use ena::unify::UnifyKey; +use hir_def::{lang_item::LangItem, AdtId}; use hir_expand::name::Name; use intern::sym; use rustc_hash::FxHashMap; @@ -21,7 +22,7 @@ use crate::{ to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, - Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, + Solution, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause, }; @@ -265,14 +266,16 @@ impl<'a> InferenceTable<'a> { } let v = InferenceVar::from(i as u32); let root = self.var_unification_table.inference_var_root(v); - if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) { - *data |= TypeVariableFlags::DIVERGING; - } + self.modify_type_variable_flag(root, |f| { + *f |= TypeVariableFlags::DIVERGING; + }); } } pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { - self.type_variable_table[iv.index() as usize].set(TypeVariableFlags::DIVERGING, diverging); + self.modify_type_variable_flag(iv, |f| { + f.set(TypeVariableFlags::DIVERGING, diverging); + }); } fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { @@ -369,6 +372,18 @@ impl<'a> InferenceTable<'a> { var } + fn modify_type_variable_flag(&mut self, var: InferenceVar, cb: F) + where + F: FnOnce(&mut TypeVariableFlags), + { + let idx = var.index() as usize; + if self.type_variable_table.len() <= idx { + self.extend_type_variable_table(idx); + } + if let Some(f) = self.type_variable_table.get_mut(idx) { + cb(f); + } + } fn extend_type_variable_table(&mut self, to_index: usize) { let count = to_index - self.type_variable_table.len() + 1; self.type_variable_table.extend(iter::repeat(TypeVariableFlags::default()).take(count)); @@ -898,6 +913,37 @@ impl<'a> InferenceTable<'a> { _ => c, } } + + /// Check if given type is `Sized` or not + pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool { + // Early return for some obvious types + if matches!(ty.kind(Interner), TyKind::Scalar(..) | TyKind::Ref(..) | TyKind::Raw(..)) { + return true; + } + if let Some((AdtId::StructId(id), subst)) = ty.as_adt() { + let struct_data = self.db.struct_data(id); + if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() { + let last_field_ty = + self.db.field_types(id.into())[last_field].clone().substitute(Interner, subst); + // Structs can have DST as its last field and such cases are not handled + // as unsized by the chalk, so we do this manually + return self.is_sized(&last_field_ty); + } + } + let Some(sized) = self + .db + .lang_item(self.trait_env.krate, LangItem::Sized) + .and_then(|sized| sized.as_trait()) + else { + return false; + }; + let sized_pred = WhereClause::Implemented(TraitRef { + trait_id: to_chalk_trait_id(sized), + substitution: Substitution::from1(Interner, ty.clone()), + }); + let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner); + matches!(self.try_obligation(goal), Some(Solution::Unique(_))) + } } impl fmt::Debug for InferenceTable<'_> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 47cc2a2f1e6bd..4cdc0db46a15f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -1,13 +1,13 @@ //! Compute the binary representation of a type -use std::{borrow::Cow, fmt}; +use std::fmt; use base_db::salsa::Cycle; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ - Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, - Scalar, Size, StructKind, TargetDataLayout, WrappingRange, + Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS, + Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange, }, LocalFieldId, StructId, }; @@ -15,7 +15,6 @@ use la_arena::{Idx, RawIdx}; use rustc_abi::AddressSpace; use rustc_index::{IndexSlice, IndexVec}; -use stdx::never; use triomphe::Arc; use crate::{ @@ -73,6 +72,7 @@ pub type Variants = hir_def::layout::Variants) -> fmt::Result { match self { + LayoutError::EmptyUnion => write!(f, "type is an union with no fields"), LayoutError::HasErrorConst => write!(f, "type contains an unevaluatable const"), LayoutError::HasErrorType => write!(f, "type contains an error"), LayoutError::HasPlaceholder => write!(f, "type contains placeholders"), @@ -99,6 +101,9 @@ impl fmt::Display for LayoutError { } LayoutError::SizeOverflow => write!(f, "size overflow"), LayoutError::TargetLayoutNotAvailable => write!(f, "target layout not available"), + LayoutError::UnexpectedUnsized => { + write!(f, "an unsized type was found where a sized type was expected") + } LayoutError::Unknown => write!(f, "unknown"), LayoutError::UserReprTooSmall => { write!(f, "the `#[repr]` hint is too small to hold the discriminants of the enum") @@ -107,19 +112,23 @@ impl fmt::Display for LayoutError { } } -struct LayoutCx<'a> { - target: &'a TargetDataLayout, +impl From> for LayoutError { + fn from(err: LayoutCalculatorError) -> Self { + match err { + LayoutCalculatorError::EmptyUnion => LayoutError::EmptyUnion, + LayoutCalculatorError::UnexpectedUnsized(_) => LayoutError::UnexpectedUnsized, + LayoutCalculatorError::SizeOverflow => LayoutError::SizeOverflow, + } + } } -impl<'a> LayoutCalculator for LayoutCx<'a> { - type TargetDataLayoutRef = &'a TargetDataLayout; - - fn delayed_bug(&self, txt: impl Into>) { - never!("{}", txt.into()); - } +struct LayoutCx<'a> { + calc: LayoutCalculator<&'a TargetDataLayout>, +} - fn current_data_layout(&self) -> &'a TargetDataLayout { - self.target +impl<'a> LayoutCx<'a> { + fn new(target: &'a TargetDataLayout) -> Self { + Self { calc: LayoutCalculator::new(target) } } } @@ -205,8 +214,8 @@ pub fn layout_of_ty_query( let Ok(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable); }; - let cx = LayoutCx { target: &target }; - let dl = cx.current_data_layout(); + let dl = &*target; + let cx = LayoutCx::new(dl); let ty = normalize(db, trait_env.clone(), ty); let result = match ty.kind(Interner) { TyKind::Adt(AdtId(def), subst) => { @@ -281,7 +290,7 @@ pub fn layout_of_ty_query( .collect::, _>>()?; let fields = fields.iter().map(|it| &**it).collect::>(); let fields = fields.iter().collect::>(); - cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)? + cx.calc.univariant(&fields, &ReprOptions::default(), kind)? } TyKind::Array(element, count) => { let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64; @@ -367,12 +376,12 @@ pub fn layout_of_ty_query( }; // Effectively a (ptr, meta) tuple. - cx.scalar_pair(data_ptr, metadata) + cx.calc.scalar_pair(data_ptr, metadata) } - TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?, - TyKind::Never => cx.layout_of_never_type(), + TyKind::FnDef(_, _) => layout_of_unit(&cx)?, + TyKind::Never => cx.calc.layout_of_never_type(), TyKind::Dyn(_) | TyKind::Foreign(_) => { - let mut unit = layout_of_unit(&cx, dl)?; + let mut unit = layout_of_unit(&cx)?; match &mut unit.abi { Abi::Aggregate { sized } => *sized = false, _ => return Err(LayoutError::Unknown), @@ -414,8 +423,7 @@ pub fn layout_of_ty_query( .collect::, _>>()?; let fields = fields.iter().map(|it| &**it).collect::>(); let fields = fields.iter().collect::>(); - cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized) - .ok_or(LayoutError::Unknown)? + cx.calc.univariant(&fields, &ReprOptions::default(), StructKind::AlwaysSized)? } TyKind::Coroutine(_, _) | TyKind::CoroutineWitness(_, _) => { return Err(LayoutError::NotImplemented) @@ -447,14 +455,14 @@ pub fn layout_of_ty_recover( Err(LayoutError::RecursiveTypeWithoutIndirection) } -fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result { - cx.univariant::( - dl, - IndexSlice::empty(), - &ReprOptions::default(), - StructKind::AlwaysSized, - ) - .ok_or(LayoutError::Unknown) +fn layout_of_unit(cx: &LayoutCx<'_>) -> Result { + cx.calc + .univariant::( + IndexSlice::empty(), + &ReprOptions::default(), + StructKind::AlwaysSized, + ) + .map_err(Into::into) } fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index 3463e69097287..a060ebfe6be2a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -5,7 +5,7 @@ use std::{cmp, ops::Bound}; use base_db::salsa::Cycle; use hir_def::{ data::adt::VariantData, - layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout}, + layout::{Integer, ReprOptions, TargetDataLayout}, AdtId, VariantId, }; use intern::sym; @@ -36,8 +36,8 @@ pub fn layout_of_adt_query( let Ok(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable); }; - let cx = LayoutCx { target: &target }; - let dl = cx.current_data_layout(); + let dl = &*target; + let cx = LayoutCx::new(dl); let handle_variant = |def: VariantId, var: &VariantData| { var.fields() .iter() @@ -73,9 +73,9 @@ pub fn layout_of_adt_query( .collect::>(); let variants = variants.iter().map(|it| it.iter().collect()).collect::>(); let result = if matches!(def, AdtId::UnionId(..)) { - cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)? + cx.calc.layout_of_union(&repr, &variants)? } else { - cx.layout_of_struct_or_enum( + cx.calc.layout_of_struct_or_enum( &repr, &variants, matches!(def, AdtId::EnumId(..)), @@ -103,8 +103,7 @@ pub fn layout_of_adt_query( .next() .and_then(|it| it.iter().last().map(|it| !it.is_unsized())) .unwrap_or(true), - ) - .ok_or(LayoutError::SizeOverflow)? + )? }; Ok(Arc::new(result)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs index 9b1424548c2a9..7d77f6d0731a3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs @@ -11,8 +11,8 @@ pub fn target_data_layout_query( db: &dyn HirDatabase, krate: CrateId, ) -> Result, Arc> { - match db.data_layout(krate) { - Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(&it) { + match &db.crate_workspace_data()[&krate].data_layout { + Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(it) { Ok(it) => Ok(Arc::new(it)), Err(e) => { Err(match e { @@ -42,6 +42,6 @@ pub fn target_data_layout_query( }.into()) } }, - Err(e) => Err(e), + Err(e) => Err(e.clone()), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 2f4e764f4cecf..5ed41b99ba3e7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -42,6 +42,7 @@ pub mod lang_items; pub mod layout; pub mod method_resolution; pub mod mir; +pub mod object_safety; pub mod primitive; pub mod traits; @@ -82,6 +83,7 @@ pub use autoderef::autoderef; pub use builder::{ParamKind, TyBuilder}; pub use chalk_ext::*; pub use infer::{ + cast::CastError, closure::{CaptureKind, CapturedItem}, could_coerce, could_unify, could_unify_deeply, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast, @@ -377,6 +379,7 @@ pub enum FnAbi { AvrNonBlockingInterrupt, C, CCmseNonsecureCall, + CCmseNonsecureEntry, CDecl, CDeclUnwind, CUnwind, @@ -434,6 +437,7 @@ impl FnAbi { s if *s == sym::avr_dash_interrupt => FnAbi::AvrInterrupt, s if *s == sym::avr_dash_non_dash_blocking_dash_interrupt => FnAbi::AvrNonBlockingInterrupt, s if *s == sym::C_dash_cmse_dash_nonsecure_dash_call => FnAbi::CCmseNonsecureCall, + s if *s == sym::C_dash_cmse_dash_nonsecure_dash_entry => FnAbi::CCmseNonsecureEntry, s if *s == sym::C_dash_unwind => FnAbi::CUnwind, s if *s == sym::C => FnAbi::C, s if *s == sym::cdecl_dash_unwind => FnAbi::CDeclUnwind, @@ -477,6 +481,7 @@ impl FnAbi { FnAbi::AvrNonBlockingInterrupt => "avr-non-blocking-interrupt", FnAbi::C => "C", FnAbi::CCmseNonsecureCall => "C-cmse-nonsecure-call", + FnAbi::CCmseNonsecureEntry => "C-cmse-nonsecure-entry", FnAbi::CDecl => "C-decl", FnAbi::CDeclUnwind => "cdecl-unwind", FnAbi::CUnwind => "C-unwind", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 370d9ba99cb0c..c6c2108e34af4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -58,7 +58,7 @@ use crate::{ }, db::HirDatabase, error_lifetime, - generics::{generics, Generics}, + generics::{generics, trait_self_param_idx, Generics}, make_binders, mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, @@ -516,8 +516,11 @@ impl<'a> TyLoweringContext<'a> { TypeNs::TraitId(trait_) => { let ty = match remaining_segments.len() { 1 => { - let trait_ref = - self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); + let trait_ref = self.lower_trait_ref_from_resolved_path( + trait_, + resolved_segment, + TyKind::Error.intern(Interner), + ); let segment = remaining_segments.first().unwrap(); let found = self .db @@ -952,11 +955,17 @@ impl<'a> TyLoweringContext<'a> { Substitution::from_iter(Interner, substs) } - fn lower_trait_ref_from_path( + pub(crate) fn lower_trait_ref_from_resolved_path( &self, - path: &Path, - explicit_self_ty: Option, - ) -> Option { + resolved: TraitId, + segment: PathSegment<'_>, + explicit_self_ty: Ty, + ) -> TraitRef { + let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty); + TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } + } + + fn lower_trait_ref_from_path(&self, path: &Path, explicit_self_ty: Ty) -> Option { let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? { // FIXME(trait_alias): We need to handle trait alias here. TypeNs::TraitId(tr) => tr, @@ -966,21 +975,7 @@ impl<'a> TyLoweringContext<'a> { Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty)) } - pub(crate) fn lower_trait_ref_from_resolved_path( - &self, - resolved: TraitId, - segment: PathSegment<'_>, - explicit_self_ty: Option, - ) -> TraitRef { - let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty); - TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } - } - - fn lower_trait_ref( - &self, - trait_ref: &HirTraitRef, - explicit_self_ty: Option, - ) -> Option { + fn lower_trait_ref(&self, trait_ref: &HirTraitRef, explicit_self_ty: Ty) -> Option { self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty) } @@ -988,9 +983,9 @@ impl<'a> TyLoweringContext<'a> { &self, segment: PathSegment<'_>, resolved: TraitId, - explicit_self_ty: Option, + explicit_self_ty: Ty, ) -> Substitution { - self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty) + self.substs_from_path_segment(segment, Some(resolved.into()), false, Some(explicit_self_ty)) } pub(crate) fn lower_where_predicate<'b>( @@ -1041,7 +1036,7 @@ impl<'a> TyLoweringContext<'a> { let mut trait_ref = None; let clause = match bound.as_ref() { TypeBound::Path(path, TraitBoundModifier::None) => { - trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty)); + trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) } TypeBound::Path(path, TraitBoundModifier::Maybe) => { @@ -1053,7 +1048,7 @@ impl<'a> TyLoweringContext<'a> { // `?Sized` has no of them. // If we got another trait here ignore the bound completely. let trait_id = self - .lower_trait_ref_from_path(path, Some(self_ty.clone())) + .lower_trait_ref_from_path(path, self_ty.clone()) .map(|trait_ref| trait_ref.hir_trait_id()); if trait_id == sized_trait { self.unsized_types.borrow_mut().insert(self_ty); @@ -1062,7 +1057,7 @@ impl<'a> TyLoweringContext<'a> { } TypeBound::ForLifetime(_, path) => { // FIXME Don't silently drop the hrtb lifetimes here - trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty)); + trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) } TypeBound::Lifetime(l) => { @@ -1700,6 +1695,28 @@ pub(crate) fn generic_predicates_query( db: &dyn HirDatabase, def: GenericDefId, ) -> GenericPredicates { + generic_predicates_filtered_by(db, def, |_, _| true) +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +pub(crate) fn generic_predicates_without_parent_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> GenericPredicates { + generic_predicates_filtered_by(db, def, |_, d| *d == def) +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +fn generic_predicates_filtered_by( + db: &dyn HirDatabase, + def: GenericDefId, + filter: F, +) -> GenericPredicates +where + F: Fn(&WherePredicate, &GenericDefId) -> bool, +{ let resolver = def.resolver(db.upcast()); let (impl_trait_lowering, param_lowering) = match def { GenericDefId::FunctionId(_) => { @@ -1714,6 +1731,7 @@ pub(crate) fn generic_predicates_query( let mut predicates = resolver .where_predicates_in_scope() + .filter(|(pred, def)| filter(pred, def)) .flat_map(|(pred, def)| { ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p)) }) @@ -1747,21 +1765,7 @@ fn implicitly_sized_clauses<'a, 'subst: 'a>( .lang_item(resolver.krate(), LangItem::Sized) .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id))?; - let get_trait_self_idx = |container: ItemContainerId| { - if matches!(container, ItemContainerId::TraitId(_)) { - let generics = generics(db.upcast(), def); - Some(generics.len_self()) - } else { - None - } - }; - let trait_self_idx = match def { - GenericDefId::TraitId(_) => Some(0), - GenericDefId::FunctionId(it) => get_trait_self_idx(it.lookup(db.upcast()).container), - GenericDefId::ConstId(it) => get_trait_self_idx(it.lookup(db.upcast()).container), - GenericDefId::TypeAliasId(it) => get_trait_self_idx(it.lookup(db.upcast()).container), - _ => None, - }; + let trait_self_idx = trait_self_param_idx(db.upcast(), def); Some( substitution @@ -2117,7 +2121,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option< .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; - Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?)) + Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?)) } pub(crate) fn return_type_impl_traits( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 22d4da0e755ae..8e815aabf2070 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -185,8 +185,8 @@ impl ProjectionElem { never!("Out of bound tuple field"); TyKind::Error.intern(Interner) }), - _ => { - never!("Only tuple has tuple field"); + ty => { + never!("Only tuple has tuple field: {:?}", ty); TyKind::Error.intern(Interner) } }, @@ -837,7 +837,9 @@ pub enum CastKind { PointerFromExposedAddress, /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are /// translated into `&raw mut/const *r`, i.e., they are not actually casts. - Pointer(PointerCast), + PtrToPtr, + /// Pointer related casts that are done by coercions. + PointerCoercion(PointerCast), /// Cast into a dyn* object. DynStar, IntToInt, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 1bb0c1886857a..0d42617d185c4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -421,9 +421,25 @@ impl MirEvalError { } MirEvalError::MirLowerError(func, err) => { let function_name = db.function_data(*func); + let self_ = match func.lookup(db.upcast()).container { + ItemContainerId::ImplId(impl_id) => Some({ + let generics = crate::generics::generics(db.upcast(), impl_id.into()); + let substs = generics.placeholder_subst(db); + db.impl_self_ty(impl_id) + .substitute(Interner, &substs) + .display(db, edition) + .to_string() + }), + ItemContainerId::TraitId(it) => { + Some(db.trait_data(it).name.display(db.upcast(), edition).to_string()) + } + _ => None, + }; writeln!( f, - "MIR lowering for function `{}` ({:?}) failed due:", + "MIR lowering for function `{}{}{}` ({:?}) failed due:", + self_.as_deref().unwrap_or_default(), + if self_.is_some() { "::" } else { "" }, function_name.name.display(db.upcast(), edition), func )?; @@ -1475,7 +1491,7 @@ impl Evaluator<'_> { } } Rvalue::Cast(kind, operand, target_ty) => match kind { - CastKind::Pointer(cast) => match cast { + CastKind::PointerCoercion(cast) => match cast { PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => { let current_ty = self.operand_ty(operand, locals)?; if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) = @@ -1506,6 +1522,7 @@ impl Evaluator<'_> { }, CastKind::DynStar => not_supported!("dyn star cast"), CastKind::IntToInt + | CastKind::PtrToPtr | CastKind::PointerExposeAddress | CastKind::PointerFromExposedAddress => { let current_ty = self.operand_ty(operand, locals)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 371a5278dc9a5..595a78da10fb9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -399,7 +399,7 @@ extern "C" { fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; } -fn my_cmp(x: &[u8], y: &[u8]) -> i32 { +fn my_cmp(x: &[u8; 3], y: &[u8; 3]) -> i32 { memcmp(x as *const u8, y as *const u8, x.len()) } @@ -779,6 +779,7 @@ fn main() { fn posix_getenv() { check_pass( r#" +//- minicore: sized //- /main.rs env:foo=bar type c_char = u8; @@ -849,7 +850,7 @@ fn main() { fn regression_14966() { check_pass( r#" -//- minicore: fn, copy, coerce_unsized +//- minicore: fn, copy, coerce_unsized, dispatch_from_dyn trait A { fn a(&self) {} } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 9e235504519e2..a2cb122c54391 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -31,7 +31,7 @@ use crate::{ display::HirDisplay, error_lifetime, generics::generics, - infer::{CaptureKind, CapturedItem, TypeMismatch}, + infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch}, inhabitedness::is_ty_uninhabited_from, layout::LayoutError, mapping::ToChalk, @@ -94,7 +94,8 @@ pub enum MirLowerError { UnresolvedField, UnsizedTemporary(Ty), MissingFunctionDefinition(DefWithBodyId, ExprId), - TypeMismatch(Option), + TypeMismatch(TypeMismatch), + HasErrors, /// This should never happen. Type mismatch should catch everything. TypeError(&'static str), NotSupported(String), @@ -179,15 +180,13 @@ impl MirLowerError { body.pretty_print_expr(db.upcast(), *owner, *it, edition) )?; } - MirLowerError::TypeMismatch(e) => match e { - Some(e) => writeln!( - f, - "Type mismatch: Expected {}, found {}", - e.expected.display(db, edition), - e.actual.display(db, edition), - )?, - None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?, - }, + MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?, + MirLowerError::TypeMismatch(e) => writeln!( + f, + "Type mismatch: Expected {}, found {}", + e.expected.display(db, edition), + e.actual.display(db, edition), + )?, MirLowerError::GenericArgNotProvided(id, subst) => { let parent = id.parent; let param = &db.generic_params(parent)[id.local_id]; @@ -362,7 +361,7 @@ impl<'ctx> MirLowerCtx<'ctx> { current, place, Rvalue::Cast( - CastKind::Pointer(*cast), + CastKind::PointerCoercion(*cast), Operand::Copy(p), last.target.clone(), ), @@ -898,14 +897,26 @@ impl<'ctx> MirLowerCtx<'ctx> { let Some((it, current)) = self.lower_expr_to_some_operand(*expr, current)? else { return Ok(None); }; - let source_ty = self.infer[*expr].clone(); - let target_ty = self.infer[expr_id].clone(); - self.push_assignment( - current, - place, - Rvalue::Cast(cast_kind(&source_ty, &target_ty)?, it, target_ty), - expr_id.into(), - ); + // Since we don't have THIR, this is the "zipped" version of [rustc's HIR lowering](https://github.com/rust-lang/rust/blob/e71f9529121ca8f687e4b725e3c9adc3f1ebab4d/compiler/rustc_mir_build/src/thir/cx/expr.rs#L165-L178) + // and [THIR lowering as RValue](https://github.com/rust-lang/rust/blob/a4601859ae3875732797873612d424976d9e3dd0/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs#L193-L313) + let rvalue = if self.infer.coercion_casts.contains(expr) { + Rvalue::Use(it) + } else { + let source_ty = self.infer[*expr].clone(); + let target_ty = self.infer[expr_id].clone(); + let cast_kind = if source_ty.as_reference().is_some() { + CastKind::PointerCoercion(PointerCast::ArrayToPointer) + } else { + let mut table = InferenceTable::new( + self.db, + self.db.trait_environment_for_body(self.owner), + ); + cast_kind(&mut table, &source_ty, &target_ty)? + }; + + Rvalue::Cast(cast_kind, it, target_ty) + }; + self.push_assignment(current, place, rvalue, expr_id.into()); Ok(Some(current)) } Expr::Ref { expr, rawness: _, mutability } => { @@ -2005,40 +2016,21 @@ impl<'ctx> MirLowerCtx<'ctx> { } } -fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result { - Ok(match (source_ty.kind(Interner), target_ty.kind(Interner)) { - (TyKind::FnDef(..), TyKind::Function(_)) => CastKind::Pointer(PointerCast::ReifyFnPointer), - (TyKind::Scalar(s), TyKind::Scalar(t)) => match (s, t) { - (chalk_ir::Scalar::Float(_), chalk_ir::Scalar::Float(_)) => CastKind::FloatToFloat, - (chalk_ir::Scalar::Float(_), _) => CastKind::FloatToInt, - (_, chalk_ir::Scalar::Float(_)) => CastKind::IntToFloat, - (_, _) => CastKind::IntToInt, - }, - (TyKind::Scalar(_), TyKind::Raw(..)) => CastKind::PointerFromExposedAddress, - (TyKind::Raw(..), TyKind::Scalar(_)) => CastKind::PointerExposeAddress, - (TyKind::Raw(_, a) | TyKind::Ref(_, _, a), TyKind::Raw(_, b) | TyKind::Ref(_, _, b)) => { - CastKind::Pointer(if a == b { - PointerCast::MutToConstPointer - } else if matches!(b.kind(Interner), TyKind::Slice(_)) - && matches!(a.kind(Interner), TyKind::Array(_, _)) - || matches!(b.kind(Interner), TyKind::Dyn(_)) - { - PointerCast::Unsize - } else if matches!(a.kind(Interner), TyKind::Slice(s) if s == b) { - PointerCast::ArrayToPointer - } else { - // cast between two sized pointer, like *const i32 to *const i8, or two unsized pointer, like - // slice to slice, slice to str, ... . These are no-ops (even in the unsized case, no metadata - // will be touched) but there is no specific variant - // for it in `PointerCast` so we use `MutToConstPointer` - PointerCast::MutToConstPointer - }) - } - // Enum to int casts - (TyKind::Scalar(_), TyKind::Adt(..)) | (TyKind::Adt(..), TyKind::Scalar(_)) => { - CastKind::IntToInt +fn cast_kind(table: &mut InferenceTable<'_>, source_ty: &Ty, target_ty: &Ty) -> Result { + let from = CastTy::from_ty(table, source_ty); + let cast = CastTy::from_ty(table, target_ty); + Ok(match (from, cast) { + (Some(CastTy::Ptr(..) | CastTy::FnPtr), Some(CastTy::Int(_))) => { + CastKind::PointerExposeAddress } - (a, b) => not_supported!("Unknown cast between {a:?} and {b:?}"), + (Some(CastTy::Int(_)), Some(CastTy::Ptr(..))) => CastKind::PointerFromExposedAddress, + (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => CastKind::IntToInt, + (Some(CastTy::FnPtr), Some(CastTy::Ptr(..))) => CastKind::FnPtrToPtr, + (Some(CastTy::Float), Some(CastTy::Int(_))) => CastKind::FloatToInt, + (Some(CastTy::Int(_)), Some(CastTy::Float)) => CastKind::IntToFloat, + (Some(CastTy::Float), Some(CastTy::Float)) => CastKind::FloatToFloat, + (Some(CastTy::Ptr(..)), Some(CastTy::Ptr(..))) => CastKind::PtrToPtr, + _ => not_supported!("Unknown cast between {source_ty:?} and {target_ty:?}"), }) } @@ -2191,7 +2183,7 @@ pub fn lower_to_mir( root_expr: ExprId, ) -> Result { if infer.has_errors { - return Err(MirLowerError::TypeMismatch(None)); + return Err(MirLowerError::HasErrors); } let mut ctx = MirLowerCtx::new(db, owner, body, infer); // 0 is return local diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs b/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs new file mode 100644 index 0000000000000..a4c6626855523 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs @@ -0,0 +1,612 @@ +//! Compute the object-safety of a trait + +use std::ops::ControlFlow; + +use chalk_ir::{ + cast::Cast, + visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, + DebruijnIndex, +}; +use chalk_solve::rust_ir::InlineBound; +use hir_def::{ + lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, + TypeAliasId, +}; +use rustc_hash::FxHashSet; +use smallvec::SmallVec; + +use crate::{ + all_super_traits, + db::HirDatabase, + from_assoc_type_id, from_chalk_trait_id, + generics::{generics, trait_self_param_idx}, + lower::callable_item_sig, + to_assoc_type_id, to_chalk_trait_id, + utils::elaborate_clause_supertraits, + AliasEq, AliasTy, Binders, BoundVar, CallableSig, GoalData, ImplTraitId, Interner, OpaqueTyId, + ProjectionTyExt, Solution, Substitution, TraitRef, Ty, TyKind, WhereClause, +}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum ObjectSafetyViolation { + SizedSelf, + SelfReferential, + Method(FunctionId, MethodViolationCode), + AssocConst(ConstId), + GAT(TypeAliasId), + // This doesn't exist in rustc, but added for better visualization + HasNonSafeSuperTrait(TraitId), +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum MethodViolationCode { + StaticMethod, + ReferencesSelfInput, + ReferencesSelfOutput, + ReferencesImplTraitInTrait, + AsyncFn, + WhereClauseReferencesSelf, + Generic, + UndispatchableReceiver, +} + +pub fn object_safety(db: &dyn HirDatabase, trait_: TraitId) -> Option { + for super_trait in all_super_traits(db.upcast(), trait_).into_iter().skip(1).rev() { + if db.object_safety_of_trait(super_trait).is_some() { + return Some(ObjectSafetyViolation::HasNonSafeSuperTrait(super_trait)); + } + } + + db.object_safety_of_trait(trait_) +} + +pub fn object_safety_with_callback( + db: &dyn HirDatabase, + trait_: TraitId, + cb: &mut F, +) -> ControlFlow<()> +where + F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>, +{ + for super_trait in all_super_traits(db.upcast(), trait_).into_iter().skip(1).rev() { + if db.object_safety_of_trait(super_trait).is_some() { + cb(ObjectSafetyViolation::HasNonSafeSuperTrait(trait_))?; + } + } + + object_safety_of_trait_with_callback(db, trait_, cb) +} + +pub fn object_safety_of_trait_with_callback( + db: &dyn HirDatabase, + trait_: TraitId, + cb: &mut F, +) -> ControlFlow<()> +where + F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>, +{ + // Check whether this has a `Sized` bound + if generics_require_sized_self(db, trait_.into()) { + cb(ObjectSafetyViolation::SizedSelf)?; + } + + // Check if there exist bounds that referencing self + if predicates_reference_self(db, trait_) { + cb(ObjectSafetyViolation::SelfReferential)?; + } + if bounds_reference_self(db, trait_) { + cb(ObjectSafetyViolation::SelfReferential)?; + } + + // rustc checks for non-lifetime binders here, but we don't support HRTB yet + + let trait_data = db.trait_data(trait_); + for (_, assoc_item) in &trait_data.items { + object_safety_violation_for_assoc_item(db, trait_, *assoc_item, cb)?; + } + + ControlFlow::Continue(()) +} + +pub fn object_safety_of_trait_query( + db: &dyn HirDatabase, + trait_: TraitId, +) -> Option { + let mut res = None; + object_safety_of_trait_with_callback(db, trait_, &mut |osv| { + res = Some(osv); + ControlFlow::Break(()) + }); + + res +} + +fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { + let krate = def.module(db.upcast()).krate(); + let Some(sized) = db.lang_item(krate, LangItem::Sized).and_then(|l| l.as_trait()) else { + return false; + }; + + let Some(trait_self_param_idx) = trait_self_param_idx(db.upcast(), def) else { + return false; + }; + + let predicates = &*db.generic_predicates(def); + let predicates = predicates.iter().map(|p| p.skip_binders().skip_binders().clone()); + elaborate_clause_supertraits(db, predicates).any(|pred| match pred { + WhereClause::Implemented(trait_ref) => { + if from_chalk_trait_id(trait_ref.trait_id) == sized { + if let TyKind::BoundVar(it) = + *trait_ref.self_type_parameter(Interner).kind(Interner) + { + // Since `generic_predicates` is `Binder>`, the `DebrujinIndex` of + // self-parameter is `1` + return it + .index_if_bound_at(DebruijnIndex::ONE) + .is_some_and(|idx| idx == trait_self_param_idx); + } + } + false + } + _ => false, + }) +} + +// rustc gathers all the spans that references `Self` for error rendering, +// but we don't have good way to render such locations. +// So, just return single boolean value for existence of such `Self` reference +fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool { + db.generic_predicates(trait_.into()) + .iter() + .any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No)) +} + +// Same as the above, `predicates_reference_self` +fn bounds_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool { + let trait_data = db.trait_data(trait_); + trait_data + .items + .iter() + .filter_map(|(_, it)| match *it { + AssocItemId::TypeAliasId(id) => { + let assoc_ty_id = to_assoc_type_id(id); + let assoc_ty_data = db.associated_ty_data(assoc_ty_id); + Some(assoc_ty_data) + } + _ => None, + }) + .any(|assoc_ty_data| { + assoc_ty_data.binders.skip_binders().bounds.iter().any(|bound| { + let def = from_assoc_type_id(assoc_ty_data.id).into(); + match bound.skip_binders() { + InlineBound::TraitBound(it) => it.args_no_self.iter().any(|arg| { + contains_illegal_self_type_reference( + db, + def, + trait_, + arg, + DebruijnIndex::ONE, + AllowSelfProjection::Yes, + ) + }), + InlineBound::AliasEqBound(it) => it.parameters.iter().any(|arg| { + contains_illegal_self_type_reference( + db, + def, + trait_, + arg, + DebruijnIndex::ONE, + AllowSelfProjection::Yes, + ) + }), + } + }) + }) +} + +#[derive(Clone, Copy)] +enum AllowSelfProjection { + Yes, + No, +} + +fn predicate_references_self( + db: &dyn HirDatabase, + trait_: TraitId, + predicate: &Binders>, + allow_self_projection: AllowSelfProjection, +) -> bool { + match predicate.skip_binders().skip_binders() { + WhereClause::Implemented(trait_ref) => { + trait_ref.substitution.iter(Interner).skip(1).any(|arg| { + contains_illegal_self_type_reference( + db, + trait_.into(), + trait_, + arg, + DebruijnIndex::ONE, + allow_self_projection, + ) + }) + } + WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), .. }) => { + proj.substitution.iter(Interner).skip(1).any(|arg| { + contains_illegal_self_type_reference( + db, + trait_.into(), + trait_, + arg, + DebruijnIndex::ONE, + allow_self_projection, + ) + }) + } + _ => false, + } +} + +fn contains_illegal_self_type_reference>( + db: &dyn HirDatabase, + def: GenericDefId, + trait_: TraitId, + t: &T, + outer_binder: DebruijnIndex, + allow_self_projection: AllowSelfProjection, +) -> bool { + let Some(trait_self_param_idx) = trait_self_param_idx(db.upcast(), def) else { + return false; + }; + struct IllegalSelfTypeVisitor<'a> { + db: &'a dyn HirDatabase, + trait_: TraitId, + super_traits: Option>, + trait_self_param_idx: usize, + allow_self_projection: AllowSelfProjection, + } + impl<'a> TypeVisitor for IllegalSelfTypeVisitor<'a> { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor { + self + } + + fn interner(&self) -> Interner { + Interner + } + + fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow { + match ty.kind(Interner) { + TyKind::BoundVar(BoundVar { debruijn, index }) => { + if *debruijn == outer_binder && *index == self.trait_self_param_idx { + ControlFlow::Break(()) + } else { + ty.super_visit_with(self.as_dyn(), outer_binder) + } + } + TyKind::Alias(AliasTy::Projection(proj)) => match self.allow_self_projection { + AllowSelfProjection::Yes => { + let trait_ = proj.trait_(self.db); + if self.super_traits.is_none() { + self.super_traits = + Some(all_super_traits(self.db.upcast(), self.trait_)); + } + if self.super_traits.as_ref().is_some_and(|s| s.contains(&trait_)) { + ControlFlow::Continue(()) + } else { + ty.super_visit_with(self.as_dyn(), outer_binder) + } + } + AllowSelfProjection::No => ty.super_visit_with(self.as_dyn(), outer_binder), + }, + _ => ty.super_visit_with(self.as_dyn(), outer_binder), + } + } + + fn visit_const( + &mut self, + constant: &chalk_ir::Const, + outer_binder: DebruijnIndex, + ) -> std::ops::ControlFlow { + constant.data(Interner).ty.super_visit_with(self.as_dyn(), outer_binder) + } + } + + let mut visitor = IllegalSelfTypeVisitor { + db, + trait_, + super_traits: None, + trait_self_param_idx, + allow_self_projection, + }; + t.visit_with(visitor.as_dyn(), outer_binder).is_break() +} + +fn object_safety_violation_for_assoc_item( + db: &dyn HirDatabase, + trait_: TraitId, + item: AssocItemId, + cb: &mut F, +) -> ControlFlow<()> +where + F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>, +{ + // Any item that has a `Self : Sized` requisite is otherwise + // exempt from the regulations. + if generics_require_sized_self(db, item.into()) { + return ControlFlow::Continue(()); + } + + match item { + AssocItemId::ConstId(it) => cb(ObjectSafetyViolation::AssocConst(it)), + AssocItemId::FunctionId(it) => { + virtual_call_violations_for_method(db, trait_, it, &mut |mvc| { + cb(ObjectSafetyViolation::Method(it, mvc)) + }) + } + AssocItemId::TypeAliasId(it) => { + let def_map = db.crate_def_map(trait_.krate(db.upcast())); + if def_map.is_unstable_feature_enabled(&intern::sym::generic_associated_type_extended) { + ControlFlow::Continue(()) + } else { + let generic_params = db.generic_params(item.into()); + if !generic_params.is_empty() { + cb(ObjectSafetyViolation::GAT(it)) + } else { + ControlFlow::Continue(()) + } + } + } + } +} + +fn virtual_call_violations_for_method( + db: &dyn HirDatabase, + trait_: TraitId, + func: FunctionId, + cb: &mut F, +) -> ControlFlow<()> +where + F: FnMut(MethodViolationCode) -> ControlFlow<()>, +{ + let func_data = db.function_data(func); + if !func_data.has_self_param() { + cb(MethodViolationCode::StaticMethod)?; + } + + if func_data.is_async() { + cb(MethodViolationCode::AsyncFn)?; + } + + let sig = callable_item_sig(db, func.into()); + if sig.skip_binders().params().iter().skip(1).any(|ty| { + contains_illegal_self_type_reference( + db, + func.into(), + trait_, + ty, + DebruijnIndex::INNERMOST, + AllowSelfProjection::Yes, + ) + }) { + cb(MethodViolationCode::ReferencesSelfInput)?; + } + + if contains_illegal_self_type_reference( + db, + func.into(), + trait_, + sig.skip_binders().ret(), + DebruijnIndex::INNERMOST, + AllowSelfProjection::Yes, + ) { + cb(MethodViolationCode::ReferencesSelfOutput)?; + } + + if !func_data.is_async() { + if let Some(mvc) = contains_illegal_impl_trait_in_trait(db, &sig) { + cb(mvc)?; + } + } + + let generic_params = db.generic_params(func.into()); + if generic_params.len_type_or_consts() > 0 { + cb(MethodViolationCode::Generic)?; + } + + if func_data.has_self_param() && !receiver_is_dispatchable(db, trait_, func, &sig) { + cb(MethodViolationCode::UndispatchableReceiver)?; + } + + let predicates = &*db.generic_predicates_without_parent(func.into()); + let trait_self_idx = trait_self_param_idx(db.upcast(), func.into()); + for pred in predicates { + let pred = pred.skip_binders().skip_binders(); + + if matches!(pred, WhereClause::TypeOutlives(_)) { + continue; + } + + // Allow `impl AutoTrait` predicates + if let WhereClause::Implemented(TraitRef { trait_id, substitution }) = pred { + let trait_data = db.trait_data(from_chalk_trait_id(*trait_id)); + if trait_data.is_auto + && substitution + .as_slice(Interner) + .first() + .and_then(|arg| arg.ty(Interner)) + .and_then(|ty| ty.bound_var(Interner)) + .is_some_and(|b| { + b.debruijn == DebruijnIndex::ONE && Some(b.index) == trait_self_idx + }) + { + continue; + } + } + + if contains_illegal_self_type_reference( + db, + func.into(), + trait_, + pred, + DebruijnIndex::ONE, + AllowSelfProjection::Yes, + ) { + cb(MethodViolationCode::WhereClauseReferencesSelf)?; + break; + } + } + + ControlFlow::Continue(()) +} + +fn receiver_is_dispatchable( + db: &dyn HirDatabase, + trait_: TraitId, + func: FunctionId, + sig: &Binders, +) -> bool { + let Some(trait_self_idx) = trait_self_param_idx(db.upcast(), func.into()) else { + return false; + }; + + // `self: Self` can't be dispatched on, but this is already considered object safe. + // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437 + if sig + .skip_binders() + .params() + .first() + .and_then(|receiver| receiver.bound_var(Interner)) + .is_some_and(|b| { + b == BoundVar { debruijn: DebruijnIndex::INNERMOST, index: trait_self_idx } + }) + { + return true; + } + + let placeholder_subst = generics(db.upcast(), func.into()).placeholder_subst(db); + + let substituted_sig = sig.clone().substitute(Interner, &placeholder_subst); + let Some(receiver_ty) = substituted_sig.params().first() else { + return false; + }; + + let krate = func.module(db.upcast()).krate(); + let traits = ( + db.lang_item(krate, LangItem::Unsize).and_then(|it| it.as_trait()), + db.lang_item(krate, LangItem::DispatchFromDyn).and_then(|it| it.as_trait()), + ); + let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else { + return false; + }; + + // Type `U` + let unsized_self_ty = + TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32)).intern(Interner); + // `Receiver[Self => U]` + let Some(unsized_receiver_ty) = receiver_for_self_ty(db, func, unsized_self_ty.clone()) else { + return false; + }; + + let self_ty = placeholder_subst.as_slice(Interner)[trait_self_idx].assert_ty_ref(Interner); + let unsized_predicate = WhereClause::Implemented(TraitRef { + trait_id: to_chalk_trait_id(unsize_did), + substitution: Substitution::from_iter(Interner, [self_ty.clone(), unsized_self_ty.clone()]), + }); + let trait_predicate = WhereClause::Implemented(TraitRef { + trait_id: to_chalk_trait_id(trait_), + substitution: Substitution::from_iter( + Interner, + std::iter::once(unsized_self_ty.clone().cast(Interner)) + .chain(placeholder_subst.iter(Interner).skip(1).cloned()), + ), + }); + + let generic_predicates = &*db.generic_predicates(func.into()); + + let clauses = std::iter::once(unsized_predicate) + .chain(std::iter::once(trait_predicate)) + .chain(generic_predicates.iter().map(|pred| { + pred.clone().substitute(Interner, &placeholder_subst).into_value_and_skipped_binders().0 + })) + .map(|pred| { + pred.cast::>(Interner).into_from_env_clause(Interner) + }); + let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); + + let obligation = WhereClause::Implemented(TraitRef { + trait_id: to_chalk_trait_id(dispatch_from_dyn_did), + substitution: Substitution::from_iter(Interner, [receiver_ty.clone(), unsized_receiver_ty]), + }); + let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(obligation)).intern(Interner); + + let in_env = chalk_ir::InEnvironment::new(&env, goal); + + let mut table = chalk_solve::infer::InferenceTable::::new(); + let canonicalized = table.canonicalize(Interner, in_env); + let solution = db.trait_solve(krate, None, canonicalized.quantified); + + matches!(solution, Some(Solution::Unique(_))) +} + +fn receiver_for_self_ty(db: &dyn HirDatabase, func: FunctionId, ty: Ty) -> Option { + let generics = generics(db.upcast(), func.into()); + let trait_self_idx = trait_self_param_idx(db.upcast(), func.into())?; + let subst = generics.placeholder_subst(db); + let subst = Substitution::from_iter( + Interner, + subst.iter(Interner).enumerate().map(|(idx, arg)| { + if idx == trait_self_idx { + ty.clone().cast(Interner) + } else { + arg.clone() + } + }), + ); + let sig = callable_item_sig(db, func.into()); + let sig = sig.substitute(Interner, &subst); + sig.params_and_return.first().cloned() +} + +fn contains_illegal_impl_trait_in_trait( + db: &dyn HirDatabase, + sig: &Binders, +) -> Option { + struct OpaqueTypeCollector(FxHashSet); + + impl TypeVisitor for OpaqueTypeCollector { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor { + self + } + + fn interner(&self) -> Interner { + Interner + } + + fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow { + if let TyKind::OpaqueType(opaque_ty_id, _) = ty.kind(Interner) { + self.0.insert(*opaque_ty_id); + } + ty.super_visit_with(self.as_dyn(), outer_binder) + } + } + + let ret = sig.skip_binders().ret(); + let mut visitor = OpaqueTypeCollector(FxHashSet::default()); + ret.visit_with(visitor.as_dyn(), DebruijnIndex::INNERMOST); + + // Since we haven't implemented RPITIT in proper way like rustc yet, + // just check whether `ret` contains RPIT for now + for opaque_ty in visitor.0 { + let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.into()); + if matches!(impl_trait_id, ImplTraitId::ReturnTypeImplTrait(..)) { + return Some(MethodViolationCode::ReferencesImplTraitInTrait); + } + } + + None +} + +#[cfg(test)] +mod tests; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs new file mode 100644 index 0000000000000..c2a9117c5be4f --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs @@ -0,0 +1,393 @@ +use std::ops::ControlFlow; + +use hir_def::db::DefDatabase; +use rustc_hash::{FxHashMap, FxHashSet}; +use syntax::ToSmolStr; +use test_fixture::WithFixture; + +use crate::{object_safety::object_safety_with_callback, test_db::TestDB}; + +use super::{ + MethodViolationCode::{self, *}, + ObjectSafetyViolation, +}; + +use ObjectSafetyViolationKind::*; + +#[allow(clippy::upper_case_acronyms)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum ObjectSafetyViolationKind { + SizedSelf, + SelfReferential, + Method(MethodViolationCode), + AssocConst, + GAT, + HasNonSafeSuperTrait, +} + +fn check_object_safety<'a>( + ra_fixture: &str, + expected: impl IntoIterator)>, +) { + let mut expected: FxHashMap<_, _> = + expected.into_iter().map(|(id, osvs)| (id, FxHashSet::from_iter(osvs))).collect(); + let (db, file_ids) = TestDB::with_many_files(ra_fixture); + for (trait_id, name) in file_ids.into_iter().flat_map(|file_id| { + let module_id = db.module_for_file(file_id); + let def_map = module_id.def_map(&db); + let scope = &def_map[module_id.local_id].scope; + scope + .declarations() + .filter_map(|def| { + if let hir_def::ModuleDefId::TraitId(trait_id) = def { + let name = + db.trait_data(trait_id).name.display_no_db(file_id.edition()).to_smolstr(); + Some((trait_id, name)) + } else { + None + } + }) + .collect::>() + }) { + let Some(expected) = expected.remove(name.as_str()) else { + continue; + }; + let mut osvs = FxHashSet::default(); + object_safety_with_callback(&db, trait_id, &mut |osv| { + osvs.insert(match osv { + ObjectSafetyViolation::SizedSelf => SizedSelf, + ObjectSafetyViolation::SelfReferential => SelfReferential, + ObjectSafetyViolation::Method(_, mvc) => Method(mvc), + ObjectSafetyViolation::AssocConst(_) => AssocConst, + ObjectSafetyViolation::GAT(_) => GAT, + ObjectSafetyViolation::HasNonSafeSuperTrait(_) => HasNonSafeSuperTrait, + }); + ControlFlow::Continue(()) + }); + assert_eq!(osvs, expected, "Object safety violations for `{name}` do not match;"); + } + + let remains: Vec<_> = expected.keys().collect(); + assert!(remains.is_empty(), "Following traits do not exist in the test fixture; {remains:?}"); +} + +#[test] +fn item_bounds_can_reference_self() { + check_object_safety( + r#" +//- minicore: eq +pub trait Foo { + type X: PartialEq; + type Y: PartialEq; + type Z: PartialEq; +} +"#, + [("Foo", vec![])], + ); +} + +#[test] +fn associated_consts() { + check_object_safety( + r#" +trait Bar { + const X: usize; +} +"#, + [("Bar", vec![AssocConst])], + ); +} + +#[test] +fn bounds_reference_self() { + check_object_safety( + r#" +//- minicore: eq +trait X { + type U: PartialEq; +} +"#, + [("X", vec![SelfReferential])], + ); +} + +#[test] +fn by_value_self() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Bar { + fn bar(self); +} + +trait Baz { + fn baz(self: Self); +} + +trait Quux { + // Legal because of the where clause: + fn baz(self: Self) where Self : Sized; +} +"#, + [("Bar", vec![]), ("Baz", vec![]), ("Quux", vec![])], + ); +} + +#[test] +fn generic_methods() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Bar { + fn bar(&self, t: T); +} + +trait Quux { + fn bar(&self, t: T) + where Self : Sized; +} + +trait Qax { + fn bar<'a>(&self, t: &'a ()); +} +"#, + [("Bar", vec![Method(Generic)]), ("Quux", vec![]), ("Qax", vec![])], + ); +} + +#[test] +fn mentions_self() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Bar { + fn bar(&self, x: &Self); +} + +trait Baz { + fn baz(&self) -> Self; +} + +trait Quux { + fn quux(&self, s: &Self) -> Self where Self : Sized; +} +"#, + [ + ("Bar", vec![Method(ReferencesSelfInput)]), + ("Baz", vec![Method(ReferencesSelfOutput)]), + ("Quux", vec![]), + ], + ); +} + +#[test] +fn no_static() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Foo { + fn foo() {} +} +"#, + [("Foo", vec![Method(StaticMethod)])], + ); +} + +#[test] +fn sized_self() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Bar: Sized { + fn bar(&self, t: T); +} +"#, + [("Bar", vec![SizedSelf])], + ); + + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Bar + where Self : Sized +{ + fn bar(&self, t: T); +} +"#, + [("Bar", vec![SizedSelf])], + ); +} + +#[test] +fn supertrait_gat() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait GatTrait { + type Gat; +} + +trait SuperTrait: GatTrait {} +"#, + [("GatTrait", vec![GAT]), ("SuperTrait", vec![HasNonSafeSuperTrait])], + ); +} + +#[test] +fn supertrait_mentions_self() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Bar { + fn bar(&self, x: &T); +} + +trait Baz : Bar { +} +"#, + [("Bar", vec![]), ("Baz", vec![SizedSelf, SelfReferential])], + ); +} + +#[test] +fn rustc_issue_19538() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Foo { + fn foo(&self, val: T); +} + +trait Bar: Foo {} +"#, + [("Foo", vec![Method(Generic)]), ("Bar", vec![HasNonSafeSuperTrait])], + ); +} + +#[test] +fn rustc_issue_22040() { + check_object_safety( + r#" +//- minicore: fmt, eq, dispatch_from_dyn +use core::fmt::Debug; + +trait Expr: Debug + PartialEq { + fn print_element_count(&self); +} +"#, + [("Expr", vec![SelfReferential])], + ); +} + +#[test] +fn rustc_issue_102762() { + check_object_safety( + r#" +//- minicore: future, send, sync, dispatch_from_dyn, deref +use core::pin::Pin; + +struct Box {} +impl core::ops::Deref for Box { + type Target = T; + + fn deref(&self) -> &Self::Target { + loop {} + } +} +impl, U: ?Sized> DispatchFromDyn> for Box {} + +struct Vec {} + +pub trait Fetcher: Send + Sync { + fn get<'a>(self: &'a Box) -> Pin> + 'a>> + where + Self: Sync, + { + loop {} + } +} +"#, + [("Fetcher", vec![Method(UndispatchableReceiver)])], + ); +} + +#[test] +fn rustc_issue_102933() { + check_object_safety( + r#" +//- minicore: future, dispatch_from_dyn, deref +use core::future::Future; + +struct Box {} +impl core::ops::Deref for Box { + type Target = T; + + fn deref(&self) -> &Self::Target { + loop {} + } +} +impl, U: ?Sized> DispatchFromDyn> for Box {} + +pub trait Service { + type Response; + type Future: Future; +} + +pub trait A1: Service {} + +pub trait A2: Service>> + A1 { + fn foo(&self) {} +} + +pub trait B1: Service>> {} + +pub trait B2: Service + B1 { + fn foo(&self) {} +} + "#, + [("A2", vec![]), ("B2", vec![])], + ); +} + +#[test] +fn rustc_issue_106247() { + check_object_safety( + r#" +//- minicore: sync, dispatch_from_dyn +pub trait Trait { + fn method(&self) where Self: Sync; +} +"#, + [("Trait", vec![])], + ); +} + +#[test] +fn std_error_is_object_safe() { + check_object_safety( + r#" +//- minicore: fmt, dispatch_from_dyn +trait Erased<'a>: 'a {} + +pub struct Request<'a>(dyn Erased<'a> + 'a); + +pub trait Error: core::fmt::Debug + core::fmt::Display { + fn provide<'a>(&'a self, request: &mut Request<'a>); +} +"#, + [("Error", vec![])], + ); +} + +#[test] +fn lifetime_gat_is_object_unsafe() { + check_object_safety( + r#" +//- minicore: dispatch_from_dyn +trait Foo { + type Bar<'a>; +} +"#, + [("Foo", vec![ObjectSafetyViolationKind::GAT])], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index 908bbc248c604..273571901ad58 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -49,7 +49,7 @@ fn let_stmt_coerce() { //- minicore: coerce_unsized fn test() { let x: &[isize] = &[1]; - // ^^^^ adjustments: Deref(None), Borrow(Ref('?3, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?2, Not)), Pointer(Unsize) let x: *const [isize] = &[1]; // ^^^^ adjustments: Deref(None), Borrow(RawPtr(Not)), Pointer(Unsize) } @@ -148,7 +148,7 @@ fn foo(x: &[T]) -> &[T] { x } fn test(i: i32) { let x = match i { 2 => foo(&[2]), - // ^^^^ adjustments: Deref(None), Borrow(Ref('?10, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?8, Not)), Pointer(Unsize) 1 => &[1], _ => &[3], }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index 5454a496ba8c1..53b69c12f05d5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -1,7 +1,7 @@ use expect_test::expect; use test_utils::{bench, bench_fixture, skip_slow_tests}; -use crate::tests::check_infer_with_mismatches; +use crate::tests::{check_infer_with_mismatches, check_no_mismatches}; use super::{check_infer, check_types}; @@ -206,6 +206,7 @@ fn expr_macro_def_expanded_in_various_places() { 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () + 100..119 'for _ ...!() {}': () 104..105 '_': IntoIterator::Item 117..119 '{}': () 124..134 '|| spam!()': impl Fn() -> isize @@ -299,6 +300,7 @@ fn expr_macro_rules_expanded_in_various_places() { 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () + 114..133 'for _ ...!() {}': () 118..119 '_': IntoIterator::Item 131..133 '{}': () 138..148 '|| spam!()': impl Fn() -> isize @@ -1404,3 +1406,105 @@ fn foo(t: Tensor) { "#, ); } + +#[test] +fn asm_unit() { + check_no_mismatches( + r#" +//- minicore: asm +fn unit() { + core::arch::asm!("") +} +"#, + ); +} + +#[test] +fn asm_no_return() { + check_no_mismatches( + r#" +//- minicore: asm +fn unit() -> ! { + core::arch::asm!("", options(noreturn)) +} +"#, + ); +} + +#[test] +fn asm_things() { + check_infer( + r#" +//- minicore: asm, concat +fn main() { + unsafe { + let foo = 1; + let mut o = 0; + core::arch::asm!( + "%input = OpLoad _ {0}", + concat!("%result = ", bar, " _ %input"), + "OpStore {1} %result", + in(reg) &foo, + in(reg) &mut o, + ); + o + + let thread_id: usize; + core::arch::asm!(" + mov {0}, gs:[0x30] + mov {0}, [{0}+0x48] + ", out(reg) thread_id, options(pure, readonly, nostack)); + + static UNMAP_BASE: usize; + const MEM_RELEASE: usize; + static VirtualFree: usize; + const OffPtr: usize; + const OffFn: usize; + core::arch::asm!(" + push {free_type} + push {free_size} + push {base} + + mov eax, fs:[30h] + mov eax, [eax+8h] + add eax, {off_fn} + mov [eax-{off_fn}+{off_ptr}], eax + + push eax + + jmp {virtual_free} + ", + off_ptr = const OffPtr, + off_fn = const OffFn, + + free_size = const 0, + free_type = const MEM_RELEASE, + + virtual_free = sym VirtualFree, + + base = sym UNMAP_BASE, + options(noreturn), + ); + } +} +"#, + expect![[r#" + !0..122 'builti...muto,)': () + !0..136 'builti...tack))': () + !0..449 'builti...urn),)': ! + 10..1236 '{ ... } }': () + 16..1234 'unsafe... }': () + 37..40 'foo': i32 + 43..44 '1': i32 + 58..63 'mut o': i32 + 66..67 '0': i32 + !95..104 'thread_id': usize + !103..107 '&foo': &'? i32 + !104..107 'foo': i32 + !115..120 '&muto': &'? mut i32 + !119..120 'o': i32 + 293..294 'o': i32 + 308..317 'thread_id': usize + "#]], + ) +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index 610fc9b6b4562..74acf23b75ab6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -1286,6 +1286,7 @@ fn main() { fn method_on_dyn_impl() { check_types( r#" +//- minicore: coerce_unsized trait Foo {} impl Foo for u32 {} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index 0ccbcf63e2b67..5c63cd00f97d9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -371,6 +371,7 @@ fn diverging_expression_3_break() { 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () + 151..172 'for a ...eak; }': () 155..156 'a': {unknown} 160..161 'b': {unknown} 162..172 '{ break; }': () @@ -387,6 +388,7 @@ fn diverging_expression_3_break() { 237..250 'for a in b {}': () 237..250 'for a in b {}': () 237..250 'for a in b {}': () + 237..250 'for a in b {}': () 241..242 'a': {unknown} 246..247 'b': {unknown} 248..250 '{}': () @@ -402,6 +404,7 @@ fn diverging_expression_3_break() { 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () + 315..337 'for a ...urn; }': () 319..320 'a': {unknown} 324..325 'b': {unknown} 326..337 '{ return; }': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 57866acc06374..51c27f8714ac5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -57,6 +57,7 @@ fn infer_pattern() { 101..151 'for (e... }': () 101..151 'for (e... }': () 101..151 'for (e... }': () + 101..151 'for (e... }': () 105..111 '(e, f)': ({unknown}, {unknown}) 106..107 'e': {unknown} 109..110 'f': {unknown} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 17fbe4db31795..a3cf12d8a16ed 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -275,6 +275,7 @@ fn infer_std_crash_5() { 32..320 'for co... }': () 32..320 'for co... }': () 32..320 'for co... }': () + 32..320 'for co... }': () 36..43 'content': {unknown} 47..60 'doesnt_matter': {unknown} 61..320 '{ ... }': () @@ -1065,7 +1066,7 @@ fn test() { fn bare_dyn_trait_binders_9639() { check_no_mismatches( r#" -//- minicore: fn, coerce_unsized +//- minicore: fn, coerce_unsized, dispatch_from_dyn fn infix_parse(_state: S, _level_code: &Fn(S)) -> T { loop {} } @@ -1244,6 +1245,7 @@ fn test() { 16..66 'for _ ... }': () 16..66 'for _ ... }': () 16..66 'for _ ... }': () + 16..66 'for _ ... }': () 20..21 '_': IntoIterator::Item<()> 25..39 '{ let x = 0; }': () 31..32 'x': i32 @@ -1907,6 +1909,7 @@ fn dont_unify_on_casts() { // #15246 check_types( r#" +//- minicore: sized fn unify(_: [bool; 1]) {} fn casted(_: *const bool) {} fn default() -> T { loop {} } @@ -1926,6 +1929,7 @@ fn test() { fn rustc_test_issue_52437() { check_types( r#" + //- minicore: sized fn main() { let x = [(); &(&'static: loop { |x| {}; }) as *const _ as usize] //^ [(); _] @@ -2228,3 +2232,66 @@ async fn f() -> Bar {} "#]], ); } + +#[test] +fn issue_18109() { + check_infer( + r#" +//- minicore: option +struct Map(T, U); + +impl Map { + fn new() -> Self { loop {} } + fn get(&self, _: &T) -> Option<&U> { loop {} } +} + +fn test(x: bool) { + let map = Map::new(); + let _ = match x { + true => { + let Some(val) = map.get(&8) else { return }; + *val + } + false => return, + _ => 42, + }; +} +"#, + expect![[r#" + 69..80 '{ loop {} }': Map + 71..78 'loop {}': ! + 76..78 '{}': () + 93..97 'self': &'? Map + 99..100 '_': &'? T + 120..131 '{ loop {} }': Option<&'? U> + 122..129 'loop {}': ! + 127..129 '{}': () + 143..144 'x': bool + 152..354 '{ ... }; }': () + 162..165 'map': Map + 168..176 'Map::new': fn new() -> Map + 168..178 'Map::new()': Map + 188..189 '_': i32 + 192..351 'match ... }': i32 + 198..199 'x': bool + 210..214 'true': bool + 210..214 'true': bool + 218..303 '{ ... }': i32 + 236..245 'Some(val)': Option<&'? i32> + 241..244 'val': &'? i32 + 248..251 'map': Map + 248..259 'map.get(&8)': Option<&'? i32> + 256..258 '&8': &'? i32 + 257..258 '8': i32 + 265..275 '{ return }': ! + 267..273 'return': ! + 289..293 '*val': i32 + 290..293 'val': &'? i32 + 312..317 'false': bool + 312..317 'false': bool + 321..327 'return': ! + 337..338 '_': bool + 342..344 '42': i32 + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 1c6fa62e30ceb..0473ee02fab11 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -917,7 +917,7 @@ fn test(a: A) { 278..279 'A': extern "rust-call" A(*mut i32) -> A 278..292 'A(0 as *mut _)': A 278..307 'A(0 as...B(a)))': &'? i32 - 280..281 '0': i32 + 280..281 '0': usize 280..291 '0 as *mut _': *mut i32 297..306 '&&B(B(a))': &'? &'? B>> 298..306 '&B(B(a))': &'? B>> @@ -3572,6 +3572,7 @@ fn f(t: Ark) { fn ref_to_array_to_ptr_cast() { check_types( r#" +//- minicore: sized fn default() -> T { loop {} } fn foo() { let arr = [default()]; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index a98cff2a08b26..0b2d6bdd2593f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1448,14 +1448,20 @@ fn foo() -> Foo> { fn dyn_trait() { check_infer( r#" -//- minicore: sized +//- minicore: deref, dispatch_from_dyn trait Trait { fn foo(&self) -> T; fn foo2(&self) -> i64; } -fn bar() -> dyn Trait {} -fn test(x: dyn Trait, y: &dyn Trait) { +struct Box {} +impl core::ops::Deref for Box { + type Target = T; +} + +fn bar() -> Box> {} + +fn test(x: Box>, y: &dyn Trait) { x; y; let z = bar(); @@ -1469,27 +1475,27 @@ fn test(x: dyn Trait, y: &dyn Trait) { expect![[r#" 29..33 'self': &'? Self 54..58 'self': &'? Self - 97..99 '{}': dyn Trait - 109..110 'x': dyn Trait - 128..129 'y': &'? dyn Trait - 148..265 '{ ...2(); }': () - 154..155 'x': dyn Trait - 161..162 'y': &'? dyn Trait - 172..173 'z': dyn Trait - 176..179 'bar': fn bar() -> dyn Trait - 176..181 'bar()': dyn Trait - 187..188 'x': dyn Trait - 187..194 'x.foo()': u64 - 200..201 'y': &'? dyn Trait - 200..207 'y.foo()': u64 - 213..214 'z': dyn Trait - 213..220 'z.foo()': u64 - 226..227 'x': dyn Trait - 226..234 'x.foo2()': i64 - 240..241 'y': &'? dyn Trait - 240..248 'y.foo2()': i64 - 254..255 'z': dyn Trait - 254..262 'z.foo2()': i64 + 198..200 '{}': Box> + 210..211 'x': Box> + 234..235 'y': &'? dyn Trait + 254..371 '{ ...2(); }': () + 260..261 'x': Box> + 267..268 'y': &'? dyn Trait + 278..279 'z': Box> + 282..285 'bar': fn bar() -> Box> + 282..287 'bar()': Box> + 293..294 'x': Box> + 293..300 'x.foo()': u64 + 306..307 'y': &'? dyn Trait + 306..313 'y.foo()': u64 + 319..320 'z': Box> + 319..326 'z.foo()': u64 + 332..333 'x': Box> + 332..340 'x.foo2()': i64 + 346..347 'y': &'? dyn Trait + 346..354 'y.foo2()': i64 + 360..361 'z': Box> + 360..368 'z.foo2()': i64 "#]], ); } @@ -1534,7 +1540,7 @@ fn test(s: S) { fn dyn_trait_bare() { check_infer( r#" -//- minicore: sized +//- minicore: sized, dispatch_from_dyn trait Trait { fn foo(&self) -> u64; } @@ -1570,7 +1576,7 @@ fn test(x: Trait, y: &Trait) -> u64 { check_infer_with_mismatches( r#" -//- minicore: fn, coerce_unsized +//- minicore: fn, coerce_unsized, dispatch_from_dyn struct S; impl S { fn foo(&self) {} @@ -3106,7 +3112,7 @@ fn dyn_fn_param_informs_call_site_closure_signature() { cov_mark::check!(dyn_fn_param_informs_call_site_closure_signature); check_types( r#" -//- minicore: fn, coerce_unsized +//- minicore: fn, coerce_unsized, dispatch_from_dyn struct S; impl S { fn inherent(&self) -> u8 { 0 } @@ -3151,7 +3157,7 @@ fn infer_box_fn_arg() { // The type mismatch is because we don't define Unsize and CoerceUnsized check_infer_with_mismatches( r#" -//- minicore: fn, deref, option +//- minicore: fn, deref, option, dispatch_from_dyn #[lang = "owned_box"] pub struct Box { inner: *mut T, diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index ffb972475f8f7..0b3cdb2f37907 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -4,7 +4,9 @@ //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; -use hir_ty::{db::HirDatabase, diagnostics::BodyValidationDiagnostic, InferenceDiagnostic}; +use hir_ty::{ + db::HirDatabase, diagnostics::BodyValidationDiagnostic, CastError, InferenceDiagnostic, +}; use cfg::{CfgExpr, CfgOptions}; use either::Either; @@ -50,10 +52,12 @@ macro_rules! diagnostics { diagnostics![ AwaitOutsideOfAsync, BreakOutsideOfLoop, + CastToUnsized, ExpectedFunction, InactiveCode, IncoherentImpl, IncorrectCase, + InvalidCast, InvalidDeriveTarget, MacroDefError, MacroError, @@ -254,6 +258,8 @@ pub struct PrivateField { #[derive(Debug)] pub struct MissingUnsafe { pub expr: InFile>, + /// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error. + pub only_lint: bool, } #[derive(Debug)] @@ -364,6 +370,20 @@ pub struct RemoveUnnecessaryElse { pub if_expr: InFile>, } +#[derive(Debug)] +pub struct CastToUnsized { + pub expr: InFile>, + pub cast_ty: Type, +} + +#[derive(Debug)] +pub struct InvalidCast { + pub expr: InFile>, + pub error: CastError, + pub expr_ty: Type, + pub cast_ty: Type, +} + impl AnyDiagnostic { pub(crate) fn body_validation_diagnostic( db: &dyn HirDatabase, @@ -620,6 +640,16 @@ impl AnyDiagnostic { }; MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into() } + InferenceDiagnostic::CastToUnsized { expr, cast_ty } => { + let expr = expr_syntax(*expr)?; + CastToUnsized { expr, cast_ty: Type::new(db, def, cast_ty.clone()) }.into() + } + InferenceDiagnostic::InvalidCast { expr, error, expr_ty, cast_ty } => { + let expr = expr_syntax(*expr)?; + let expr_ty = Type::new(db, def, expr_ty.clone()); + let cast_ty = Type::new(db, def, cast_ty.clone()); + InvalidCast { expr, error: *error, expr_ty, cast_ty }.into() + } }) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 923dca646673c..c2b2fbef75177 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -99,17 +99,20 @@ impl HirDisplay for Function { } // FIXME: Use resolved `param.ty` once we no longer discard lifetimes + let body = db.body(self.id.into()); for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)).skip(skip_self) { - let local = param.as_local(db).map(|it| it.name(db)); if !first { f.write_str(", ")?; } else { first = false; } - match local { - Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?, - None => f.write_str("_: ")?, - } + + let pat_id = body.params[param.idx - body.self_param.is_some() as usize]; + let pat_str = + body.pretty_print_pat(db.upcast(), self.id.into(), pat_id, true, f.edition()); + f.write_str(&pat_str)?; + + f.write_str(": ")?; type_ref.hir_fmt(f)?; } diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 7d52a28b91e91..82c90ac30101b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -14,8 +14,8 @@ use tt::TextRange; use crate::{ db::HirDatabase, Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, - Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, Struct, Trait, - TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant, + InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, + Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant, }; pub trait HasSource { @@ -292,3 +292,26 @@ impl HasSource for ExternCrateDecl { Some(self.id.lookup(db.upcast()).source(db.upcast())) } } + +impl HasSource for InlineAsmOperand { + type Ast = ast::AsmOperandNamed; + fn source(self, db: &dyn HirDatabase) -> Option> { + let (_body, source_map) = db.body_with_source_map(self.owner); + if let Ok(src) = source_map.expr_syntax(self.expr) { + let root = src.file_syntax(db.upcast()); + return src + .map(|ast| match ast.to_node(&root) { + ast::Expr::AsmExpr(asm) => asm + .asm_pieces() + .filter_map(|it| match it { + ast::AsmPiece::AsmOperandNamed(it) => Some(it), + _ => None, + }) + .nth(self.index), + _ => None, + }) + .transpose(); + } + None + } +} diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 58340c74fea9d..8f5db32f9576e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -43,7 +43,7 @@ use hir_def::{ body::{BodyDiagnostic, SyntheticSyntax}, data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, - hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, + hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat}, item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode}, lang_item::LangItemTarget, layout::{self, ReprOptions, TargetDataLayout}, @@ -66,7 +66,7 @@ use hir_ty::{ diagnostics::BodyValidationDiagnostic, error_lifetime, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, - method_resolution::{self}, + method_resolution, mir::{interpret_mir, MutBorrowKind}, primitive::UintTy, traits::FnTrait, @@ -80,7 +80,7 @@ use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; use smallvec::SmallVec; use span::{Edition, EditionedFileId, FileId, MacroCallId, SyntaxContextId}; -use stdx::{impl_from, never}; +use stdx::{format_to, impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasGenericParams, HasName}, format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, T, @@ -137,6 +137,7 @@ pub use { hygiene::{marks_rev, SyntaxContextExt}, inert_attr_macro::AttributeTemplate, name::Name, + prettify_macro_expansion, proc_macro::{ProcMacros, ProcMacrosBuilder}, tt, ExpandResult, HirFileId, HirFileIdExt, MacroFileId, MacroFileIdExt, }, @@ -145,7 +146,8 @@ pub use { display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, layout::LayoutError, mir::{MirEvalError, MirLowerError}, - FnAbi, PointerCast, Safety, + object_safety::{MethodViolationCode, ObjectSafetyViolation}, + CastError, FnAbi, PointerCast, Safety, }, // FIXME: Properly encapsulate mir hir_ty::{mir, Interner as ChalkTyInterner}, @@ -1882,9 +1884,10 @@ impl DefWithBody { ); } - for expr in hir_ty::diagnostics::missing_unsafe(db, self.into()) { + let (unafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into()); + for expr in unafe_exprs { match source_map.expr_syntax(expr) { - Ok(expr) => acc.push(MissingUnsafe { expr }.into()), + Ok(expr) => acc.push(MissingUnsafe { expr, only_lint }.into()), Err(SyntheticSyntax) => { // FIXME: Here and elsewhere in this file, the `expr` was // desugared, report or assert that this doesn't happen. @@ -2206,6 +2209,35 @@ impl Function { db.function_data(self.id).is_async() } + pub fn returns_impl_future(self, db: &dyn HirDatabase) -> bool { + if self.is_async(db) { + return true; + } + + let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false }; + let Some(future_trait_id) = + db.lang_item(self.ty(db).env.krate, LangItem::Future).and_then(|t| t.as_trait()) + else { + return false; + }; + let Some(sized_trait_id) = + db.lang_item(self.ty(db).env.krate, LangItem::Sized).and_then(|t| t.as_trait()) + else { + return false; + }; + + let mut has_impl_future = false; + impl_traits + .filter(|t| { + let fut = t.id == future_trait_id; + has_impl_future |= fut; + !fut && t.id != sized_trait_id + }) + // all traits but the future trait must be auto traits + .all(|t| t.is_auto(db)) + && has_impl_future + } + /// Does this function have `#[test]` attribute? pub fn is_test(self, db: &dyn HirDatabase) -> bool { db.function_data(self.id).attrs.is_test() @@ -2522,6 +2554,17 @@ impl Const { Type::from_value_def(db, self.id) } + /// Evaluate the constant and return the result as a string. + /// + /// This function is intended for IDE assistance, different from [`Const::render_eval`]. + pub fn eval(self, db: &dyn HirDatabase, edition: Edition) -> Result { + let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?; + Ok(format!("{}", c.display(db, edition))) + } + + /// Evaluate the constant and return the result as a string, with more detailed information. + /// + /// This function is intended for user-facing display. pub fn render_eval( self, db: &dyn HirDatabase, @@ -2536,10 +2579,16 @@ impl Const { let value = u128::from_le_bytes(mir::pad16(b, false)); let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); + let mut result = if let Scalar::Int(_) = s { + value_signed.to_string() + } else { + value.to_string() + }; if value >= 10 { - return Ok(format!("{value_signed} ({value:#X})")); + format_to!(result, " ({value:#X})"); + return Ok(result); } else { - return Ok(format!("{value_signed}")); + return Ok(result); } } } @@ -2641,6 +2690,10 @@ impl Trait { .count() } + pub fn object_safety(&self, db: &dyn HirDatabase) -> Option { + hir_ty::object_safety::object_safety(db, self.id) + } + fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { db.trait_data(self.id) .macro_calls @@ -5211,6 +5264,26 @@ impl Type { } } +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub struct InlineAsmOperand { + owner: DefWithBodyId, + expr: ExprId, + index: usize, +} + +impl InlineAsmOperand { + pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { + self.owner.into() + } + + pub fn name(&self, db: &dyn HirDatabase) -> Option { + match &db.body(self.owner)[self.expr] { + hir_def::hir::Expr::InlineAsm(e) => e.operands.get(self.index)?.0.clone(), + _ => None, + } + } +} + // FIXME: Document this #[derive(Debug)] pub struct Callable { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 763f53031e4c5..fa14b53dbc3d7 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -13,7 +13,8 @@ use either::Either; use hir_def::{ hir::Expr, lower::LowerCtx, - nameres::MacroSubNs, + nameres::{MacroSubNs, ModuleOrigin}, + path::ModPath, resolver::{self, HasResolver, Resolver, TypeNs}, type_ref::Mutability, AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId, @@ -31,7 +32,7 @@ use intern::Symbol; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; -use span::{EditionedFileId, FileId}; +use span::{EditionedFileId, FileId, HirFileIdRepr}; use stdx::TupleExt; use syntax::{ algo::skip_trivia_token, @@ -46,9 +47,9 @@ use crate::{ source_analyzer::{resolve_hir_path, SourceAnalyzer}, Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile, - Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, - Static, Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, TypeParam, Union, - Variant, VariantDef, + InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, + OverloadedDeref, Path, ScopeDef, Static, Struct, ToolModule, Trait, TraitAlias, TupleField, + Type, TypeAlias, TypeParam, Union, Variant, VariantDef, }; const CONTINUE_NO_BREAKS: ControlFlow = ControlFlow::Continue(()); @@ -322,6 +323,47 @@ impl<'db> SemanticsImpl<'db> { tree } + pub fn find_parent_file(&self, file_id: HirFileId) -> Option> { + match file_id.repr() { + HirFileIdRepr::FileId(file_id) => { + let module = self.file_to_module_defs(file_id.file_id()).next()?; + let def_map = self.db.crate_def_map(module.krate().id); + match def_map[module.id.local_id].origin { + ModuleOrigin::CrateRoot { .. } => None, + ModuleOrigin::File { declaration, declaration_tree_id, .. } => { + let file_id = declaration_tree_id.file_id(); + let in_file = InFile::new(file_id, declaration); + let node = in_file.to_node(self.db.upcast()); + let root = find_root(node.syntax()); + self.cache(root, file_id); + Some(in_file.with_value(node.syntax().clone())) + } + _ => unreachable!("FileId can only belong to a file module"), + } + } + HirFileIdRepr::MacroFile(macro_file) => { + let node = self + .db + .lookup_intern_macro_call(macro_file.macro_call_id) + .to_node(self.db.upcast()); + let root = find_root(&node.value); + self.cache(root, node.file_id); + Some(node) + } + } + } + + /// Returns the `SyntaxNode` of the module. If this is a file module, returns + /// the `SyntaxNode` of the *definition* file, not of the *declaration*. + pub fn module_definition_node(&self, module: Module) -> InFile { + let def_map = module.id.def_map(self.db.upcast()); + let definition = def_map[module.id.local_id].origin.definition_source(self.db.upcast()); + let definition = definition.map(|it| it.node()); + let root_node = find_root(&definition.value); + self.cache(root_node, definition.file_id); + definition + } + pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode { let node = self.db.parse_or_expand(file_id); self.cache(node.clone(), file_id); @@ -344,6 +386,19 @@ impl<'db> SemanticsImpl<'db> { Some(node) } + pub fn check_cfg_attr(&self, attr: &ast::TokenTree) -> Option { + let file_id = self.find_file(attr.syntax()).file_id; + let krate = match file_id.repr() { + HirFileIdRepr::FileId(file_id) => { + self.file_to_module_defs(file_id.file_id()).next()?.krate().id + } + HirFileIdRepr::MacroFile(macro_file) => { + self.db.lookup_intern_macro_call(macro_file.macro_call_id).krate + } + }; + hir_expand::check_cfg_attr_value(self.db.upcast(), attr, krate) + } + /// Expands the macro if it isn't one of the built-in ones that expand to custom syntax or dummy /// expansions. pub fn expand_allowed_builtins(&self, macro_call: &ast::MacroCall) -> Option { @@ -367,7 +422,6 @@ impl<'db> SemanticsImpl<'db> { | BuiltinFnLikeExpander::File | BuiltinFnLikeExpander::ModulePath | BuiltinFnLikeExpander::Asm - | BuiltinFnLikeExpander::LlvmAsm | BuiltinFnLikeExpander::GlobalAsm | BuiltinFnLikeExpander::LogSyntax | BuiltinFnLikeExpander::TraceMacros @@ -408,7 +462,7 @@ impl<'db> SemanticsImpl<'db> { Some( calls .into_iter() - .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id })) + .map(|call| macro_call_to_macro_id(self, ctx, call?).map(|id| Macro { id })) .collect(), ) }) @@ -546,11 +600,11 @@ impl<'db> SemanticsImpl<'db> { ) } - /// Retrieves all the formatting parts of the format_args! template string. + /// Retrieves all the formatting parts of the format_args! (or `asm!`) template string. pub fn as_format_args_parts( &self, string: &ast::String, - ) -> Option)>> { + ) -> Option>)>> { let quote = string.open_quote_text_range()?; let token = self.wrap_token_infile(string.syntax().clone()).into_real_file().ok()?; @@ -560,14 +614,33 @@ impl<'db> SemanticsImpl<'db> { let string = ast::String::cast(token)?; let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; - let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?; - let source_analyzer = self.analyze_no_infer(format_args.syntax())?; - let format_args = self.wrap_node_infile(format_args); - let res = source_analyzer - .as_format_args_parts(self.db, format_args.as_ref())? - .map(|(range, res)| (range + quote.end(), res)) - .collect(); - Some(res) + let parent = literal.parent()?; + if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { + let source_analyzer = self.analyze_no_infer(format_args.syntax())?; + let format_args = self.wrap_node_infile(format_args); + let res = source_analyzer + .as_format_args_parts(self.db, format_args.as_ref())? + .map(|(range, res)| (range + quote.end(), res.map(Either::Left))) + .collect(); + Some(res) + } else { + let asm = ast::AsmExpr::cast(parent)?; + let source_analyzer = self.analyze_no_infer(asm.syntax())?; + let line = asm.template().position(|it| *it.syntax() == literal)?; + let asm = self.wrap_node_infile(asm); + let (owner, (expr, asm_parts)) = source_analyzer.as_asm_parts(asm.as_ref())?; + let res = asm_parts + .get(line)? + .iter() + .map(|&(range, index)| { + ( + range + quote.end(), + Some(Either::Right(InlineAsmOperand { owner, expr, index })), + ) + }) + .collect(); + Some(res) + } })() .map_or(ControlFlow::Continue(()), ControlFlow::Break) }) @@ -578,7 +651,7 @@ impl<'db> SemanticsImpl<'db> { &self, original_token: SyntaxToken, offset: TextSize, - ) -> Option<(TextRange, Option)> { + ) -> Option<(TextRange, Option>)> { let original_string = ast::String::cast(original_token.clone())?; let original_token = self.wrap_token_infile(original_token).into_real_file().ok()?; let quote = original_string.open_quote_text_range()?; @@ -599,13 +672,27 @@ impl<'db> SemanticsImpl<'db> { &self, string: ast::String, offset: TextSize, - ) -> Option<(TextRange, Option)> { + ) -> Option<(TextRange, Option>)> { debug_assert!(offset <= string.syntax().text_range().len()); let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; - let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?; - let source_analyzer = &self.analyze_no_infer(format_args.syntax())?; - let format_args = self.wrap_node_infile(format_args); - source_analyzer.resolve_offset_in_format_args(self.db, format_args.as_ref(), offset) + let parent = literal.parent()?; + if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { + let source_analyzer = &self.analyze_no_infer(format_args.syntax())?; + let format_args = self.wrap_node_infile(format_args); + source_analyzer + .resolve_offset_in_format_args(self.db, format_args.as_ref(), offset) + .map(|(range, res)| (range, res.map(Either::Left))) + } else { + let asm = ast::AsmExpr::cast(parent)?; + let source_analyzer = &self.analyze_no_infer(asm.syntax())?; + let line = asm.template().position(|it| *it.syntax() == literal)?; + let asm = self.wrap_node_infile(asm); + source_analyzer.resolve_offset_in_asm_template(asm.as_ref(), line, offset).map( + |(owner, (expr, range, index))| { + (range, Some(Either::Right(InlineAsmOperand { owner, expr, index }))) + }, + ) + } } /// Maps a node down by mapping its first and last token down. @@ -818,16 +905,7 @@ impl<'db> SemanticsImpl<'db> { let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| { Some( ctx.cache - .expansion_info_cache - .entry(macro_file) - .or_insert_with(|| { - let exp_info = macro_file.expansion_info(self.db.upcast()); - - let InMacroFile { file_id, value } = exp_info.expanded(); - self.cache(value, file_id.into()); - - exp_info - }) + .get_or_insert_expansion(self, macro_file) .map_range_down(span)? .map(SmallVec::<[_; 2]>::from_iter), ) @@ -1113,11 +1191,7 @@ impl<'db> SemanticsImpl<'db> { let macro_file = file_id.macro_file()?; self.with_ctx(|ctx| { - let expansion_info = ctx - .cache - .expansion_info_cache - .entry(macro_file) - .or_insert_with(|| macro_file.expansion_info(self.db.upcast())); + let expansion_info = ctx.cache.get_or_insert_expansion(self, macro_file); expansion_info.arg().map(|node| node?.parent()).transpose() }) } @@ -1333,7 +1407,7 @@ impl<'db> SemanticsImpl<'db> { let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call); self.with_ctx(|ctx| { ctx.macro_call_to_macro_call(macro_call) - .and_then(|call| macro_call_to_macro_id(ctx, call)) + .and_then(|call| macro_call_to_macro_id(self, ctx, call)) .map(Into::into) }) .or_else(|| { @@ -1375,7 +1449,7 @@ impl<'db> SemanticsImpl<'db> { let item_in_file = self.wrap_node_infile(item.clone()); let id = self.with_ctx(|ctx| { let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?; - macro_call_to_macro_id(ctx, macro_call_id) + macro_call_to_macro_id(self, ctx, macro_call_id) })?; Some(Macro { id }) } @@ -1384,6 +1458,16 @@ impl<'db> SemanticsImpl<'db> { self.analyze(path.syntax())?.resolve_path(self.db, path) } + pub fn resolve_mod_path( + &self, + scope: &SyntaxNode, + path: &ModPath, + ) -> Option> { + let analyze = self.analyze(scope)?; + let items = analyze.resolver.resolve_module_path_in_items(self.db.upcast(), path); + Some(items.iter_items().map(|(item, _)| item.into())) + } + fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit) } @@ -1685,6 +1769,7 @@ impl<'db> SemanticsImpl<'db> { } fn macro_call_to_macro_id( + sema: &SemanticsImpl<'_>, ctx: &mut SourceToDefCtx<'_, '_>, macro_call_id: MacroCallId, ) -> Option { @@ -1700,11 +1785,7 @@ fn macro_call_to_macro_id( it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) } HirFileIdRepr::MacroFile(macro_file) => { - let expansion_info = ctx - .cache - .expansion_info_cache - .entry(macro_file) - .or_insert_with(|| macro_file.expansion_info(ctx.db.upcast())); + let expansion_info = ctx.cache.get_or_insert_expansion(sema, macro_file); it.to_ptr(db).to_node(&expansion_info.expanded().value) } }; @@ -1716,11 +1797,7 @@ fn macro_call_to_macro_id( it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) } HirFileIdRepr::MacroFile(macro_file) => { - let expansion_info = ctx - .cache - .expansion_info_cache - .entry(macro_file) - .or_insert_with(|| macro_file.expansion_info(ctx.db.upcast())); + let expansion_info = ctx.cache.get_or_insert_expansion(sema, macro_file); it.to_ptr(db).to_node(&expansion_info.expanded().value) } }; @@ -1771,6 +1848,7 @@ to_def_impls![ (crate::Label, ast::Label, label_to_def), (crate::Adt, ast::Adt, adt_to_def), (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def), + (crate::InlineAsmOperand, ast::AsmOperandNamed, asm_operand_to_def), (MacroCallId, ast::MacroCall, macro_call_to_macro_call), ]; diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index 09df639d4a810..c1e4e1d1e2714 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -99,7 +99,8 @@ use hir_def::{ VariantId, }; use hir_expand::{ - attrs::AttrId, name::AsName, ExpansionInfo, HirFileId, HirFileIdExt, MacroCallId, + attrs::AttrId, name::AsName, ExpansionInfo, HirFileId, HirFileIdExt, InMacroFile, MacroCallId, + MacroFileIdExt, }; use rustc_hash::FxHashMap; use smallvec::SmallVec; @@ -110,15 +111,32 @@ use syntax::{ AstNode, AstPtr, SyntaxNode, }; -use crate::{db::HirDatabase, InFile}; +use crate::{db::HirDatabase, InFile, InlineAsmOperand, SemanticsImpl}; #[derive(Default)] pub(super) struct SourceToDefCache { pub(super) dynmap_cache: FxHashMap<(ChildContainer, HirFileId), DynMap>, - pub(super) expansion_info_cache: FxHashMap, + expansion_info_cache: FxHashMap, pub(super) file_to_def_cache: FxHashMap>, } +impl SourceToDefCache { + pub(super) fn get_or_insert_expansion( + &mut self, + sema: &SemanticsImpl<'_>, + macro_file: MacroFileId, + ) -> &ExpansionInfo { + self.expansion_info_cache.entry(macro_file).or_insert_with(|| { + let exp_info = macro_file.expansion_info(sema.db.upcast()); + + let InMacroFile { file_id, value } = exp_info.expanded(); + sema.cache(value, file_id.into()); + + exp_info + }) + } +} + pub(super) struct SourceToDefCtx<'db, 'cache> { pub(super) db: &'db dyn HirDatabase, pub(super) cache: &'cache mut SourceToDefCache, @@ -273,6 +291,25 @@ impl SourceToDefCtx<'_, '_> { ast::Adt::Union(it) => self.union_to_def(InFile::new(file_id, it)).map(AdtId::UnionId), } } + + pub(super) fn asm_operand_to_def( + &mut self, + src: InFile<&ast::AsmOperandNamed>, + ) -> Option { + let asm = src.value.syntax().parent().and_then(ast::AsmExpr::cast)?; + let index = asm + .asm_pieces() + .filter_map(|it| match it { + ast::AsmPiece::AsmOperandNamed(it) => Some(it), + _ => None, + }) + .position(|it| it == *src.value)?; + let container = self.find_pat_or_label_container(src.syntax_ref())?; + let (_, source_map) = self.db.body_with_source_map(container); + let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?; + Some(InlineAsmOperand { owner: container, expr, index }) + } + pub(super) fn bind_pat_to_def( &mut self, src: InFile<&ast::IdentPat>, @@ -281,7 +318,7 @@ impl SourceToDefCtx<'_, '_> { let (body, source_map) = self.db.body_with_source_map(container); let src = src.cloned().map(ast::Pat::from); let pat_id = source_map.node_pat(src.as_ref())?; - // the pattern could resolve to a constant, verify that that is not the case + // the pattern could resolve to a constant, verify that this is not the case if let crate::Pat::Bind { id, .. } = body[pat_id] { Some((container, id)) } else { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index be0116862b9cf..3da67ae23f83b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -904,6 +904,22 @@ impl SourceAnalyzer { }) } + pub(crate) fn resolve_offset_in_asm_template( + &self, + asm: InFile<&ast::AsmExpr>, + line: usize, + offset: TextSize, + ) -> Option<(DefWithBodyId, (ExprId, TextRange, usize))> { + let (def, _, body_source_map) = self.def.as_ref()?; + let (expr, args) = body_source_map.asm_template_args(asm)?; + Some(*def).zip( + args.get(line)? + .iter() + .find(|(range, _)| range.contains_inclusive(offset)) + .map(|(range, idx)| (expr, *range, *idx)), + ) + } + pub(crate) fn as_format_args_parts<'a>( &'a self, db: &'a dyn HirDatabase, @@ -927,6 +943,14 @@ impl SourceAnalyzer { )) } + pub(crate) fn as_asm_parts( + &self, + asm: InFile<&ast::AsmExpr>, + ) -> Option<(DefWithBodyId, (ExprId, &[Vec<(TextRange, usize)>]))> { + let (def, _, body_source_map) = self.def.as_ref()?; + Some(*def).zip(body_source_map.asm_template_args(asm)) + } + fn resolve_impl_method_or_trait_def( &self, db: &dyn HirDatabase, diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml index df52562b6a102..2a14fbe1e0a2d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml @@ -34,5 +34,8 @@ expect-test = "1.4.0" test-utils.workspace = true test-fixture.workspace = true +[features] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index b6abb06a2afc1..a211ca8f2d675 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -1,12 +1,13 @@ use std::iter::{self, Peekable}; use either::Either; -use hir::{sym, Adt, Crate, HasAttrs, HasSource, ImportPathConfig, ModuleDef, Semantics}; +use hir::{sym, Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics}; +use ide_db::syntax_helpers::suggest_name; use ide_db::RootDatabase; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; use syntax::ast::edit_in_place::Removable; -use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat}; +use syntax::ast::{self, make, AstNode, MatchArmList, MatchExpr, Pat}; use crate::{utils, AssistContext, AssistId, AssistKind, Assists}; @@ -90,7 +91,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .into_iter() .filter_map(|variant| { Some(( - build_pat(ctx.db(), module, variant, cfg)?, + build_pat(ctx, module, variant, cfg)?, variant.should_be_hidden(ctx.db(), module.krate()), )) }) @@ -141,9 +142,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let is_hidden = variants .iter() .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); - let patterns = variants - .into_iter() - .filter_map(|variant| build_pat(ctx.db(), module, variant, cfg)); + let patterns = + variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg)); (ast::Pat::from(make::tuple_pat(patterns)), is_hidden) }) @@ -174,9 +174,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let is_hidden = variants .iter() .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); - let patterns = variants - .into_iter() - .filter_map(|variant| build_pat(ctx.db(), module, variant, cfg)); + let patterns = + variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg)); (ast::Pat::from(make::slice_pat(patterns)), is_hidden) }) .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat)); @@ -438,33 +437,39 @@ fn resolve_array_of_enum_def( } fn build_pat( - db: &RootDatabase, + ctx: &AssistContext<'_>, module: hir::Module, var: ExtendedVariant, cfg: ImportPathConfig, ) -> Option { + let db = ctx.db(); match var { ExtendedVariant::Variant(var) => { let edition = module.krate().edition(db); let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition); - // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though - Some(match var.source(db)?.value.kind() { - ast::StructKind::Tuple(field_list) => { - let pats = - iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); + let fields = var.fields(db); + let pat = match var.kind(db) { + hir::StructKind::Tuple => { + let mut name_generator = suggest_name::NameGenerator::new(); + let pats = fields.into_iter().map(|f| { + let name = name_generator.for_type(&f.ty(db), db, edition); + match name { + Some(name) => make::ext::simple_ident_pat(make::name(&name)).into(), + None => make::wildcard_pat().into(), + } + }); make::tuple_struct_pat(path, pats).into() } - ast::StructKind::Record(field_list) => { - let pats = field_list.fields().map(|f| { - make::ext::simple_ident_pat( - f.name().expect("Record field must have a name"), - ) - .into() - }); + hir::StructKind::Record => { + let pats = fields + .into_iter() + .map(|f| make::name(f.name(db).as_str())) + .map(|name| make::ext::simple_ident_pat(name).into()); make::record_pat(path, pats).into() } - ast::StructKind::Unit => make::path_pat(path), - }) + hir::StructKind::Unit => make::path_pat(path), + }; + Some(pat) } ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))), ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))), @@ -1976,4 +1981,81 @@ fn a() { }"#, ) } + + #[test] + fn suggest_name_for_tuple_struct_patterns() { + // single tuple struct + check_assist( + add_missing_match_arms, + r#" +struct S; + +pub enum E { + A + B(S), +} + +fn f() { + let value = E::A; + match value { + $0 + } +} +"#, + r#" +struct S; + +pub enum E { + A + B(S), +} + +fn f() { + let value = E::A; + match value { + $0E::A => todo!(), + E::B(s) => todo!(), + } +} +"#, + ); + + // multiple tuple struct patterns + check_assist( + add_missing_match_arms, + r#" +struct S1; +struct S2; + +pub enum E { + A + B(S1, S2), +} + +fn f() { + let value = E::A; + match value { + $0 + } +} +"#, + r#" +struct S1; +struct S2; + +pub enum E { + A + B(S1, S2), +} + +fn f() { + let value = E::A; + match value { + $0E::A => todo!(), + E::B(s1, s2) => todo!(), + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs new file mode 100644 index 0000000000000..fafc3448a87ca --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs @@ -0,0 +1,206 @@ +use hir::Semantics; +use ide_db::{ + assists::{AssistId, AssistKind}, + source_change::SourceChangeBuilder, + RootDatabase, +}; +use syntax::{ast, AstNode}; + +use crate::{AssistContext, Assists}; + +// Assist: explicit_enum_discriminant +// +// Adds explicit discriminant to all enum variants. +// +// ``` +// enum TheEnum$0 { +// Foo, +// Bar, +// Baz = 42, +// Quux, +// } +// ``` +// -> +// ``` +// enum TheEnum { +// Foo = 0, +// Bar = 1, +// Baz = 42, +// Quux = 43, +// } +// ``` +pub(crate) fn explicit_enum_discriminant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let enum_node = ctx.find_node_at_offset::()?; + let enum_def = ctx.sema.to_def(&enum_node)?; + + let is_data_carrying = enum_def.is_data_carrying(ctx.db()); + let has_primitive_repr = enum_def.repr(ctx.db()).and_then(|repr| repr.int).is_some(); + + // Data carrying enums without a primitive repr have no stable discriminants. + if is_data_carrying && !has_primitive_repr { + return None; + } + + let variant_list = enum_node.variant_list()?; + + // Don't offer the assist if the enum has no variants or if all variants already have an + // explicit discriminant. + if variant_list.variants().all(|variant_node| variant_node.expr().is_some()) { + return None; + } + + acc.add( + AssistId("explicit_enum_discriminant", AssistKind::RefactorRewrite), + "Add explicit enum discriminants", + enum_node.syntax().text_range(), + |builder| { + for variant_node in variant_list.variants() { + add_variant_discriminant(&ctx.sema, builder, &variant_node); + } + }, + ); + + Some(()) +} + +fn add_variant_discriminant( + sema: &Semantics<'_, RootDatabase>, + builder: &mut SourceChangeBuilder, + variant_node: &ast::Variant, +) { + if variant_node.expr().is_some() { + return; + } + + let Some(variant_def) = sema.to_def(variant_node) else { + return; + }; + let Ok(discriminant) = variant_def.eval(sema.db) else { + return; + }; + + let variant_range = variant_node.syntax().text_range(); + + builder.insert(variant_range.end(), format!(" = {discriminant}")); +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::explicit_enum_discriminant; + + #[test] + fn non_primitive_repr_non_data_bearing_add_discriminant() { + check_assist( + explicit_enum_discriminant, + r#" +enum TheEnum$0 { + Foo, + Bar, + Baz = 42, + Quux, + FooBar = -5, + FooBaz, +} +"#, + r#" +enum TheEnum { + Foo = 0, + Bar = 1, + Baz = 42, + Quux = 43, + FooBar = -5, + FooBaz = -4, +} +"#, + ); + } + + #[test] + fn primitive_repr_data_bearing_add_discriminant() { + check_assist( + explicit_enum_discriminant, + r#" +#[repr(u8)] +$0enum TheEnum { + Foo { x: u32 }, + Bar, + Baz(String), + Quux, +} +"#, + r#" +#[repr(u8)] +enum TheEnum { + Foo { x: u32 } = 0, + Bar = 1, + Baz(String) = 2, + Quux = 3, +} +"#, + ); + } + + #[test] + fn non_primitive_repr_data_bearing_not_applicable() { + check_assist_not_applicable( + explicit_enum_discriminant, + r#" +enum TheEnum$0 { + Foo, + Bar(u16), + Baz, +} +"#, + ); + } + + #[test] + fn primitive_repr_non_data_bearing_add_discriminant() { + check_assist( + explicit_enum_discriminant, + r#" +#[repr(i64)] +enum TheEnum { + Foo = 1 << 63, + Bar, + Baz$0 = 0x7fff_ffff_ffff_fffe, + Quux, +} +"#, + r#" +#[repr(i64)] +enum TheEnum { + Foo = 1 << 63, + Bar = -9223372036854775807, + Baz = 0x7fff_ffff_ffff_fffe, + Quux = 9223372036854775807, +} +"#, + ); + } + + #[test] + fn discriminants_already_explicit_not_applicable() { + check_assist_not_applicable( + explicit_enum_discriminant, + r#" +enum TheEnum$0 { + Foo = 0, + Bar = 4, +} +"#, + ); + } + + #[test] + fn empty_enum_not_applicable() { + check_assist_not_applicable( + explicit_enum_discriminant, + r#" +enum TheEnum$0 {} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index dcf16e89b2c49..1eaf31628f318 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -2,7 +2,7 @@ use either::Either; use ide_db::syntax_helpers::node_ext::walk_ty; use syntax::{ ast::{self, edit::IndentLevel, make, AstNode, HasGenericArgs, HasGenericParams, HasName}, - ted, + syntax_editor, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -43,9 +43,8 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> AssistId("extract_type_alias", AssistKind::RefactorExtract), "Extract type as type alias", target, - |edit| { - let node = edit.make_syntax_mut(node.clone()); - let target_ty = edit.make_mut(ty.clone()); + |builder| { + let mut edit = builder.make_editor(node); let mut known_generics = match item.generic_param_list() { Some(it) => it.generic_params().collect(), @@ -67,25 +66,28 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> .map_or(String::new(), |it| it.to_generic_args().to_string()); // FIXME: replace with a `ast::make` constructor let new_ty = make::ty(&format!("Type{ty_args}")).clone_for_update(); - ted::replace(target_ty.syntax(), new_ty.syntax()); + edit.replace(ty.syntax(), new_ty.syntax()); // Insert new alias - let indent = IndentLevel::from_node(&node); let ty_alias = make::ty_alias("Type", generic_params, None, None, Some((ty, None))) .clone_for_update(); - ted::insert_all( - ted::Position::before(node), + + if let Some(cap) = ctx.config.snippet_cap { + if let Some(name) = ty_alias.name() { + edit.add_annotation(name.syntax(), builder.make_tabstop_before(cap)); + } + } + + let indent = IndentLevel::from_node(node); + edit.insert_all( + syntax_editor::Position::before(node), vec![ ty_alias.syntax().clone().into(), make::tokens::whitespace(&format!("\n\n{indent}")).into(), ], ); - if let Some(cap) = ctx.config.snippet_cap { - if let Some(name) = ty_alias.name() { - edit.add_tabstop_before(cap, name); - } - } + builder.add_file_edits(ctx.file_id(), edit); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 5ae75bb1ff8e0..a43a4b5e1a060 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -1,4 +1,5 @@ use hir::TypeInfo; +use ide_db::syntax_helpers::suggest_name; use syntax::{ ast::{self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasName}, ted, NodeOrToken, @@ -6,7 +7,7 @@ use syntax::{ SyntaxNode, T, }; -use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; +use crate::{AssistContext, AssistId, AssistKind, Assists}; // Assist: extract_variable // diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs index f40f2713ad131..af2c2c759ec78 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs @@ -1,4 +1,8 @@ -use syntax::{algo::non_trivia_sibling, Direction, SyntaxKind, T}; +use ide_db::base_db::SourceDatabase; +use syntax::TextSize; +use syntax::{ + algo::non_trivia_sibling, ast, AstNode, Direction, SyntaxKind, SyntaxToken, TextRange, T, +}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -21,6 +25,8 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let comma = ctx.find_token_syntax_at_offset(T![,])?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; + let (mut prev_text, mut next_text) = (prev.to_string(), next.to_string()); + let (mut prev_range, mut next_range) = (prev.text_range(), next.text_range()); // Don't apply a "flip" in case of a last comma // that typically comes before punctuation @@ -34,17 +40,55 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( return None; } + if let Some(parent) = comma.parent().and_then(ast::TokenTree::cast) { + // An attribute. It often contains a path followed by a token tree (e.g. `align(2)`), so we have + // to be smarter. + let prev_start = + match comma.siblings_with_tokens(Direction::Prev).skip(1).find(|it| it.kind() == T![,]) + { + Some(it) => position_after_token(it.as_token().unwrap()), + None => position_after_token(&parent.left_delimiter_token()?), + }; + let prev_end = prev.text_range().end(); + let next_start = next.text_range().start(); + let next_end = + match comma.siblings_with_tokens(Direction::Next).skip(1).find(|it| it.kind() == T![,]) + { + Some(it) => position_before_token(it.as_token().unwrap()), + None => position_before_token(&parent.right_delimiter_token()?), + }; + prev_range = TextRange::new(prev_start, prev_end); + next_range = TextRange::new(next_start, next_end); + let file_text = ctx.db().file_text(ctx.file_id().file_id()); + prev_text = file_text[prev_range].to_owned(); + next_text = file_text[next_range].to_owned(); + } + acc.add( AssistId("flip_comma", AssistKind::RefactorRewrite), "Flip comma", comma.text_range(), |edit| { - edit.replace(prev.text_range(), next.to_string()); - edit.replace(next.text_range(), prev.to_string()); + edit.replace(prev_range, next_text); + edit.replace(next_range, prev_text); }, ) } +fn position_before_token(token: &SyntaxToken) -> TextSize { + match non_trivia_sibling(token.clone().into(), Direction::Prev) { + Some(prev_token) => prev_token.text_range().end(), + None => token.text_range().start(), + } +} + +fn position_after_token(token: &SyntaxToken) -> TextSize { + match non_trivia_sibling(token.clone().into(), Direction::Next) { + Some(prev_token) => prev_token.text_range().start(), + None => token.text_range().end(), + } +} + #[cfg(test)] mod tests { use super::*; @@ -89,4 +133,18 @@ mod tests { // See https://github.com/rust-lang/rust-analyzer/issues/7693 check_assist_not_applicable(flip_comma, r#"bar!(a,$0 b)"#); } + + #[test] + fn flip_comma_attribute() { + check_assist( + flip_comma, + r#"#[repr(align(2),$0 C)] struct Foo;"#, + r#"#[repr(C, align(2))] struct Foo;"#, + ); + check_assist( + flip_comma, + r#"#[foo(bar, baz(1 + 1),$0 qux, other)] struct Foo;"#, + r#"#[foo(bar, qux, baz(1 + 1), other)] struct Foo;"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs index bf4ce5c907e80..66bf9b0186861 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -2,13 +2,14 @@ use std::ops::Not; use crate::{ assist_context::{AssistContext, Assists}, - utils::{convert_param_list_to_arg_list, suggest_name}, + utils::convert_param_list_to_arg_list, }; use either::Either; use hir::{db::HirDatabase, HasVisibility}; use ide_db::{ assists::{AssistId, GroupLabel}, path_transform::PathTransform, + syntax_helpers::suggest_name, FxHashMap, FxHashSet, }; use itertools::Itertools; @@ -281,8 +282,11 @@ fn generate_impl( ai.assoc_items() .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) .for_each(|item| { - let assoc = - process_assoc_item(item, qualified_path_type.clone(), field_name); + let assoc = process_assoc_item( + item.clone_for_update(), + qualified_path_type.clone(), + field_name, + ); if let Some(assoc) = assoc { delegate_assoc_items.add_item(assoc); } @@ -583,7 +587,7 @@ fn resolve_name_conflicts( for old_strukt_param in old_strukt_params.generic_params() { // Get old name from `strukt` - let mut name = SmolStr::from(match &old_strukt_param { + let name = SmolStr::from(match &old_strukt_param { ast::GenericParam::ConstParam(c) => c.name()?.to_string(), ast::GenericParam::LifetimeParam(l) => { l.lifetime()?.lifetime_ident_token()?.to_string() @@ -592,8 +596,19 @@ fn resolve_name_conflicts( }); // The new name cannot be conflicted with generics in trait, and the renamed names. - name = suggest_name::for_unique_generic_name(&name, old_impl_params); - name = suggest_name::for_unique_generic_name(&name, ¶ms); + let param_list_to_names = |param_list: &GenericParamList| { + param_list.generic_params().flat_map(|param| match param { + ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()), + p => Some(p.to_string()), + }) + }; + let existing_names = param_list_to_names(old_impl_params) + .chain(param_list_to_names(¶ms)) + .collect_vec(); + let mut name_generator = suggest_name::NameGenerator::new_with_names( + existing_names.iter().map(|s| s.as_str()), + ); + let name = name_generator.suggest_name(&name); match old_strukt_param { ast::GenericParam::ConstParam(c) => { if let Some(const_ty) = c.ty() { @@ -1212,9 +1227,9 @@ struct S { b : B, } -impl Trait for S { - fn f(&self, a: T0) -> T0 { - as Trait>::f(&self.b, a) +impl Trait for S { + fn f(&self, a: T1) -> T1 { + as Trait>::f(&self.b, a) } } "#, @@ -1526,12 +1541,12 @@ where b : B, } -impl Trait for S +impl Trait for S where - T10: AnotherTrait + T3: AnotherTrait { fn f(&self, a: T) -> T { - as Trait>::f(&self.b, a) + as Trait>::f(&self.b, a) } }"#, ); @@ -1588,12 +1603,12 @@ where b : B, } -impl Trait for S +impl Trait for S where - T0: AnotherTrait + T2: AnotherTrait { fn f(&self, a: T) -> T { - as Trait>::f(&self.b, a) + as Trait>::f(&self.b, a) } }"#, ); @@ -1785,4 +1800,40 @@ impl T for B { "#, ); } + + #[test] + fn assoc_items_attributes_mutably_cloned() { + check_assist( + generate_delegate_trait, + r#" +pub struct A; +pub trait C { + #[allow(clippy::dead_code)] + fn a_funk(&self) -> &D; +} + +pub struct B> { + has_dr$0ain: T, +} +"#, + r#" +pub struct A; +pub trait C { + #[allow(clippy::dead_code)] + fn a_funk(&self) -> &D; +} + +pub struct B> { + has_drain: T, +} + +impl> C for B { + #[allow(clippy::dead_code)] + fn a_funk(&self) -> &D { + >::a_funk(&self.has_drain) + } +} +"#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index 821783c283134..7b7dac9a3d6c4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -1,10 +1,22 @@ use syntax::{ - ast::{self, make, AstNode, HasName}, + ast::{self, edit_in_place::Indent, make, AstNode, HasName}, ted, }; use crate::{utils, AssistContext, AssistId, AssistKind, Assists}; +fn insert_impl(impl_: ast::Impl, nominal: &ast::Adt) { + let indent = nominal.indent_level(); + ted::insert_all_raw( + ted::Position::after(nominal.syntax()), + vec![ + // Add a blank line after the ADT, and indentation for the impl to match the ADT + make::tokens::whitespace(&format!("\n\n{indent}")).into(), + impl_.syntax().clone().into(), + ], + ); +} + // Assist: generate_impl // // Adds a new inherent impl for a type. @@ -46,12 +58,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio } } - // Add the impl after the adt - let nominal = edit.make_mut(nominal); - ted::insert_all_raw( - ted::Position::after(nominal.syntax()), - vec![make::tokens::blank_line().into(), impl_.syntax().clone().into()], - ); + insert_impl(impl_, &edit.make_mut(nominal)); }, ) } @@ -97,12 +104,7 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> } } - // Add the impl after the adt - let nominal = edit.make_mut(nominal); - ted::insert_all_raw( - ted::Position::after(nominal.syntax()), - vec![make::tokens::blank_line().into(), impl_.syntax().clone().into()], - ); + insert_impl(impl_, &edit.make_mut(nominal)); }, ) } @@ -418,4 +420,65 @@ mod tests { "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}", ); } + + #[test] + fn add_impl_with_indent() { + check_assist( + generate_impl, + r#" + mod foo { + struct Bar$0 {} + } + "#, + r#" + mod foo { + struct Bar {} + + impl Bar {$0} + } + "#, + ); + } + + #[test] + fn add_impl_with_multiple_indent() { + check_assist( + generate_impl, + r#" + mod foo { + fn bar() { + struct Baz$0 {} + } + } + "#, + r#" + mod foo { + fn bar() { + struct Baz {} + + impl Baz {$0} + } + } + "#, + ); + } + + #[test] + fn add_trait_impl_with_indent() { + check_assist( + generate_trait_impl, + r#" + mod foo { + struct Bar$0 {} + } + "#, + r#" + mod foo { + struct Bar {} + + impl ${0:_} for Bar {} + } + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 5bd204dd573b9..9e09f198feb4a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -2,14 +2,18 @@ use std::collections::BTreeSet; use ast::make; use either::Either; -use hir::{db::HirDatabase, sym, FileRange, PathResolution, Semantics, TypeInfo}; +use hir::{ + db::{ExpandDatabase, HirDatabase}, + sym, FileRange, PathResolution, Semantics, TypeInfo, +}; use ide_db::{ + base_db::CrateId, defs::Definition, imports::insert_use::remove_path_if_in_use_stmt, path_transform::PathTransform, search::{FileReference, FileReferenceNode, SearchScope}, source_change::SourceChangeBuilder, - syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref}, + syntax_helpers::{node_ext::expr_as_name_ref, prettify_macro_expansion}, EditionedFileId, RootDatabase, }; use itertools::{izip, Itertools}; @@ -102,12 +106,13 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> let mut remove_def = true; let mut inline_refs_for_file = |file_id, refs: Vec| { builder.edit_file(file_id); + let call_krate = ctx.sema.file_to_module_def(file_id).map(|it| it.krate()); let count = refs.len(); // The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️ let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some); let call_infos: Vec<_> = name_refs .into_iter() - .filter_map(CallInfo::from_name_ref) + .filter_map(|it| CallInfo::from_name_ref(it, call_krate?.into())) // FIXME: do not handle callsites in macros' parameters, because // directly inlining into macros may cause errors. .filter(|call_info| !ctx.sema.hir_file_for(call_info.node.syntax()).is_macro()) @@ -185,7 +190,10 @@ pub(super) fn split_refs_and_uses( // ``` pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let name_ref: ast::NameRef = ctx.find_node_at_offset()?; - let call_info = CallInfo::from_name_ref(name_ref.clone())?; + let call_info = CallInfo::from_name_ref( + name_ref.clone(), + ctx.sema.file_to_module_def(ctx.file_id())?.krate().into(), + )?; let (function, label) = match &call_info.node { ast::CallableExpr::Call(call) => { let path = match call.expr()? { @@ -243,10 +251,11 @@ struct CallInfo { node: ast::CallableExpr, arguments: Vec, generic_arg_list: Option, + krate: CrateId, } impl CallInfo { - fn from_name_ref(name_ref: ast::NameRef) -> Option { + fn from_name_ref(name_ref: ast::NameRef, krate: CrateId) -> Option { let parent = name_ref.syntax().parent()?; if let Some(call) = ast::MethodCallExpr::cast(parent.clone()) { let receiver = call.receiver()?; @@ -256,6 +265,7 @@ impl CallInfo { generic_arg_list: call.generic_arg_list(), node: ast::CallableExpr::MethodCall(call), arguments, + krate, }) } else if let Some(segment) = ast::PathSegment::cast(parent) { let path = segment.syntax().parent().and_then(ast::Path::cast)?; @@ -266,6 +276,7 @@ impl CallInfo { arguments: call.arg_list()?.args().collect(), node: ast::CallableExpr::Call(call), generic_arg_list: segment.generic_arg_list(), + krate, }) } else { None @@ -307,11 +318,15 @@ fn inline( function: hir::Function, fn_body: &ast::BlockExpr, params: &[(ast::Pat, Option, hir::Param)], - CallInfo { node, arguments, generic_arg_list }: &CallInfo, + CallInfo { node, arguments, generic_arg_list, krate }: &CallInfo, ) -> ast::Expr { - let mut body = if sema.hir_file_for(fn_body.syntax()).is_macro() { + let file_id = sema.hir_file_for(fn_body.syntax()); + let mut body = if let Some(macro_file) = file_id.macro_file() { cov_mark::hit!(inline_call_defined_in_macro); - if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) { + let span_map = sema.db.expansion_span_map(macro_file); + let body_prettified = + prettify_macro_expansion(sema.db, fn_body.syntax().clone(), &span_map, *krate); + if let Some(body) = ast::BlockExpr::cast(body_prettified) { body } else { fn_body.clone_for_update() @@ -420,8 +435,16 @@ fn inline( let mut insert_let_stmt = || { let param_ty = param_ty.clone().map(|param_ty| { - if sema.hir_file_for(param_ty.syntax()).is_macro() { - ast::Type::cast(insert_ws_into(param_ty.syntax().clone())).unwrap_or(param_ty) + let file_id = sema.hir_file_for(param_ty.syntax()); + if let Some(macro_file) = file_id.macro_file() { + let span_map = sema.db.expansion_span_map(macro_file); + let param_ty_prettified = prettify_macro_expansion( + sema.db, + param_ty.syntax().clone(), + &span_map, + *krate, + ); + ast::Type::cast(param_ty_prettified).unwrap_or(param_ty) } else { param_ty } @@ -1020,6 +1043,7 @@ fn main() { check_assist( inline_call, r#" +//- minicore: sized fn foo(x: *const u32) -> u32 { x as u32 } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs index f1c2acdd3ed91..6b504a918b403 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs @@ -53,10 +53,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_> | ast::Expr::BinExpr(_) | ast::Expr::CallExpr(_) => { let edition = ctx.sema.scope(variable.syntax())?.krate().edition(ctx.db()); - match konst.render_eval(ctx.sema.db, edition) { - Ok(result) => result, - Err(_) => return None, - } + konst.eval(ctx.sema.db, edition).ok()? } _ => return None, }; @@ -127,12 +124,14 @@ mod tests { ("u64", "0", NUMBER), ("u128", "0", NUMBER), ("usize", "0", NUMBER), + ("usize", "16", NUMBER), ("i8", "0", NUMBER), ("i16", "0", NUMBER), ("i32", "0", NUMBER), ("i64", "0", NUMBER), ("i128", "0", NUMBER), ("isize", "0", NUMBER), + ("isize", "16", NUMBER), ("bool", "false", BOOL), ("&str", "\"str\"", STR), ("char", "'c'", CHAR), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs index 6a1f7f26c92cc..b9fc075ae8382 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs @@ -333,7 +333,8 @@ fn foo() { check_assist( inline_local_variable, r" -fn bar(a: usize): usize { a } +//- minicore: sized +fn bar(a: usize) -> usize { a } fn foo() { let a$0 = bar(1) as u64; a + 1; @@ -347,7 +348,7 @@ fn foo() { bar(a); }", r" -fn bar(a: usize): usize { a } +fn bar(a: usize) -> usize { a } fn foo() { (bar(1) as u64) + 1; if (bar(1) as u64) > 10 { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs index 4708be616964f..d558ec3bec7d9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs @@ -1,4 +1,5 @@ -use ide_db::syntax_helpers::insert_whitespace_into_node::insert_ws_into; +use hir::db::ExpandDatabase; +use ide_db::syntax_helpers::prettify_macro_expansion; use syntax::ast::{self, AstNode}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -36,7 +37,15 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let unexpanded = ctx.find_node_at_offset::()?; - let expanded = insert_ws_into(ctx.sema.expand(&unexpanded)?.clone_for_update()); + let macro_call = ctx.sema.to_def(&unexpanded)?; + let expanded = ctx.sema.parse_or_expand(macro_call.as_file()); + let span_map = ctx.sema.db.expansion_span_map(macro_call.as_macro_file()); + let expanded = prettify_macro_expansion( + ctx.db(), + expanded, + &span_map, + ctx.sema.file_to_module_def(ctx.file_id())?.krate().into(), + ); let text_range = unexpanded.syntax().text_range(); acc.add( @@ -295,6 +304,75 @@ fn main() { } }; } +"#, + ); + } + + #[test] + fn dollar_crate() { + check_assist( + inline_macro, + r#" +pub struct Foo; +#[macro_export] +macro_rules! m { + () => { $crate::Foo }; +} +fn bar() { + m$0!(); +} +"#, + r#" +pub struct Foo; +#[macro_export] +macro_rules! m { + () => { $crate::Foo }; +} +fn bar() { + crate::Foo; +} +"#, + ); + check_assist( + inline_macro, + r#" +//- /a.rs crate:a +pub struct Foo; +#[macro_export] +macro_rules! m { + () => { $crate::Foo }; +} +//- /b.rs crate:b deps:a +fn bar() { + a::m$0!(); +} +"#, + r#" +fn bar() { + a::Foo; +} +"#, + ); + check_assist( + inline_macro, + r#" +//- /a.rs crate:a +pub struct Foo; +#[macro_export] +macro_rules! m { + () => { $crate::Foo }; +} +//- /b.rs crate:b deps:a +pub use a::m; +//- /c.rs crate:c deps:b +fn bar() { + b::m$0!(); +} +"#, + r#" +fn bar() { + a::Foo; +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs index f6624d6c872d0..66dffde505c13 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -43,6 +43,7 @@ use super::inline_call::split_refs_and_uses; // fn foo() { // let _: i32 = 3; // } +// ``` pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let name = ctx.find_node_at_offset::()?; let ast_alias = name.syntax().parent().and_then(ast::TypeAlias::cast)?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 543b7f7ab6329..bf6ac1719f318 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,9 +1,11 @@ +use ide_db::syntax_helpers::suggest_name; +use itertools::Itertools; use syntax::{ - ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasGenericParams}, + ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasGenericParams, HasName}, ted, }; -use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; +use crate::{AssistContext, AssistId, AssistKind, Assists}; // Assist: introduce_named_generic // @@ -32,8 +34,18 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let impl_trait_type = edit.make_mut(impl_trait_type); let fn_ = edit.make_mut(fn_); let fn_generic_param_list = fn_.get_or_create_generic_param_list(); - let type_param_name = - suggest_name::for_impl_trait_as_generic(&impl_trait_type, &fn_generic_param_list); + + let existing_names = fn_generic_param_list + .generic_params() + .flat_map(|param| match param { + ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()), + p => Some(p.to_string()), + }) + .collect_vec(); + let type_param_name = suggest_name::NameGenerator::new_with_names( + existing_names.iter().map(|s| s.as_str()), + ) + .for_impl_trait_as_generic(&impl_trait_type); let type_param = make::type_param(make::name(&type_param_name), Some(type_bound_list)) .clone_for_update(); @@ -115,7 +127,7 @@ fn foo<$0B: Bar check_assist( introduce_named_generic, r#"fn foo(bar: $0impl Bar) {}"#, - r#"fn foo(bar: B0) {}"#, + r#"fn foo(bar: B1) {}"#, ); } @@ -124,7 +136,7 @@ fn foo<$0B: Bar check_assist( introduce_named_generic, r#"fn foo(bar: $0impl Bar) {}"#, - r#"fn foo(bar: B2) {}"#, + r#"fn foo(bar: B4) {}"#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index d4fdc072fb5b5..c6f99d68748dd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -6,7 +6,10 @@ use ide_db::{ search::{FileReference, ReferenceCategory, SearchScope}, FxHashMap, RootDatabase, }; -use syntax::{ast, AstNode}; +use syntax::{ + ast::{self, Rename}, + AstNode, +}; use text_edit::TextRange; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -100,19 +103,19 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)), _ => None, }) - .any(|d| used_once_in_scope(ctx, d, scope)) + .any(|d| used_once_in_scope(ctx, d, u.rename(), scope)) { return Some(u); } } else if let Definition::Trait(ref t) = def { // If the trait or any item is used. - if !std::iter::once(def) - .chain(t.items(ctx.db()).into_iter().map(Definition::from)) - .any(|d| used_once_in_scope(ctx, d, scope)) + if !std::iter::once((def, u.rename())) + .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None))) + .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope)) { return Some(u); } - } else if !used_once_in_scope(ctx, def, scope) { + } else if !used_once_in_scope(ctx, def, u.rename(), scope) { return Some(u); } @@ -138,7 +141,12 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) } } -fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec) -> bool { +fn used_once_in_scope( + ctx: &AssistContext<'_>, + def: Definition, + rename: Option, + scopes: &Vec, +) -> bool { let mut found = false; for scope in scopes { @@ -151,7 +159,10 @@ fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec Quxx for T {} +} + +use foo::{Foo as Bar, Bar as Baz, Qux as _, Quxx as _}$0; + +fn test(_: Bar) { + let a = (); + a.quxx(); +} +"#, + r#" +mod foo { + pub struct Foo {} + pub struct Bar {} + pub struct Qux {} + pub trait Quux { + fn quxx(&self) {} + } + impl Quxx for T {} +} + +use foo::{Foo as Bar, Quxx as _}; + +fn test(_: Bar) { + let a = (); + a.quxx(); +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs index 59bb0c45e1439..a856da0921537 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -1,9 +1,10 @@ +use ide_db::syntax_helpers::suggest_name; use syntax::{ ast::{self, make, AstNode}, ted, }; -use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; +use crate::{AssistContext, AssistId, AssistKind, Assists}; // Assist: replace_is_some_with_if_let_some // diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index 65330b34c4ad2..1101c20f1b785 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -29,7 +29,7 @@ pub(crate) fn replace_qualified_name_with_use( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - let original_path: ast::Path = ctx.find_node_at_offset()?; + let mut original_path: ast::Path = ctx.find_node_at_offset()?; // We don't want to mess with use statements if original_path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() { cov_mark::hit!(not_applicable_in_use); @@ -37,8 +37,7 @@ pub(crate) fn replace_qualified_name_with_use( } if original_path.qualifier().is_none() { - cov_mark::hit!(dont_import_trivial_paths); - return None; + original_path = original_path.parent_path()?; } // only offer replacement for non assoc items @@ -236,12 +235,6 @@ fs::Path ); } - #[test] - fn dont_import_trivial_paths() { - cov_mark::check!(dont_import_trivial_paths); - check_assist_not_applicable(replace_qualified_name_with_use, r"impl foo$0 for () {}"); - } - #[test] fn test_replace_not_applicable_in_use() { cov_mark::check!(not_applicable_in_use); @@ -271,6 +264,29 @@ fn main() { ); } + #[test] + fn assist_runs_on_first_segment() { + check_assist( + replace_qualified_name_with_use, + r" +mod std { pub mod fmt { pub trait Debug {} } } +fn main() { + $0std::fmt::Debug; + let x: std::fmt::Debug = std::fmt::Debug; +} + ", + r" +use std::fmt; + +mod std { pub mod fmt { pub trait Debug {} } } +fn main() { + fmt::Debug; + let x: fmt::Debug = fmt::Debug; +} + ", + ); + } + #[test] fn does_not_replace_in_submodules() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs index eedb2ea3b9ada..e452b5f77870c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs @@ -64,12 +64,9 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) acc.add( AssistId("toggle_macro_delimiter", AssistKind::Refactor), match token { - MacroDelims::LPar => "Replace delimiters with braces", - MacroDelims::RPar => "Replace delimiters with braces", - MacroDelims::LBra => "Replace delimiters with parentheses", - MacroDelims::RBra => "Replace delimiters with parentheses", - MacroDelims::LCur => "Replace delimiters with brackets", - MacroDelims::RCur => "Replace delimiters with brackets", + MacroDelims::LPar | MacroDelims::RPar => "Replace delimiters with braces", + MacroDelims::LBra | MacroDelims::RBra => "Replace delimiters with parentheses", + MacroDelims::LCur | MacroDelims::RCur => "Replace delimiters with brackets", }, token_tree.syntax().text_range(), |builder| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs index b68ed00f77210..8f0e9b4fe09d5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs @@ -1,12 +1,14 @@ use std::iter; +use hir::HasSource; use ide_db::{ famous_defs::FamousDefs, syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, }; +use itertools::Itertools; use syntax::{ - ast::{self, make, Expr}, - match_ast, ted, AstNode, + ast::{self, make, Expr, HasGenericParams}, + match_ast, ted, AstNode, ToSmolStr, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -39,25 +41,22 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext< }; let type_ref = &ret_type.ty()?; - let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); - let result_enum = + let core_result = FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_result_Result()?; - if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == result_enum) { + let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); + if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_result) { + // The return type is already wrapped in a Result cov_mark::hit!(wrap_return_type_in_result_simple_return_type_already_result); return None; } - let new_result_ty = - make::ext::ty_result(type_ref.clone(), make::ty_placeholder()).clone_for_update(); - let generic_args = new_result_ty.syntax().descendants().find_map(ast::GenericArgList::cast)?; - let last_genarg = generic_args.generic_args().last()?; - acc.add( AssistId("wrap_return_type_in_result", AssistKind::RefactorRewrite), "Wrap return type in Result", type_ref.syntax().text_range(), |edit| { + let new_result_ty = result_type(ctx, &core_result, type_ref).clone_for_update(); let body = edit.make_mut(ast::Expr::BlockExpr(body)); let mut exprs_to_wrap = Vec::new(); @@ -81,16 +80,72 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext< } let old_result_ty = edit.make_mut(type_ref.clone()); - ted::replace(old_result_ty.syntax(), new_result_ty.syntax()); - if let Some(cap) = ctx.config.snippet_cap { - edit.add_placeholder_snippet(cap, last_genarg); + // Add a placeholder snippet at the first generic argument that doesn't equal the return type. + // This is normally the error type, but that may not be the case when we inserted a type alias. + let args = new_result_ty.syntax().descendants().find_map(ast::GenericArgList::cast); + let error_type_arg = args.and_then(|list| { + list.generic_args().find(|arg| match arg { + ast::GenericArg::TypeArg(_) => arg.syntax().text() != type_ref.syntax().text(), + ast::GenericArg::LifetimeArg(_) => false, + _ => true, + }) + }); + if let Some(error_type_arg) = error_type_arg { + if let Some(cap) = ctx.config.snippet_cap { + edit.add_placeholder_snippet(cap, error_type_arg); + } } }, ) } +fn result_type( + ctx: &AssistContext<'_>, + core_result: &hir::Enum, + ret_type: &ast::Type, +) -> ast::Type { + // Try to find a Result type alias in the current scope (shadowing the default). + let result_path = hir::ModPath::from_segments( + hir::PathKind::Plain, + iter::once(hir::Name::new_symbol_root(hir::sym::Result.clone())), + ); + let alias = ctx.sema.resolve_mod_path(ret_type.syntax(), &result_path).and_then(|def| { + def.filter_map(|def| match def.as_module_def()? { + hir::ModuleDef::TypeAlias(alias) => { + let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?; + (&enum_ty == core_result).then_some(alias) + } + _ => None, + }) + .find_map(|alias| { + let mut inserted_ret_type = false; + let generic_params = alias + .source(ctx.db())? + .value + .generic_param_list()? + .generic_params() + .map(|param| match param { + // Replace the very first type parameter with the functions return type. + ast::GenericParam::TypeParam(_) if !inserted_ret_type => { + inserted_ret_type = true; + ret_type.to_smolstr() + } + ast::GenericParam::LifetimeParam(_) => make::lifetime("'_").to_smolstr(), + _ => make::ty_placeholder().to_smolstr(), + }) + .join(", "); + + let name = alias.name(ctx.db()); + let name = name.as_str(); + Some(make::ty(&format!("{name}<{generic_params}>"))) + }) + }); + // If there is no applicable alias in scope use the default Result type. + alias.unwrap_or_else(|| make::ext::ty_result(ret_type.clone(), make::ty_placeholder())) +} + fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { match e { Expr::BreakExpr(break_expr) => { @@ -998,4 +1053,216 @@ fn foo(the_field: u32) -> Result { "#, ); } + + #[test] + fn wrap_return_type_in_local_result_type() { + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +type Result = core::result::Result; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +type Result = core::result::Result; + +fn foo() -> Result { + return Ok(42i32); +} +"#, + ); + + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +type Result2 = core::result::Result; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +type Result2 = core::result::Result; + +fn foo() -> Result { + return Ok(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_imported_local_result_type() { + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +mod some_module { + pub type Result = core::result::Result; +} + +use some_module::Result; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +mod some_module { + pub type Result = core::result::Result; +} + +use some_module::Result; + +fn foo() -> Result { + return Ok(42i32); +} +"#, + ); + + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +mod some_module { + pub type Result = core::result::Result; +} + +use some_module::*; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +mod some_module { + pub type Result = core::result::Result; +} + +use some_module::*; + +fn foo() -> Result { + return Ok(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_result_type_from_function_body() { + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +fn foo() -> i3$02 { + type Result = core::result::Result; + 0 +} +"#, + r#" +fn foo() -> Result { + type Result = core::result::Result; + Ok(0) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_result_type_already_using_alias() { + check_assist_not_applicable( + wrap_return_type_in_result, + r#" +//- minicore: result +pub type Result = core::result::Result; + +fn foo() -> Result { + return Ok(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_result_type_multiple_generics() { + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +type Result = core::result::Result; + +fn foo() -> i3$02 { + 0 +} +"#, + r#" +type Result = core::result::Result; + +fn foo() -> Result { + Ok(0) +} +"#, + ); + + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +type Result = core::result::Result, ()>; + +fn foo() -> i3$02 { + 0 +} + "#, + r#" +type Result = core::result::Result, ()>; + +fn foo() -> Result { + Ok(0) +} + "#, + ); + + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +type Result<'a, T, E> = core::result::Result, &'a ()>; + +fn foo() -> i3$02 { + 0 +} + "#, + r#" +type Result<'a, T, E> = core::result::Result, &'a ()>; + +fn foo() -> Result<'_, i32, ${0:_}> { + Ok(0) +} + "#, + ); + + check_assist( + wrap_return_type_in_result, + r#" +//- minicore: result +type Result = core::result::Result, Bar>; + +fn foo() -> i3$02 { + 0 +} + "#, + r#" +type Result = core::result::Result, Bar>; + +fn foo() -> Result { + Ok(0) +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs index 0fa46ef43a1ef..149cb4c43849d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs @@ -25,6 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // struct S { // field: i32 // } +// ``` enum WrapUnwrapOption { WrapDerive { derive: TextRange, attr: ast::Attr }, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index c88cb3d5eaf05..c98655b423029 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -58,6 +58,8 @@ //! See also this post: //! +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + mod assist_config; mod assist_context; #[cfg(test)] @@ -136,6 +138,7 @@ mod handlers { mod destructure_tuple_binding; mod desugar_doc_comment; mod expand_glob_import; + mod explicit_enum_discriminant; mod extract_expressions_from_format_string; mod extract_function; mod extract_module; @@ -266,6 +269,7 @@ mod handlers { destructure_tuple_binding::destructure_tuple_binding, destructure_struct_binding::destructure_struct_binding, expand_glob_import::expand_glob_import, + explicit_enum_discriminant::explicit_enum_discriminant, extract_expressions_from_format_string::extract_expressions_from_format_string, extract_struct_from_enum_variant::extract_struct_from_enum_variant, extract_type_alias::extract_type_alias, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index dce7bbf342f74..48e12a8107353 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -909,6 +909,29 @@ fn qux(bar: Bar, baz: Baz) {} ) } +#[test] +fn doctest_explicit_enum_discriminant() { + check_doc_test( + "explicit_enum_discriminant", + r#####" +enum TheEnum$0 { + Foo, + Bar, + Baz = 42, + Quux, +} +"#####, + r#####" +enum TheEnum { + Foo = 0, + Bar = 1, + Baz = 42, + Quux = 43, +} +"#####, + ) +} + #[test] fn doctest_extract_expressions_from_format_string() { check_doc_test( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index b8a6f3b6dbeb2..0830017bd0fdd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -1,10 +1,13 @@ //! Assorted functions shared by several assists. pub(crate) use gen_trait_fn_body::gen_trait_fn_body; -use hir::{db::HirDatabase, HasAttrs as HirHasAttrs, HirDisplay, InFile, Semantics}; +use hir::{ + db::{ExpandDatabase, HirDatabase}, + HasAttrs as HirHasAttrs, HirDisplay, InFile, Semantics, +}; use ide_db::{ famous_defs::FamousDefs, path_transform::PathTransform, - syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase, + syntax_helpers::prettify_macro_expansion, RootDatabase, }; use stdx::format_to; use syntax::{ @@ -23,7 +26,6 @@ use crate::assist_context::{AssistContext, SourceChangeBuilder}; mod gen_trait_fn_body; pub(crate) mod ref_field_expr; -pub(crate) mod suggest_name; pub(crate) fn unwrap_trivial_block(block_expr: ast::BlockExpr) -> ast::Expr { extract_trivial_expression(&block_expr) @@ -179,10 +181,15 @@ pub fn add_trait_assoc_items_to_impl( let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; let items = original_items.iter().map(|InFile { file_id, value: original_item }| { let cloned_item = { - if file_id.is_macro() { - if let Some(formatted) = - ast::AssocItem::cast(insert_ws_into(original_item.syntax().clone())) - { + if let Some(macro_file) = file_id.macro_file() { + let span_map = sema.db.expansion_span_map(macro_file); + let item_prettified = prettify_macro_expansion( + sema.db, + original_item.syntax().clone(), + &span_map, + target_scope.krate().into(), + ); + if let Some(formatted) = ast::AssocItem::cast(item_prettified) { return formatted; } else { stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`"); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index b537150608bb0..414627fbabae1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -617,6 +617,16 @@ impl Completions { } self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name)); } + + pub(crate) fn suggest_name(&mut self, ctx: &CompletionContext<'_>, name: &str) { + let item = CompletionItem::new( + CompletionItemKind::Binding, + ctx.source_range(), + SmolStr::from(name), + ctx.edition, + ); + item.add_to(self, ctx.db); + } } /// Calls the callback for each variant of the provided enum with the path to the variant. diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index 9821fb4a2fa95..d0b489c4e836c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -56,7 +56,7 @@ pub(crate) fn complete_known_attribute_input( &parse_tt_as_comma_sep_paths(tt, ctx.edition)?, FEATURES, ), - "allow" | "warn" | "deny" | "forbid" => { + "allow" | "expect" | "deny" | "forbid" | "warn" => { let existing_lints = parse_tt_as_comma_sep_paths(tt, ctx.edition)?; let lints: Vec = CLIPPY_LINT_GROUPS @@ -222,7 +222,7 @@ macro_rules! attrs { [@ {} {$($tt:tt)*}] => { &[$($tt)*] as _ }; // starting matcher [$($tt:tt),*] => { - attrs!(@ { $($tt)* } { "allow", "cfg", "cfg_attr", "deny", "forbid", "warn" }) + attrs!(@ { $($tt)* } { "allow", "cfg", "cfg_attr", "deny", "expect", "forbid", "warn" }) }; } @@ -303,6 +303,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[ attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)), attr(r#"doc(hidden)"#, Some("dochidden"), Some(r#"doc(hidden)"#)), + attr("expect(…)", Some("expect"), Some("expect(${0:lint})")), attr( r#"export_name = "…""#, Some("export_name"), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index d55bc3ea5d03a..f2c360a9d5bfd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -600,7 +600,7 @@ fn foo(a: A) { a.$0 } struct A {} trait Trait { fn the_method(&self); } impl Trait for A {} -fn foo(a: A) { a.the_method()$0 } +fn foo(a: A) { a.the_method();$0 } "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index 1a06e0a3a0e73..b0e417e6b3351 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -32,6 +32,7 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ "riscv-interrupt-m", "riscv-interrupt-s", "C-cmse-nonsecure-call", + "C-cmse-nonsecure-entry", "wasm", "system", "system-unwind", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index fc6e1ebf05fc6..672e1796d1eff 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -31,14 +31,14 @@ //! } //! ``` -use hir::HasAttrs; +use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name}; use ide_db::{ documentation::HasDocs, path_transform::PathTransform, - syntax_helpers::insert_whitespace_into_node, traits::get_missing_assoc_items, SymbolKind, + syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items, SymbolKind, }; use syntax::{ - ast::{self, edit_in_place::AttrsOwnerEdit, HasTypeBounds}, - format_smolstr, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T, + ast::{self, edit_in_place::AttrsOwnerEdit, make, HasGenericArgs, HasTypeBounds}, + format_smolstr, ted, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T, }; use text_edit::TextEdit; @@ -178,12 +178,36 @@ fn add_function_impl( func: hir::Function, impl_def: hir::Impl, ) { - let fn_name = func.name(ctx.db); + let fn_name = &func.name(ctx.db); + let sugar: &[_] = if func.is_async(ctx.db) { + &[AsyncSugaring::Async, AsyncSugaring::Desugar] + } else if func.returns_impl_future(ctx.db) { + &[AsyncSugaring::Plain, AsyncSugaring::Resugar] + } else { + &[AsyncSugaring::Plain] + }; + for &sugaring in sugar { + add_function_impl_(acc, ctx, replacement_range, func, impl_def, fn_name, sugaring); + } +} - let is_async = func.is_async(ctx.db); +fn add_function_impl_( + acc: &mut Completions, + ctx: &CompletionContext<'_>, + replacement_range: TextRange, + func: hir::Function, + impl_def: hir::Impl, + fn_name: &Name, + async_sugaring: AsyncSugaring, +) { + let async_ = if let AsyncSugaring::Async | AsyncSugaring::Resugar = async_sugaring { + "async " + } else { + "" + }; let label = format_smolstr!( "{}fn {}({})", - if is_async { "async " } else { "" }, + async_, fn_name.display(ctx.db, ctx.edition), if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." } ); @@ -195,23 +219,16 @@ fn add_function_impl( }); let mut item = CompletionItem::new(completion_kind, replacement_range, label, ctx.edition); - item.lookup_by(format!( - "{}fn {}", - if is_async { "async " } else { "" }, - fn_name.display(ctx.db, ctx.edition) - )) - .set_documentation(func.docs(ctx.db)) - .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); + item.lookup_by(format!("{}fn {}", async_, fn_name.display(ctx.db, ctx.edition))) + .set_documentation(func.docs(ctx.db)) + .set_relevance(CompletionRelevance { exact_name_match: true, ..Default::default() }); if let Some(source) = ctx.sema.source(func) { - let assoc_item = ast::AssocItem::Fn(source.value); - if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { - let transformed_fn = match transformed_item { - ast::AssocItem::Fn(func) => func, - _ => unreachable!(), - }; - - let function_decl = function_declaration(&transformed_fn, source.file_id.is_macro()); + if let Some(transformed_fn) = + get_transformed_fn(ctx, source.value, impl_def, async_sugaring) + { + let function_decl = + function_declaration(ctx, &transformed_fn, source.file_id.macro_file()); match ctx.config.snippet_cap { Some(cap) => { let snippet = format!("{function_decl} {{\n $0\n}}"); @@ -227,6 +244,14 @@ fn add_function_impl( } } +#[derive(Copy, Clone)] +enum AsyncSugaring { + Desugar, + Resugar, + Async, + Plain, +} + /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc. fn get_transformed_assoc_item( ctx: &CompletionContext<'_>, @@ -251,6 +276,82 @@ fn get_transformed_assoc_item( Some(assoc_item) } +/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc. +fn get_transformed_fn( + ctx: &CompletionContext<'_>, + fn_: ast::Fn, + impl_def: hir::Impl, + async_: AsyncSugaring, +) -> Option { + let trait_ = impl_def.trait_(ctx.db)?; + let source_scope = &ctx.sema.scope(fn_.syntax())?; + let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?; + let transform = PathTransform::trait_impl( + target_scope, + source_scope, + trait_, + ctx.sema.source(impl_def)?.value, + ); + + let fn_ = fn_.clone_for_update(); + // FIXME: Paths in nested macros are not handled well. See + // `macro_generated_assoc_item2` test. + transform.apply(fn_.syntax()); + fn_.remove_attrs_and_docs(); + match async_ { + AsyncSugaring::Desugar => { + match fn_.ret_type() { + Some(ret_ty) => { + let ty = ret_ty.ty()?; + ted::replace( + ty.syntax(), + make::ty(&format!("impl Future")) + .syntax() + .clone_for_update(), + ); + } + None => ted::append_child( + fn_.param_list()?.syntax(), + make::ret_type(make::ty("impl Future")) + .syntax() + .clone_for_update(), + ), + } + fn_.async_token().unwrap().detach(); + } + AsyncSugaring::Resugar => { + let ty = fn_.ret_type()?.ty()?; + match &ty { + // best effort guessing here + ast::Type::ImplTraitType(t) => { + let output = t.type_bound_list()?.bounds().find_map(|b| match b.ty()? { + ast::Type::PathType(p) => { + let p = p.path()?.segment()?; + if p.name_ref()?.text() != "Future" { + return None; + } + match p.generic_arg_list()?.generic_args().next()? { + ast::GenericArg::AssocTypeArg(a) + if a.name_ref()?.text() == "Output" => + { + a.ty() + } + _ => None, + } + } + _ => None, + })?; + ted::replace(ty.syntax(), output.syntax()); + } + _ => (), + } + ted::prepend_child(fn_.syntax(), make::token(T![async])); + } + AsyncSugaring::Async | AsyncSugaring::Plain => (), + } + Some(fn_) +} + fn add_type_alias_impl( acc: &mut Completions, ctx: &CompletionContext<'_>, @@ -266,7 +367,7 @@ fn add_type_alias_impl( CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label, ctx.edition); item.lookup_by(format!("type {alias_name}")) .set_documentation(type_alias.docs(ctx.db)) - .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); + .set_relevance(CompletionRelevance { exact_name_match: true, ..Default::default() }); if let Some(source) = ctx.sema.source(type_alias) { let assoc_item = ast::AssocItem::TypeAlias(source.value); @@ -332,7 +433,8 @@ fn add_const_impl( _ => unreachable!(), }; - let label = make_const_compl_syntax(&transformed_const, source.file_id.is_macro()); + let label = + make_const_compl_syntax(ctx, &transformed_const, source.file_id.macro_file()); let replacement = format!("{label} "); let mut item = @@ -340,7 +442,7 @@ fn add_const_impl( item.lookup_by(format_smolstr!("const {const_name}")) .set_documentation(const_.docs(ctx.db)) .set_relevance(CompletionRelevance { - is_item_from_trait: true, + exact_name_match: true, ..Default::default() }); match ctx.config.snippet_cap { @@ -356,9 +458,14 @@ fn add_const_impl( } } -fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> SmolStr { - let const_ = if needs_whitespace { - insert_whitespace_into_node::insert_ws_into(const_.syntax().clone()) +fn make_const_compl_syntax( + ctx: &CompletionContext<'_>, + const_: &ast::Const, + macro_file: Option, +) -> SmolStr { + let const_ = if let Some(macro_file) = macro_file { + let span_map = ctx.db.expansion_span_map(macro_file); + prettify_macro_expansion(ctx.db, const_.syntax().clone(), &span_map, ctx.krate.into()) } else { const_.syntax().clone() }; @@ -379,9 +486,14 @@ fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> SmolS format_smolstr!("{} =", syntax.trim_end()) } -fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String { - let node = if needs_whitespace { - insert_whitespace_into_node::insert_ws_into(node.syntax().clone()) +fn function_declaration( + ctx: &CompletionContext<'_>, + node: &ast::Fn, + macro_file: Option, +) -> String { + let node = if let Some(macro_file) = macro_file { + let span_map = ctx.db.expansion_span_map(macro_file); + prettify_macro_expansion(ctx.db, node.syntax().clone(), &span_map, ctx.krate.into()) } else { node.syntax().clone() }; @@ -1401,6 +1513,134 @@ trait Tr { impl Tr for () { type Item = $0; } +"#, + ); + } + + #[test] + fn impl_fut() { + check_edit( + "fn foo", + r#" +//- minicore: future, send, sized +use core::future::Future; + +trait DesugaredAsyncTrait { + fn foo(&self) -> impl Future + Send; +} + +impl DesugaredAsyncTrait for () { + $0 +} +"#, + r#" +use core::future::Future; + +trait DesugaredAsyncTrait { + fn foo(&self) -> impl Future + Send; +} + +impl DesugaredAsyncTrait for () { + fn foo(&self) -> impl Future + Send { + $0 +} +} +"#, + ); + } + + #[test] + fn impl_fut_resugared() { + check_edit( + "async fn foo", + r#" +//- minicore: future, send, sized +use core::future::Future; + +trait DesugaredAsyncTrait { + fn foo(&self) -> impl Future + Send; +} + +impl DesugaredAsyncTrait for () { + $0 +} +"#, + r#" +use core::future::Future; + +trait DesugaredAsyncTrait { + fn foo(&self) -> impl Future + Send; +} + +impl DesugaredAsyncTrait for () { + async fn foo(&self) -> usize { + $0 +} +} +"#, + ); + } + + #[test] + fn async_desugared() { + check_edit( + "fn foo", + r#" +//- minicore: future, send, sized +use core::future::Future; + +trait DesugaredAsyncTrait { + async fn foo(&self) -> usize; +} + +impl DesugaredAsyncTrait for () { + $0 +} +"#, + r#" +use core::future::Future; + +trait DesugaredAsyncTrait { + async fn foo(&self) -> usize; +} + +impl DesugaredAsyncTrait for () { + fn foo(&self) -> impl Future { + $0 +} +} +"#, + ); + } + + #[test] + fn async_() { + check_edit( + "async fn foo", + r#" +//- minicore: future, send, sized +use core::future::Future; + +trait DesugaredAsyncTrait { + async fn foo(&self) -> usize; +} + +impl DesugaredAsyncTrait for () { + $0 +} +"#, + r#" +use core::future::Future; + +trait DesugaredAsyncTrait { + async fn foo(&self) -> usize; +} + +impl DesugaredAsyncTrait for () { + async fn foo(&self) -> usize { + $0 +} +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 3f50cd55cb365..0acb87872f5e3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -150,6 +150,68 @@ fn foo(a: A) { a.$0 } ); } + #[test] + fn for_in_impl() { + check_edit( + "for", + r#" +struct X; +impl X $0 {} +"#, + r#" +struct X; +impl X for $0 {} +"#, + ); + check_edit( + "for", + r#" +fn foo() { + struct X; + impl X $0 {} +} +"#, + r#" +fn foo() { + struct X; + impl X for $0 {} +} +"#, + ); + check_edit( + "for", + r#" +fn foo() { + struct X; + impl X $0 +} +"#, + r#" +fn foo() { + struct X; + impl X for $0 +} +"#, + ); + check_edit( + "for", + r#" +fn foo() { + struct X; + impl X { fn bar() { $0 } } +} +"#, + r#" +fn foo() { + struct X; + impl X { fn bar() { for $1 in $2 { + $0 +} } } +} +"#, + ); + } + #[test] fn let_semi() { cov_mark::check!(let_semi); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs index 60cfb7e5a8c5a..8f38e02ed7685 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs @@ -1,6 +1,7 @@ //! Completes constants and paths in unqualified patterns. use hir::{db::DefDatabase, AssocItem, ScopeDef}; +use ide_db::syntax_helpers::suggest_name; use syntax::ast::Pat; use crate::{ @@ -45,6 +46,19 @@ pub(crate) fn complete_pattern( return; } + // Suggest name only in let-stmt and fn param + if pattern_ctx.should_suggest_name { + let mut name_generator = suggest_name::NameGenerator::new(); + if let Some(suggested) = ctx + .expected_type + .as_ref() + .map(|ty| ty.strip_references()) + .and_then(|ty| name_generator.for_type(&ty, ctx.db, ctx.edition)) + { + acc.suggest_name(ctx, &suggested); + } + } + let refutable = pattern_ctx.refutability == PatternRefutability::Refutable; let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index a632f148936dc..d3579fd8cc6e0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -294,6 +294,18 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) { let mut new_element_opt = initial_element.clone(); + while let Some(parent_deref_element) = + resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast) + { + if parent_deref_element.op_kind() != Some(ast::UnaryOp::Deref) { + break; + } + + resulting_element = ast::Expr::from(parent_deref_element); + + new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt); + } + if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) { if let Some(expr) = first_ref_expr.expr() { resulting_element = expr; @@ -302,9 +314,10 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) { while let Some(parent_ref_element) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) { + let exclusive = parent_ref_element.mut_token().is_some(); resulting_element = ast::Expr::from(parent_ref_element); - new_element_opt = make::expr_ref(new_element_opt, false); + new_element_opt = make::expr_ref(new_element_opt, exclusive); } } else { // If we do not find any ref expressions, restore @@ -855,4 +868,42 @@ fn test() { expect![[r#""#]], ); } + + #[test] + fn mut_ref_consuming() { + check_edit( + "call", + r#" +fn main() { + let mut x = &mut 2; + &mut x.$0; +} +"#, + r#" +fn main() { + let mut x = &mut 2; + ${1}(&mut x); +} +"#, + ); + } + + #[test] + fn deref_consuming() { + check_edit( + "call", + r#" +fn main() { + let mut x = &mut 2; + &mut *x.$0; +} +"#, + r#" +fn main() { + let mut x = &mut 2; + ${1}(&mut *x); +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs index d885b82ec90df..0d403f49b7a87 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs @@ -19,6 +19,7 @@ pub struct CompletionConfig { pub term_search_fuel: u64, pub full_function_signatures: bool, pub callable: Option, + pub add_semicolon_to_unit: bool, pub snippet_cap: Option, pub insert_use: InsertUseConfig, pub prefer_no_std: bool, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index bcd9df941947f..192f1b43face0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -4,7 +4,7 @@ mod analysis; #[cfg(test)] mod tests; -use std::iter; +use std::{iter, ops::ControlFlow}; use hir::{ HasAttrs, Local, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo, @@ -15,7 +15,7 @@ use ide_db::{ }; use syntax::{ ast::{self, AttrKind, NameOrNameRef}, - AstNode, Edition, SmolStr, + match_ast, AstNode, Edition, SmolStr, SyntaxKind::{self, *}, SyntaxToken, TextRange, TextSize, T, }; @@ -26,7 +26,7 @@ use crate::{ CompletionConfig, }; -const COMPLETION_MARKER: &str = "intellijRulezz"; +const COMPLETION_MARKER: &str = "raCompletionMarker"; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum PatternRefutability { @@ -264,6 +264,7 @@ pub(crate) struct PatternContext { pub(crate) refutability: PatternRefutability, pub(crate) param_ctx: Option, pub(crate) has_type_ascription: bool, + pub(crate) should_suggest_name: bool, pub(crate) parent_pat: Option, pub(crate) ref_token: Option, pub(crate) mut_token: Option, @@ -456,6 +457,16 @@ pub(crate) struct CompletionContext<'a> { /// /// Here depth will be 2 pub(crate) depth_from_crate_root: usize, + + /// Whether and how to complete semicolon for unit-returning functions. + pub(crate) complete_semicolon: CompleteSemicolon, +} + +#[derive(Debug)] +pub(crate) enum CompleteSemicolon { + DoNotComplete, + CompleteSemi, + CompleteComma, } impl CompletionContext<'_> { @@ -734,6 +745,53 @@ impl<'a> CompletionContext<'a> { let depth_from_crate_root = iter::successors(module.parent(db), |m| m.parent(db)).count(); + let complete_semicolon = if config.add_semicolon_to_unit { + let inside_closure_ret = token.parent_ancestors().try_for_each(|ancestor| { + match_ast! { + match ancestor { + ast::BlockExpr(_) => ControlFlow::Break(false), + ast::ClosureExpr(_) => ControlFlow::Break(true), + _ => ControlFlow::Continue(()) + } + } + }); + + if inside_closure_ret == ControlFlow::Break(true) { + CompleteSemicolon::DoNotComplete + } else { + let next_non_trivia_token = + std::iter::successors(token.next_token(), |it| it.next_token()) + .find(|it| !it.kind().is_trivia()); + let in_match_arm = token.parent_ancestors().try_for_each(|ancestor| { + if ast::MatchArm::can_cast(ancestor.kind()) { + ControlFlow::Break(true) + } else if matches!( + ancestor.kind(), + SyntaxKind::EXPR_STMT | SyntaxKind::BLOCK_EXPR + ) { + ControlFlow::Break(false) + } else { + ControlFlow::Continue(()) + } + }); + // FIXME: This will assume expr macros are not inside match, we need to somehow go to the "parent" of the root node. + let in_match_arm = match in_match_arm { + ControlFlow::Continue(()) => false, + ControlFlow::Break(it) => it, + }; + let complete_token = if in_match_arm { T![,] } else { T![;] }; + if next_non_trivia_token.map(|it| it.kind()) == Some(complete_token) { + CompleteSemicolon::DoNotComplete + } else if in_match_arm { + CompleteSemicolon::CompleteComma + } else { + CompleteSemicolon::CompleteSemi + } + } + } else { + CompleteSemicolon::DoNotComplete + }; + let ctx = CompletionContext { sema, scope, @@ -751,6 +809,7 @@ impl<'a> CompletionContext<'a> { qualifier_ctx, locals, depth_from_crate_root, + complete_semicolon, }; Some((ctx, analysis)) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index ed359394f1c49..1f9e3edf625d1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1132,10 +1132,18 @@ fn classify_name_ref( ast::PathType(it) => make_path_kind_type(it.into()), ast::PathExpr(it) => { if let Some(p) = it.syntax().parent() { - if ast::ExprStmt::can_cast(p.kind()) { - if let Some(kind) = inbetween_body_and_decl_check(p) { - return Some(make_res(NameRefKind::Keyword(kind))); - } + let p_kind = p.kind(); + // The syntax node of interest, for which we want to check whether + // it is sandwiched between an item decl signature and its body. + let probe = if ast::ExprStmt::can_cast(p_kind) { + Some(p) + } else if ast::StmtList::can_cast(p_kind) { + Some(it.syntax().clone()) + } else { + None + }; + if let Some(kind) = probe.and_then(inbetween_body_and_decl_check) { + return Some(make_res(NameRefKind::Keyword(kind))); } } @@ -1199,7 +1207,13 @@ fn classify_name_ref( } } }, - ast::RecordExpr(it) => make_path_kind_expr(it.into()), + ast::RecordExpr(it) => { + // A record expression in this position is usually a result of parsing recovery, so check that + if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) { + return Some(make_res(NameRefKind::Keyword(kind))); + } + make_path_kind_expr(it.into()) + }, _ => return None, } }; @@ -1416,10 +1430,23 @@ fn pattern_context_for( _ => (None, None), }; + // Only suggest name in let-stmt or fn param + let should_suggest_name = matches!( + &pat, + ast::Pat::IdentPat(it) + if it.syntax() + .parent() + .map_or(false, |node| { + let kind = node.kind(); + ast::LetStmt::can_cast(kind) || ast::Param::can_cast(kind) + }) + ); + PatternContext { refutability, param_ctx, has_type_ascription, + should_suggest_name, parent_pat: pat.syntax().parent().and_then(ast::Pat::cast), mut_token, ref_token, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index a30a115da1f1b..8c97ebd550032 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -19,8 +19,10 @@ use crate::{ }; /// `CompletionItem` describes a single completion entity which expands to 1 or more entries in the -/// editor pop-up. It is basically a POD with various properties. To construct a -/// [`CompletionItem`], use [`Builder::new`] method and the [`Builder`] struct. +/// editor pop-up. +/// +/// It is basically a POD with various properties. To construct a [`CompletionItem`], +/// use [`Builder::new`] method and the [`Builder`] struct. #[derive(Clone)] #[non_exhaustive] pub struct CompletionItem { @@ -129,7 +131,8 @@ impl fmt::Debug for CompletionItem { #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] pub struct CompletionRelevance { - /// This is set in cases like these: + /// This is set when the identifier being completed matches up with the name that is expected, + /// like in a function argument. /// /// ``` /// fn f(spam: String) {} @@ -139,9 +142,9 @@ pub struct CompletionRelevance { /// } /// ``` pub exact_name_match: bool, - /// See CompletionRelevanceTypeMatch doc comments for cases where this is set. + /// See [`CompletionRelevanceTypeMatch`]. pub type_match: Option, - /// This is set in cases like these: + /// Set for local variables. /// /// ``` /// fn foo(a: u32) { @@ -150,25 +153,26 @@ pub struct CompletionRelevance { /// } /// ``` pub is_local: bool, - /// This is set when trait items are completed in an impl of that trait. - pub is_item_from_trait: bool, - /// This is set for when trait items are from traits with `#[doc(notable_trait)]` - pub is_item_from_notable_trait: bool, - /// This is set when an import is suggested whose name is already imported. + /// Populated when the completion item comes from a trait (impl). + pub trait_: Option, + /// This is set when an import is suggested in a use item whose name is already imported. pub is_name_already_imported: bool, /// This is set for completions that will insert a `use` item. pub requires_import: bool, - /// Set for method completions of the `core::ops` and `core::cmp` family. - pub is_op_method: bool, /// Set for item completions that are private but in the workspace. pub is_private_editable: bool, /// Set for postfix snippet item completions pub postfix_match: Option, - /// This is set for type inference results - pub is_definite: bool, /// This is set for items that are function (associated or method) pub function: Option, } +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub struct CompletionRelevanceTraitInfo { + /// The trait this item is from is a `#[doc(notable_trait)]` + pub notable_trait: bool, + /// Set for method completions of the `core::ops` and `core::cmp` family. + pub is_op_method: bool, +} #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum CompletionRelevanceTypeMatch { @@ -182,7 +186,7 @@ pub enum CompletionRelevanceTypeMatch { /// } /// ``` CouldUnify, - /// This is set in cases like these: + /// This is set in cases where the type matches the expected type, like: /// /// ``` /// fn f(spam: String) {} @@ -238,90 +242,82 @@ impl CompletionRelevance { /// See is_relevant if you need to make some judgement about score /// in an absolute sense. pub fn score(self) -> u32 { - let mut score = 0; + let mut score = !0 / 2; let CompletionRelevance { exact_name_match, type_match, is_local, - is_item_from_trait, is_name_already_imported, requires_import, - is_op_method, is_private_editable, postfix_match, - is_definite, - is_item_from_notable_trait, + trait_, function, } = self; + // only applicable for completions within use items + // lower rank for conflicting import names + if is_name_already_imported { + score -= 1; + } + // slightly prefer locals + if is_local { + score += 1; + } + // lower rank private things if !is_private_editable { score += 1; } - // lower rank trait op methods - if !is_op_method { - score += 10; + + if let Some(trait_) = trait_ { + // lower rank trait methods unless its notable + if !trait_.notable_trait { + score -= 5; + } + // lower rank trait op methods + if trait_.is_op_method { + score -= 5; + } } - // lower rank for conflicting import names - if !is_name_already_imported { - score += 1; - } - // lower rank for items that don't need an import - if !requires_import { - score += 1; + // lower rank for items that need an import + if requires_import { + score -= 1; } if exact_name_match { - score += 10; + score += 20; } - score += match postfix_match { - Some(CompletionRelevancePostfixMatch::Exact) => 100, - Some(CompletionRelevancePostfixMatch::NonExact) => 0, - None => 3, + match postfix_match { + Some(CompletionRelevancePostfixMatch::Exact) => score += 100, + Some(CompletionRelevancePostfixMatch::NonExact) => score -= 5, + None => (), }; score += match type_match { - Some(CompletionRelevanceTypeMatch::Exact) => 8, - Some(CompletionRelevanceTypeMatch::CouldUnify) => 3, + Some(CompletionRelevanceTypeMatch::Exact) => 18, + Some(CompletionRelevanceTypeMatch::CouldUnify) => 5, None => 0, }; - // slightly prefer locals - if is_local { - score += 1; - } - if is_item_from_trait { - score += 1; - } - if is_item_from_notable_trait { - score += 1; - } - if is_definite { - score += 10; - } - - score += function - .map(|asf| { - let mut fn_score = match asf.return_type { - CompletionRelevanceReturnType::DirectConstructor => 15, - CompletionRelevanceReturnType::Builder => 10, - CompletionRelevanceReturnType::Constructor => 5, - CompletionRelevanceReturnType::Other => 0, - }; - - // When a fn is bumped due to return type: - // Bump Constructor or Builder methods with no arguments, - // over them than with self arguments - if fn_score > 0 { - if !asf.has_params { - // bump associated functions - fn_score += 1; - } else if asf.has_self_param { - // downgrade methods (below Constructor) - fn_score = 1; - } - } + if let Some(function) = function { + let mut fn_score = match function.return_type { + CompletionRelevanceReturnType::DirectConstructor => 15, + CompletionRelevanceReturnType::Builder => 10, + CompletionRelevanceReturnType::Constructor => 5, + CompletionRelevanceReturnType::Other => 0u32, + }; + + // When a fn is bumped due to return type: + // Bump Constructor or Builder methods with no arguments, + // over them than with self arguments + if function.has_params { + // bump associated functions + fn_score = fn_score.saturating_sub(1); + } else if function.has_self_param { + // downgrade methods (below Constructor) + fn_score = fn_score.min(1); + } - fn_score - }) - .unwrap_or_default(); + score += fn_score; + }; score } @@ -364,6 +360,7 @@ impl CompletionItemKind { SymbolKind::Field => "fd", SymbolKind::Function => "fn", SymbolKind::Impl => "im", + SymbolKind::InlineAsmRegOrRegClass => "ar", SymbolKind::Label => "lb", SymbolKind::LifetimeParam => "lt", SymbolKind::Local => "lc", @@ -701,8 +698,21 @@ mod tests { // that any items in the same vec have the same score. let expected_relevance_order = vec![ vec![], - vec![Cr { is_op_method: true, is_private_editable: true, ..default }], - vec![Cr { is_op_method: true, ..default }], + vec![Cr { + trait_: Some(crate::item::CompletionRelevanceTraitInfo { + notable_trait: false, + is_op_method: true, + }), + is_private_editable: true, + ..default + }], + vec![Cr { + trait_: Some(crate::item::CompletionRelevanceTraitInfo { + notable_trait: false, + is_op_method: true, + }), + ..default + }], vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::NonExact), ..default }], vec![Cr { is_private_editable: true, ..default }], vec![default], diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index ff5ec3a29f3e1..f2e9de9382c6b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -249,7 +249,11 @@ pub(crate) fn render_type_inference( ty_string, ctx.edition, ); - builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() }); + builder.set_relevance(CompletionRelevance { + type_match: Some(CompletionRelevanceTypeMatch::Exact), + exact_name_match: true, + ..Default::default() + }); builder.build(ctx.db) } @@ -756,7 +760,7 @@ mod tests { relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact), "snippet", ), - (relevance.is_op_method, "op_method"), + (relevance.trait_.map_or(false, |it| it.is_op_method), "op_method"), (relevance.requires_import, "requires_import"), ] .into_iter() @@ -1181,7 +1185,7 @@ fn main() { fo$0 } label: "main()", source_range: 68..70, delete: 68..70, - insert: "main()$0", + insert: "main();$0", kind: SymbolKind( Function, ), @@ -1240,7 +1244,7 @@ fn main() { let _: m::Spam = S$0 } label: "main()", source_range: 75..76, delete: 75..76, - insert: "main()$0", + insert: "main();$0", kind: SymbolKind( Function, ), @@ -1272,14 +1276,11 @@ fn main() { let _: m::Spam = S$0 } Exact, ), is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: None, }, trigger_call_info: true, @@ -1300,14 +1301,11 @@ fn main() { let _: m::Spam = S$0 } Exact, ), is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: None, }, trigger_call_info: true, @@ -1333,7 +1331,7 @@ fn main() { som$0 } label: "main()", source_range: 56..59, delete: 56..59, - insert: "main()$0", + insert: "main();$0", kind: SymbolKind( Function, ), @@ -1344,7 +1342,7 @@ fn main() { som$0 } label: "something_deprecated()", source_range: 56..59, delete: 56..59, - insert: "something_deprecated()$0", + insert: "something_deprecated();$0", kind: SymbolKind( Function, ), @@ -1380,14 +1378,11 @@ fn foo() { A { the$0 } } CouldUnify, ), is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: None, }, }, @@ -1418,7 +1413,7 @@ impl S { label: "bar()", source_range: 94..94, delete: 94..94, - insert: "bar()$0", + insert: "bar();$0", kind: SymbolKind( Method, ), @@ -1431,14 +1426,11 @@ impl S { exact_name_match: false, type_match: None, is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: Some( CompletionRelevanceFn { has_params: true, @@ -1548,7 +1540,7 @@ fn foo(s: S) { s.$0 } label: "the_method()", source_range: 81..81, delete: 81..81, - insert: "the_method()$0", + insert: "the_method();$0", kind: SymbolKind( Method, ), @@ -1558,14 +1550,11 @@ fn foo(s: S) { s.$0 } exact_name_match: false, type_match: None, is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: Some( CompletionRelevanceFn { has_params: true, @@ -1774,14 +1763,11 @@ fn f() -> i32 { Exact, ), is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: None, }, }, @@ -2492,14 +2478,11 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 } exact_name_match: false, type_match: None, is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: Some( CompletionRelevanceFn { has_params: true, @@ -2574,14 +2557,11 @@ fn foo() { Exact, ), is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: None, }, }, @@ -2624,14 +2604,11 @@ fn main() { exact_name_match: false, type_match: None, is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: false, + trait_: None, is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: Some( CompletionRelevanceFn { has_params: false, @@ -2812,7 +2789,7 @@ fn main() { r#" mod m { pub fn r#type {} } fn main() { - m::r#type()$0 + m::r#type();$0 } "#, ) @@ -2986,7 +2963,7 @@ fn main() { label: "flush()", source_range: 193..193, delete: 193..193, - insert: "flush()$0", + insert: "flush();$0", kind: SymbolKind( Method, ), @@ -2996,14 +2973,16 @@ fn main() { exact_name_match: false, type_match: None, is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: true, + trait_: Some( + CompletionRelevanceTraitInfo { + notable_trait: true, + is_op_method: false, + }, + ), is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: None, }, }, @@ -3011,7 +2990,7 @@ fn main() { label: "write()", source_range: 193..193, delete: 193..193, - insert: "write()$0", + insert: "write();$0", kind: SymbolKind( Method, ), @@ -3021,14 +3000,16 @@ fn main() { exact_name_match: false, type_match: None, is_local: false, - is_item_from_trait: false, - is_item_from_notable_trait: true, + trait_: Some( + CompletionRelevanceTraitInfo { + notable_trait: true, + is_op_method: false, + }, + ), is_name_already_imported: false, requires_import: false, - is_op_method: false, is_private_editable: false, postfix_match: None, - is_definite: false, function: None, }, }, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 74092b53f523f..a859d79e24337 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -7,10 +7,12 @@ use stdx::{format_to, to_lower_snake_case}; use syntax::{format_smolstr, AstNode, Edition, SmolStr, ToSmolStr}; use crate::{ - context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind}, + context::{ + CompleteSemicolon, CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind, + }, item::{ Builder, CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevanceFn, - CompletionRelevanceReturnType, + CompletionRelevanceReturnType, CompletionRelevanceTraitInfo, }, render::{ compute_exact_name_match, compute_ref_match, compute_type_match, match_types, RenderContext, @@ -88,11 +90,13 @@ fn render( let ret_type = func.ret_type(db); let assoc_item = func.as_assoc_item(db); - let trait_ = assoc_item.and_then(|trait_| trait_.container_or_implemented_trait(db)); - let is_op_method = trait_.map_or(false, |trait_| completion.is_ops_trait(trait_)); - - let is_item_from_notable_trait = - trait_.map_or(false, |trait_| completion.is_doc_notable_trait(trait_)); + let trait_info = + assoc_item.and_then(|trait_| trait_.container_or_implemented_trait(db)).map(|trait_| { + CompletionRelevanceTraitInfo { + notable_trait: completion.is_doc_notable_trait(trait_), + is_op_method: completion.is_ops_trait(trait_), + } + }); let (has_dot_receiver, has_call_parens, cap) = match func_kind { FuncKind::Function(&PathCompletionCtx { @@ -129,8 +133,7 @@ fn render( }, exact_name_match: compute_exact_name_match(completion, &call), function, - is_op_method, - is_item_from_notable_trait, + trait_: trait_info, ..ctx.completion_relevance() }); @@ -159,7 +162,16 @@ fn render( .lookup_by(name.unescaped().display(db).to_smolstr()); if let Some((cap, (self_param, params))) = complete_call_parens { - add_call_parens(&mut item, completion, cap, call, escaped_call, self_param, params); + add_call_parens( + &mut item, + completion, + cap, + call, + escaped_call, + self_param, + params, + &ret_type, + ); } match ctx.import_to_add { @@ -216,10 +228,11 @@ pub(super) fn add_call_parens<'b>( escaped_name: SmolStr, self_param: Option, params: Vec, + ret_type: &hir::Type, ) -> &'b mut Builder { cov_mark::hit!(inserts_parens_for_function_calls); - let (snippet, label_suffix) = if self_param.is_none() && params.is_empty() { + let (mut snippet, label_suffix) = if self_param.is_none() && params.is_empty() { (format!("{escaped_name}()$0"), "()") } else { builder.trigger_call_info(); @@ -264,6 +277,24 @@ pub(super) fn add_call_parens<'b>( (snippet, "(…)") }; + if ret_type.is_unit() { + match ctx.complete_semicolon { + CompleteSemicolon::DoNotComplete => {} + CompleteSemicolon::CompleteSemi | CompleteSemicolon::CompleteComma => { + cov_mark::hit!(complete_semicolon); + let ch = if matches!(ctx.complete_semicolon, CompleteSemicolon::CompleteComma) { + ',' + } else { + ';' + }; + if snippet.ends_with("$0") { + snippet.insert(snippet.len() - "$0".len(), ch); + } else { + snippet.push(ch); + } + } + } + } builder.label(SmolStr::from_iter([&name, label_suffix])).insert_snippet(cap, snippet) } @@ -392,7 +423,7 @@ fn main() { no_$0 } "#, r#" fn no_args() {} -fn main() { no_args()$0 } +fn main() { no_args();$0 } "#, ); @@ -404,7 +435,7 @@ fn main() { with_$0 } "#, r#" fn with_args(x: i32, y: String) {} -fn main() { with_args(${1:x}, ${2:y})$0 } +fn main() { with_args(${1:x}, ${2:y});$0 } "#, ); @@ -413,14 +444,14 @@ fn main() { with_args(${1:x}, ${2:y})$0 } r#" struct S; impl S { - fn foo(&self) {} + fn foo(&self) -> i32 { 0 } } fn bar(s: &S) { s.f$0 } "#, r#" struct S; impl S { - fn foo(&self) {} + fn foo(&self) -> i32 { 0 } } fn bar(s: &S) { s.foo()$0 } "#, @@ -443,7 +474,7 @@ impl S { fn foo(&self, x: i32) {} } fn bar(s: &S) { - s.foo(${1:x})$0 + s.foo(${1:x});$0 } "#, ); @@ -462,7 +493,7 @@ impl S { struct S {} impl S { fn foo(&self, x: i32) { - self.foo(${1:x})$0 + self.foo(${1:x});$0 } } "#, @@ -485,7 +516,7 @@ struct S; impl S { fn foo(&self) {} } -fn main() { S::foo(${1:&self})$0 } +fn main() { S::foo(${1:&self});$0 } "#, ); } @@ -502,7 +533,7 @@ fn main() { with_$0 } "#, r#" fn with_args(x: i32, y: String) {} -fn main() { with_args($0) } +fn main() { with_args($0); } "#, ); } @@ -517,7 +548,7 @@ fn main() { f$0 } "#, r#" fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} -fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } +fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_});$0 } "#, ); } @@ -539,7 +570,7 @@ struct Foo {} fn ref_arg(x: &Foo) {} fn main() { let x = Foo {}; - ref_arg(${1:&x})$0 + ref_arg(${1:&x});$0 } "#, ); @@ -562,7 +593,7 @@ struct Foo {} fn ref_arg(x: &mut Foo) {} fn main() { let x = Foo {}; - ref_arg(${1:&mut x})$0 + ref_arg(${1:&mut x});$0 } "#, ); @@ -595,7 +626,7 @@ impl Bar { fn main() { let x = Foo {}; let y = Bar {}; - y.apply_foo(${1:&x})$0 + y.apply_foo(${1:&x});$0 } "#, ); @@ -616,7 +647,7 @@ fn main() { fn take_mutably(mut x: &i32) {} fn main() { - take_mutably(${1:x})$0 + take_mutably(${1:x});$0 } "#, ); @@ -649,7 +680,7 @@ fn qux(Foo { bar }: Foo) { } fn main() { - qux(${1:foo})$0 + qux(${1:foo});$0 } "#, ); @@ -735,6 +766,136 @@ fn g(foo: ()#[baz = "qux"] mut ba$0) r#" fn f(foo: (), #[baz = "qux"] mut bar: u32) {} fn g(foo: (), #[baz = "qux"] mut bar: u32) +"#, + ); + } + + #[test] + fn complete_semicolon_for_unit() { + cov_mark::check!(complete_semicolon); + check_edit( + r#"foo"#, + r#" +fn foo() {} +fn bar() { + foo$0 +} +"#, + r#" +fn foo() {} +fn bar() { + foo();$0 +} +"#, + ); + check_edit( + r#"foo"#, + r#" +fn foo(a: i32) {} +fn bar() { + foo$0 +} +"#, + r#" +fn foo(a: i32) {} +fn bar() { + foo(${1:a});$0 +} +"#, + ); + check_edit( + r#"foo"#, + r#" +fn foo(a: i32) {} +fn bar() { + foo$0; +} +"#, + r#" +fn foo(a: i32) {} +fn bar() { + foo(${1:a})$0; +} +"#, + ); + check_edit_with_config( + CompletionConfig { add_semicolon_to_unit: false, ..TEST_CONFIG }, + r#"foo"#, + r#" +fn foo(a: i32) {} +fn bar() { + foo$0 +} +"#, + r#" +fn foo(a: i32) {} +fn bar() { + foo(${1:a})$0 +} +"#, + ); + } + + #[test] + fn complete_comma_for_unit_match_arm() { + cov_mark::check!(complete_semicolon); + check_edit( + r#"foo"#, + r#" +fn foo() {} +fn bar() { + match Some(false) { + v => fo$0 + } +} +"#, + r#" +fn foo() {} +fn bar() { + match Some(false) { + v => foo(),$0 + } +} +"#, + ); + check_edit( + r#"foo"#, + r#" +fn foo() {} +fn bar() { + match Some(false) { + v => fo$0, + } +} +"#, + r#" +fn foo() {} +fn bar() { + match Some(false) { + v => foo()$0, + } +} +"#, + ); + } + + #[test] + fn no_semicolon_in_closure_ret() { + check_edit( + r#"foo"#, + r#" +fn foo() {} +fn baz(_: impl FnOnce()) {} +fn bar() { + baz(|| fo$0); +} +"#, + r#" +fn foo() {} +fn baz(_: impl FnOnce()) {} +fn bar() { + baz(|| foo()$0); +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 04ba7e1f41b62..9d77d9700718c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -70,6 +70,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { term_search_fuel: 200, full_function_signatures: false, callable: Some(CallableSnippets::FillArguments), + add_semicolon_to_unit: true, snippet_cap: SnippetCap::new(true), insert_use: InsertUseConfig { granularity: ImportGranularity::Crate, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 351abe9850b98..1bbe097cc6c86 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -26,6 +26,7 @@ struct Foo; at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -75,6 +76,7 @@ fn with_existing_attr() { at cfg(…) at cfg_attr(…) at deny(…) + at expect(…) at forbid(…) at warn(…) kw crate:: @@ -97,6 +99,7 @@ fn attr_on_source_file() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at feature(…) at forbid(…) at must_use @@ -127,6 +130,7 @@ fn attr_on_module() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at macro_use at must_use @@ -149,6 +153,7 @@ fn attr_on_module() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_implicit_prelude @@ -174,6 +179,7 @@ fn attr_on_macro_rules() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at macro_export at macro_use @@ -199,6 +205,7 @@ fn attr_on_macro_def() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -222,6 +229,7 @@ fn attr_on_extern_crate() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at macro_use at must_use @@ -246,6 +254,7 @@ fn attr_on_use() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -269,6 +278,7 @@ fn attr_on_type_alias() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -299,6 +309,7 @@ struct Foo; at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -326,6 +337,7 @@ fn attr_on_enum() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -351,6 +363,7 @@ fn attr_on_const() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -374,6 +387,7 @@ fn attr_on_static() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at export_name = "…" at forbid(…) at global_allocator @@ -402,6 +416,7 @@ fn attr_on_trait() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at must_use @@ -427,6 +442,7 @@ fn attr_on_impl() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -446,6 +462,7 @@ fn attr_on_impl() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at must_use at no_mangle @@ -469,6 +486,7 @@ fn attr_on_extern_block() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at link at must_use @@ -489,6 +507,7 @@ fn attr_on_extern_block() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at forbid(…) at link at must_use @@ -509,6 +528,7 @@ fn attr_on_variant() { at cfg(…) at cfg_attr(…) at deny(…) + at expect(…) at forbid(…) at non_exhaustive at warn(…) @@ -532,6 +552,7 @@ fn attr_on_fn() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at export_name = "…" at forbid(…) at ignore = "…" @@ -572,6 +593,7 @@ fn attr_in_source_file_end() { at doc = "…" at doc(alias = "…") at doc(hidden) + at expect(…) at export_name = "…" at forbid(…) at global_allocator diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 8350fdcc4c07c..0b532064fb2be 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -53,7 +53,7 @@ fn main() { use dep::io::stdin; fn main() { - stdin()$0 + stdin();$0 } "#, ); @@ -274,7 +274,7 @@ fn trait_function_fuzzy_completion() { use dep::test_mod::TestTrait; fn main() { - dep::test_mod::TestStruct::weird_function()$0 + dep::test_mod::TestStruct::weird_function();$0 } "#, ); @@ -368,7 +368,7 @@ use dep::test_mod::TestTrait; fn main() { let test_struct = dep::test_mod::TestStruct {}; - test_struct.random_method()$0 + test_struct.random_method();$0 } "#, ); @@ -419,7 +419,7 @@ impl foo::TestTrait for fundamental::Box { fn main() { let t = fundamental::Box(TestStruct); - t.some_method()$0 + t.some_method();$0 } "#, ); @@ -466,7 +466,7 @@ impl foo::TestTrait for &TestStruct { fn main() { let t = &TestStruct; - t.some_method()$0 + t.some_method();$0 } "#, ); @@ -507,7 +507,7 @@ fn completion(whatever: T) { use foo::{NotInScope, Wrapper}; fn completion(whatever: T) { - whatever.inner().not_in_scope()$0 + whatever.inner().not_in_scope();$0 } "#, ); @@ -579,7 +579,7 @@ fn main() { use dep::test_mod::TestTrait; fn main() { - dep::test_mod::TestAlias::random_method()$0 + dep::test_mod::TestAlias::random_method();$0 } "#, ); @@ -702,7 +702,7 @@ fn main() { use dep::test_mod::TestTrait; fn main() { - dep::test_mod::TestStruct::another_function()$0 + dep::test_mod::TestStruct::another_function();$0 } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs index 8aad7bfc3adc9..532d4928eff99 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs @@ -313,6 +313,7 @@ impl Test for () { ct const CONST1: () = fn async fn function2() fn fn function1() + fn fn function2() ma makro!(…) macro_rules! makro md module ta type Type1 = diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs index 6a0b67e291af8..bd3e7c72bcd65 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs @@ -198,6 +198,7 @@ fn foo(a$0: Tuple) { st Unit bn Record {…} Record { field$1 }$0 bn Tuple(…) Tuple($1)$0 + bn tuple kw mut kw ref "#]], @@ -850,3 +851,75 @@ fn foo() { "#, ); } + +#[test] +fn suggest_name_for_pattern() { + check_edit( + "s1", + r#" +struct S1; + +fn foo() { + let $0 = S1; +} +"#, + r#" +struct S1; + +fn foo() { + let s1 = S1; +} +"#, + ); + + check_edit( + "s1", + r#" +struct S1; + +fn foo(s$0: S1) { +} +"#, + r#" +struct S1; + +fn foo(s1: S1) { +} +"#, + ); + + // Tests for &adt + check_edit( + "s1", + r#" +struct S1; + +fn foo() { + let $0 = &S1; +} +"#, + r#" +struct S1; + +fn foo() { + let s1 = &S1; +} +"#, + ); + + // Do not suggest reserved keywords + check_empty( + r#" +struct Struct; + +fn foo() { + let $0 = Struct; +} +"#, + expect![[r#" + st Struct + kw mut + kw ref + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs index bc630189edc91..d81b3d697aa8a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs @@ -30,7 +30,7 @@ fn foo() { "#, expect![[r#" fn foo() { - a::dyn()$0 + a::dyn();$0 "#]], ); @@ -45,7 +45,7 @@ fn foo() { "#, expect![[r#" fn foo() { - a::dyn()$0 + a::dyn();$0 "#]], ); } @@ -63,7 +63,7 @@ fn foo() { "#, expect![[r#" fn foo() { - a::r#dyn()$0 + a::r#dyn();$0 "#]], ); @@ -78,7 +78,7 @@ fn foo() { "#, expect![[r#" fn foo() { - a::r#dyn()$0 + a::r#dyn();$0 "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index 2ae7d37889e53..508f6248dd414 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -63,7 +63,7 @@ fn _alpha() {} "#, r#" fn main() { - _alpha()$0 + _alpha();$0 } fn _alpha() {} "#, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 5d4b1999088a0..099f26eba78a9 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -10,8 +10,8 @@ use either::Either; use hir::{ Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field, - Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, - ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait, + Function, GenericParam, HasVisibility, HirDisplay, Impl, InlineAsmOperand, Label, Local, Macro, + Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, }; use span::Edition; @@ -50,6 +50,8 @@ pub enum Definition { BuiltinAttr(BuiltinAttr), ToolModule(ToolModule), ExternCrateDecl(ExternCrateDecl), + InlineAsmRegOrRegClass(()), + InlineAsmOperand(InlineAsmOperand), } impl Definition { @@ -83,11 +85,13 @@ impl Definition { Definition::Label(it) => it.module(db), Definition::ExternCrateDecl(it) => it.module(db), Definition::DeriveHelper(it) => it.derive().module(db), + Definition::InlineAsmOperand(it) => it.parent(db).module(db), Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) | Definition::TupleField(_) - | Definition::ToolModule(_) => return None, + | Definition::ToolModule(_) + | Definition::InlineAsmRegOrRegClass(_) => return None, }; Some(module) } @@ -121,7 +125,9 @@ impl Definition { | Definition::Local(_) | Definition::GenericParam(_) | Definition::Label(_) - | Definition::DeriveHelper(_) => return None, + | Definition::DeriveHelper(_) + | Definition::InlineAsmRegOrRegClass(_) + | Definition::InlineAsmOperand(_) => return None, }; Some(vis) } @@ -150,6 +156,8 @@ impl Definition { Definition::ToolModule(_) => return None, // FIXME Definition::DeriveHelper(it) => it.name(db), Definition::ExternCrateDecl(it) => return it.alias_or_name(db), + Definition::InlineAsmRegOrRegClass(_) => return None, + Definition::InlineAsmOperand(op) => return op.name(db), }; Some(name) } @@ -212,6 +220,7 @@ impl Definition { Definition::ToolModule(_) => None, Definition::DeriveHelper(_) => None, Definition::TupleField(_) => None, + Definition::InlineAsmRegOrRegClass(_) | Definition::InlineAsmOperand(_) => None, }; docs.or_else(|| { @@ -268,6 +277,9 @@ impl Definition { Definition::DeriveHelper(it) => { format!("derive_helper {}", it.name(db).display(db, edition)) } + // FIXME + Definition::InlineAsmRegOrRegClass(_) => "inline_asm_reg_or_reg_class".to_owned(), + Definition::InlineAsmOperand(_) => "inline_asm_reg_operand".to_owned(), } } } @@ -429,7 +441,6 @@ impl NameClass { let _p = tracing::info_span!("NameClass::classify").entered(); let parent = name.syntax().parent()?; - let definition = match_ast! { match parent { ast::Item(it) => classify_item(sema, it)?, @@ -440,6 +451,7 @@ impl NameClass { ast::Variant(it) => Definition::Variant(sema.to_def(&it)?), ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), + ast::AsmOperandNamed(it) => Definition::InlineAsmOperand(sema.to_def(&it)?), _ => return None, } }; @@ -699,6 +711,9 @@ impl NameRefClass { NameRefClass::ExternCrateShorthand { krate, decl: extern_crate } }) }, + ast::AsmRegSpec(_) => { + Some(NameRefClass::Definition(Definition::InlineAsmRegOrRegClass(()))) + }, _ => None } } @@ -753,6 +768,18 @@ impl From for Definition { } } +impl From for Definition { + fn from(value: InlineAsmOperand) -> Self { + Definition::InlineAsmOperand(value) + } +} + +impl From> for Definition { + fn from(value: Either) -> Self { + value.either(Definition::from, Definition::from) + } +} + impl AsAssocItem for Definition { fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option { match self { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 3cf29987fa14c..a45ff9a954557 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -36,8 +36,9 @@ pub mod generated { pub mod syntax_helpers { pub mod format_string; pub mod format_string_exprs; - pub mod insert_whitespace_into_node; + pub use hir::prettify_macro_expansion; pub mod node_ext; + pub mod suggest_name; pub use parser::LexedStr; } @@ -223,6 +224,7 @@ pub enum SymbolKind { Function, Method, Impl, + InlineAsmRegOrRegClass, Label, LifetimeParam, Local, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index 262eefeec00e4..f1404ed9f22cd 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -200,12 +200,14 @@ impl Definition { .and_then(syn_ctx_is_root) } } + Definition::InlineAsmOperand(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) | Definition::BuiltinAttr(_) | Definition::SelfType(_) | Definition::ToolModule(_) - | Definition::TupleField(_) => return None, + | Definition::TupleField(_) + | Definition::InlineAsmRegOrRegClass(_) => return None, // FIXME: This should be doable in theory Definition::DeriveHelper(_) => return None, }; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index 12ce5a403fe87..4166b08339bff 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -8,17 +8,18 @@ use std::mem; use std::{cell::LazyCell, cmp::Reverse}; use base_db::{salsa::Database, SourceDatabase, SourceRootDatabase}; +use either::Either; use hir::{ sym, Adt, AsAssocItem, DefWithBody, FileRange, FileRangeWrapper, HasAttrs, HasContainer, - HasSource, HirFileIdExt, InFile, InFileWrapper, InRealFile, ItemContainer, ModuleSource, - PathResolution, Semantics, Visibility, + HasSource, HirFileIdExt, InFile, InFileWrapper, InRealFile, InlineAsmOperand, ItemContainer, + ModuleSource, PathResolution, Semantics, Visibility, }; use memchr::memmem::Finder; use parser::SyntaxKind; use rustc_hash::{FxHashMap, FxHashSet}; use span::EditionedFileId; use syntax::{ - ast::{self, HasName}, + ast::{self, HasName, Rename}, match_ast, AstNode, AstToken, SmolStr, SyntaxElement, SyntaxNode, TextRange, TextSize, ToSmolStr, }; @@ -318,6 +319,23 @@ impl Definition { }; } + if let Definition::InlineAsmOperand(op) = self { + let def = match op.parent(db) { + DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + // FIXME: implement + DefWithBody::InTypeConst(_) => return SearchScope::empty(), + }; + return match def { + Some(def) => SearchScope::file_range( + def.as_ref().original_file_range_with_macro_call_body(db), + ), + None => SearchScope::single_file(file_id), + }; + } + if let Definition::SelfType(impl_) = self { return match impl_.source(db).map(|src| src.syntax().cloned()) { Some(def) => SearchScope::file_range( @@ -387,6 +405,7 @@ impl Definition { pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> { FindUsages { def: self, + rename: None, assoc_item_container: self.as_assoc_item(sema.db).map(|a| a.container(sema.db)), sema, scope: None, @@ -399,6 +418,7 @@ impl Definition { #[derive(Clone)] pub struct FindUsages<'a> { def: Definition, + rename: Option<&'a Rename>, sema: &'a Semantics<'a, RootDatabase>, scope: Option<&'a SearchScope>, /// The container of our definition should it be an assoc item @@ -429,6 +449,14 @@ impl<'a> FindUsages<'a> { self } + // FIXME: This is just a temporary fix for not handling import aliases like + // `use Foo as Bar`. We need to support them in a proper way. + // See issue #14079 + pub fn with_rename(mut self, rename: Option<&'a Rename>) -> Self { + self.rename = rename; + self + } + pub fn at_least_one(&self) -> bool { let mut found = false; self.search(&mut |_, _| { @@ -866,9 +894,16 @@ impl<'a> FindUsages<'a> { } }; - let name = match self.def { + let name = match (self.rename, self.def) { + (Some(rename), _) => { + if rename.underscore_token().is_some() { + None + } else { + rename.name().map(|n| n.to_smolstr()) + } + } // special case crate modules as these do not have a proper name - Definition::Module(module) if module.is_crate_root() => { + (_, Definition::Module(module)) if module.is_crate_root() => { // FIXME: This assumes the crate name is always equal to its display name when it // really isn't // we should instead look at the dependency edge name and recursively search our way @@ -908,7 +943,6 @@ impl<'a> FindUsages<'a> { let finder = &Finder::new(name); let include_self_kw_refs = self.include_self_kw_refs.as_ref().map(|ty| (ty, Finder::new("Self"))); - for (text, file_id, search_range) in Self::scope_files(sema.db, &search_scope) { self.sema.db.unwind_if_cancelled(); let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); @@ -917,7 +951,7 @@ impl<'a> FindUsages<'a> { for offset in Self::match_indices(&text, finder, search_range) { tree.token_at_offset(offset).for_each(|token| { let Some(str_token) = ast::String::cast(token.clone()) else { return }; - if let Some((range, nameres)) = + if let Some((range, Some(nameres))) = sema.check_for_format_args_template(token, offset) { if self.found_format_args_ref(file_id, range, str_token, nameres, sink) {} @@ -1087,19 +1121,19 @@ impl<'a> FindUsages<'a> { file_id: EditionedFileId, range: TextRange, token: ast::String, - res: Option, + res: Either, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { - match res.map(Definition::from) { - Some(def) if def == self.def => { - let reference = FileReference { - range, - name: FileReferenceNode::FormatStringEntry(token, range), - category: ReferenceCategory::READ, - }; - sink(file_id, reference) - } - _ => false, + let def = res.either(Definition::from, Definition::from); + if def == self.def { + let reference = FileReference { + range, + name: FileReferenceNode::FormatStringEntry(token, range), + category: ReferenceCategory::READ, + }; + sink(file_id, reference) + } else { + false } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index a83f8473c3964..73073e92f787e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -9,10 +9,13 @@ use crate::{assists::Command, SnippetCap}; use base_db::AnchoredPathBuf; use itertools::Itertools; use nohash_hasher::IntMap; +use rustc_hash::FxHashMap; use span::FileId; use stdx::never; use syntax::{ - algo, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, + algo, + syntax_editor::{SyntaxAnnotation, SyntaxEditor}, + AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, }; use text_edit::{TextEdit, TextEditBuilder}; @@ -197,6 +200,11 @@ pub struct SourceChangeBuilder { pub source_change: SourceChange, pub command: Option, + /// Keeps track of all edits performed on each file + pub file_editors: FxHashMap, + /// Keeps track of which annotations correspond to which snippets + pub snippet_annotations: Vec<(AnnotationSnippet, SyntaxAnnotation)>, + /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. pub mutated_tree: Option, /// Keeps track of where to place snippets @@ -238,6 +246,8 @@ impl SourceChangeBuilder { file_id: file_id.into(), source_change: SourceChange::default(), command: None, + file_editors: FxHashMap::default(), + snippet_annotations: vec![], mutated_tree: None, snippet_builder: None, } @@ -248,7 +258,75 @@ impl SourceChangeBuilder { self.file_id = file_id.into(); } + pub fn make_editor(&self, node: &SyntaxNode) -> SyntaxEditor { + SyntaxEditor::new(node.ancestors().last().unwrap_or_else(|| node.clone())) + } + + pub fn add_file_edits(&mut self, file_id: impl Into, edit: SyntaxEditor) { + match self.file_editors.entry(file_id.into()) { + Entry::Occupied(mut entry) => entry.get_mut().merge(edit), + Entry::Vacant(entry) => { + entry.insert(edit); + } + } + } + + pub fn make_placeholder_snippet(&mut self, _cap: SnippetCap) -> SyntaxAnnotation { + self.add_snippet_annotation(AnnotationSnippet::Over) + } + + pub fn make_tabstop_before(&mut self, _cap: SnippetCap) -> SyntaxAnnotation { + self.add_snippet_annotation(AnnotationSnippet::Before) + } + + pub fn make_tabstop_after(&mut self, _cap: SnippetCap) -> SyntaxAnnotation { + self.add_snippet_annotation(AnnotationSnippet::After) + } + fn commit(&mut self) { + // Apply syntax editor edits + for (file_id, editor) in mem::take(&mut self.file_editors) { + let edit_result = editor.finish(); + let mut snippet_edit = vec![]; + + // Find snippet edits + for (kind, annotation) in &self.snippet_annotations { + let elements = edit_result.find_annotation(*annotation); + + let snippet = match (kind, elements) { + (AnnotationSnippet::Before, [element]) => { + Snippet::Tabstop(element.text_range().start()) + } + (AnnotationSnippet::After, [element]) => { + Snippet::Tabstop(element.text_range().end()) + } + (AnnotationSnippet::Over, [element]) => { + Snippet::Placeholder(element.text_range()) + } + (AnnotationSnippet::Over, elements) if !elements.is_empty() => { + Snippet::PlaceholderGroup( + elements.iter().map(|it| it.text_range()).collect(), + ) + } + _ => continue, + }; + + snippet_edit.push(snippet); + } + + let mut edit = TextEdit::builder(); + algo::diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit); + let edit = edit.finish(); + + let snippet_edit = + if !snippet_edit.is_empty() { Some(SnippetEdit::new(snippet_edit)) } else { None }; + + if !edit.is_empty() || snippet_edit.is_some() { + self.source_change.insert_source_and_snippet_edit(file_id, edit, snippet_edit); + } + } + + // Apply mutable edits let snippet_edit = self.snippet_builder.take().map(|builder| { SnippetEdit::new( builder.places.into_iter().flat_map(PlaceSnippet::finalize_position).collect(), @@ -369,6 +447,13 @@ impl SourceChangeBuilder { self.source_change.is_snippet = true; } + fn add_snippet_annotation(&mut self, kind: AnnotationSnippet) -> SyntaxAnnotation { + let annotation = SyntaxAnnotation::new(); + self.snippet_annotations.push((kind, annotation)); + self.source_change.is_snippet = true; + annotation + } + pub fn finish(mut self) -> SourceChange { self.commit(); @@ -416,6 +501,15 @@ pub enum Snippet { PlaceholderGroup(Vec), } +pub enum AnnotationSnippet { + /// Place a tabstop before an element + Before, + /// Place a tabstop before an element + After, + /// Place a placeholder snippet in place of the element(s) + Over, +} + enum PlaceSnippet { /// Place a tabstop before an element Before(SyntaxElement), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs similarity index 70% rename from src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs rename to src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 3130ef0695577..2679cbef61b3b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -1,14 +1,18 @@ //! This module contains functions to suggest names for expressions, functions and other items +use std::{collections::hash_map::Entry, str::FromStr}; + use hir::Semantics; -use ide_db::{FxHashSet, RootDatabase}; use itertools::Itertools; +use rustc_hash::FxHashMap; use stdx::to_lower_snake_case; use syntax::{ ast::{self, HasName}, - match_ast, AstNode, Edition, SmolStr, + match_ast, AstNode, Edition, SmolStr, SmolStrBuilder, }; +use crate::RootDatabase; + /// Trait names, that will be ignored when in `impl Trait` and `dyn Trait` const USELESS_TRAITS: &[&str] = &["Send", "Sync", "Copy", "Clone", "Eq", "PartialEq"]; @@ -16,7 +20,9 @@ const USELESS_TRAITS: &[&str] = &["Send", "Sync", "Copy", "Clone", "Eq", "Partia /// /// **NOTE**: they all must be snake lower case const USELESS_NAMES: &[&str] = - &["new", "default", "option", "some", "none", "ok", "err", "str", "string"]; + &["new", "default", "option", "some", "none", "ok", "err", "str", "string", "from", "into"]; + +const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"]; /// Generic types replaced by their first argument /// @@ -58,59 +64,131 @@ const USELESS_METHODS: &[&str] = &[ "into_future", ]; -/// Suggest a unique name for generic parameter. +/// Generator for new names /// -/// `existing_params` is used to check if the name conflicts with existing -/// generic parameters. -/// -/// The function checks if the name conflicts with existing generic parameters. -/// If so, it will try to resolve the conflict by adding a number suffix, e.g. -/// `T`, `T0`, `T1`, ... -pub(crate) fn for_unique_generic_name( - name: &str, - existing_params: &ast::GenericParamList, -) -> SmolStr { - let param_names = existing_params - .generic_params() - .map(|param| match param { - ast::GenericParam::TypeParam(t) => t.name().unwrap().to_string(), - p => p.to_string(), - }) - .collect::>(); - let mut name = name.to_owned(); - let base_len = name.len(); - let mut count = 0; - while param_names.contains(&name) { - name.truncate(base_len); - name.push_str(&count.to_string()); - count += 1; - } - - name.into() -} - -/// Suggest name of impl trait type +/// The generator keeps track of existing names and suggests new names that do +/// not conflict with existing names. /// -/// `existing_params` is used to check if the name conflicts with existing -/// generic parameters. +/// The generator will try to resolve conflicts by adding a numeric suffix to +/// the name, e.g. `a`, `a1`, `a2`, ... /// -/// # Current implementation -/// -/// In current implementation, the function tries to get the name from the first -/// character of the name for the first type bound. +/// # Examples +/// ```rust +/// let mut generator = NameGenerator::new(); +/// assert_eq!(generator.suggest_name("a"), "a"); +/// assert_eq!(generator.suggest_name("a"), "a1"); /// -/// If the name conflicts with existing generic parameters, it will try to -/// resolve the conflict with `for_unique_generic_name`. -pub(crate) fn for_impl_trait_as_generic( - ty: &ast::ImplTraitType, - existing_params: &ast::GenericParamList, -) -> SmolStr { - let c = ty - .type_bound_list() - .and_then(|bounds| bounds.syntax().text().char_at(0.into())) - .unwrap_or('T'); - - for_unique_generic_name(c.encode_utf8(&mut [0; 4]), existing_params) +/// assert_eq!(generator.suggest_name("b2"), "b2"); +/// assert_eq!(generator.suggest_name("b"), "b3"); +/// ``` +#[derive(Debug, Default)] +pub struct NameGenerator { + pool: FxHashMap, +} + +impl NameGenerator { + /// Create a new empty generator + pub fn new() -> Self { + Self { pool: FxHashMap::default() } + } + + /// Create a new generator with existing names. When suggesting a name, it will + /// avoid conflicts with existing names. + pub fn new_with_names<'a>(existing_names: impl Iterator) -> Self { + let mut generator = Self::new(); + existing_names.for_each(|name| generator.insert(name)); + generator + } + + /// Suggest a name without conflicts. If the name conflicts with existing names, + /// it will try to resolve the conflict by adding a numeric suffix. + pub fn suggest_name(&mut self, name: &str) -> SmolStr { + let (prefix, suffix) = Self::split_numeric_suffix(name); + let prefix = SmolStr::new(prefix); + let suffix = suffix.unwrap_or(0); + + match self.pool.entry(prefix.clone()) { + Entry::Vacant(entry) => { + entry.insert(suffix); + SmolStr::from_str(name).unwrap() + } + Entry::Occupied(mut entry) => { + let count = entry.get_mut(); + *count = (*count + 1).max(suffix); + + let mut new_name = SmolStrBuilder::new(); + new_name.push_str(&prefix); + new_name.push_str(count.to_string().as_str()); + new_name.finish() + } + } + } + + /// Suggest a name for given type. + /// + /// The function will strip references first, and suggest name from the inner type. + /// + /// - If `ty` is an ADT, it will suggest the name of the ADT. + /// + If `ty` is wrapped in `Box`, `Option` or `Result`, it will suggest the name from the inner type. + /// - If `ty` is a trait, it will suggest the name of the trait. + /// - If `ty` is an `impl Trait`, it will suggest the name of the first trait. + /// + /// If the suggested name conflicts with reserved keywords, it will return `None`. + pub fn for_type( + &mut self, + ty: &hir::Type, + db: &RootDatabase, + edition: Edition, + ) -> Option { + let name = name_of_type(ty, db, edition)?; + Some(self.suggest_name(&name)) + } + + /// Suggest name of impl trait type + /// + /// # Current implementation + /// + /// In current implementation, the function tries to get the name from the first + /// character of the name for the first type bound. + /// + /// If the name conflicts with existing generic parameters, it will try to + /// resolve the conflict with `for_unique_generic_name`. + pub fn for_impl_trait_as_generic(&mut self, ty: &ast::ImplTraitType) -> SmolStr { + let c = ty + .type_bound_list() + .and_then(|bounds| bounds.syntax().text().char_at(0.into())) + .unwrap_or('T'); + + self.suggest_name(&c.to_string()) + } + + /// Insert a name into the pool + fn insert(&mut self, name: &str) { + let (prefix, suffix) = Self::split_numeric_suffix(name); + let prefix = SmolStr::new(prefix); + let suffix = suffix.unwrap_or(0); + + match self.pool.entry(prefix) { + Entry::Vacant(entry) => { + entry.insert(suffix); + } + Entry::Occupied(mut entry) => { + let count = entry.get_mut(); + *count = (*count).max(suffix); + } + } + } + + /// Remove the numeric suffix from the name + /// + /// # Examples + /// `a1b2c3` -> `a1b2c` + fn split_numeric_suffix(name: &str) -> (&str, Option) { + let pos = + name.rfind(|c: char| !c.is_numeric()).expect("Name cannot be empty or all-numeric"); + let (prefix, suffix) = name.split_at(pos + 1); + (prefix, suffix.parse().ok()) + } } /// Suggest name of variable for given expression @@ -132,7 +210,7 @@ pub(crate) fn for_impl_trait_as_generic( /// /// Currently it sticks to the first name found. // FIXME: Microoptimize and return a `SmolStr` here. -pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { +pub fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { // `from_param` does not benefit from stripping // it need the largest context possible // so we check firstmost @@ -175,6 +253,10 @@ fn normalize(name: &str) -> Option { return None; } + if USELESS_NAME_PREFIXES.iter().any(|prefix| name.starts_with(prefix)) { + return None; + } + if !is_valid_name(&name) { return None; } @@ -184,7 +266,7 @@ fn normalize(name: &str) -> Option { fn is_valid_name(name: &str) -> bool { matches!( - ide_db::syntax_helpers::LexedStr::single_token(syntax::Edition::CURRENT_FIXME, name), + super::LexedStr::single_token(syntax::Edition::CURRENT_FIXME, name), Some((syntax::SyntaxKind::IDENT, _error)) ) } @@ -818,4 +900,117 @@ fn foo(some_struct: S) { $0some_struct.some_field$0 } "some_field", ); } + + #[test] + fn from_and_to_func() { + check( + r#" +//- minicore: from +struct Foo; +struct Bar; + +impl From for Bar { + fn from(_: Foo) -> Self { + Bar; + } +} + +fn f(_: Bar) {} + +fn main() { + let foo = Foo {}; + f($0Bar::from(foo)$0); +} +"#, + "bar", + ); + + check( + r#" +//- minicore: from +struct Foo; +struct Bar; + +impl From for Bar { + fn from(_: Foo) -> Self { + Bar; + } +} + +fn f(_: Bar) {} + +fn main() { + let foo = Foo {}; + f($0Into::::into(foo)$0); +} +"#, + "bar", + ); + } + + #[test] + fn useless_name_prefix() { + check( + r#" +struct Foo; +struct Bar; + +impl Bar { + fn from_foo(_: Foo) -> Self { + Foo {} + } +} + +fn main() { + let foo = Foo {}; + let _ = $0Bar::from_foo(foo)$0; +} +"#, + "bar", + ); + + check( + r#" +struct Foo; +struct Bar; + +impl Bar { + fn with_foo(_: Foo) -> Self { + Bar {} + } +} + +fn main() { + let foo = Foo {}; + let _ = $0Bar::with_foo(foo)$0; +} +"#, + "bar", + ); + } + + #[test] + fn conflicts_with_existing_names() { + let mut generator = NameGenerator::new(); + assert_eq!(generator.suggest_name("a"), "a"); + assert_eq!(generator.suggest_name("a"), "a1"); + assert_eq!(generator.suggest_name("a"), "a2"); + assert_eq!(generator.suggest_name("a"), "a3"); + + assert_eq!(generator.suggest_name("b"), "b"); + assert_eq!(generator.suggest_name("b2"), "b2"); + assert_eq!(generator.suggest_name("b"), "b3"); + assert_eq!(generator.suggest_name("b"), "b4"); + assert_eq!(generator.suggest_name("b3"), "b5"); + + // --------- + let mut generator = NameGenerator::new_with_names(["a", "b", "b2", "c4"].into_iter()); + assert_eq!(generator.suggest_name("a"), "a1"); + assert_eq!(generator.suggest_name("a"), "a2"); + + assert_eq!(generator.suggest_name("b"), "b3"); + assert_eq!(generator.suggest_name("b2"), "b4"); + + assert_eq!(generator.suggest_name("c"), "c5"); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 18a95f0963ddb..83a1eb44a616e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -369,6 +369,23 @@ mod F { ); } + #[test] + fn external_macro() { + check_diagnostics( + r#" +//- /library.rs library crate:library +#[macro_export] +macro_rules! trigger_lint { + () => { let FOO: () }; +} +//- /user.rs crate:user deps:library +fn foo() { + library::trigger_lint!(); +} + "#, + ); + } + #[test] fn complex_ignore() { check_diagnostics( @@ -418,6 +435,64 @@ fn f((_O): u8) {} ) } + #[test] + fn ignores_no_mangle_items() { + cov_mark::check!(extern_func_no_mangle_ignored); + check_diagnostics( + r#" +#[no_mangle] +extern "C" fn NonSnakeCaseName(some_var: u8) -> u8; + "#, + ); + } + + #[test] + fn ignores_no_mangle_items_with_no_abi() { + cov_mark::check!(extern_func_no_mangle_ignored); + check_diagnostics( + r#" +#[no_mangle] +extern fn NonSnakeCaseName(some_var: u8) -> u8; + "#, + ); + } + + #[test] + fn no_mangle_items_with_rust_abi() { + check_diagnostics( + r#" +#[no_mangle] +extern "Rust" fn NonSnakeCaseName(some_var: u8) -> u8; + // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` + "#, + ); + } + + #[test] + fn no_mangle_items_non_extern() { + check_diagnostics( + r#" +#[no_mangle] +fn NonSnakeCaseName(some_var: u8) -> u8; +// ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` + "#, + ); + } + + #[test] + fn extern_fn_name() { + check_diagnostics( + r#" +extern "C" fn NonSnakeCaseName(some_var: u8) -> u8; + // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` +extern "Rust" fn NonSnakeCaseName(some_var: u8) -> u8; + // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` +extern fn NonSnakeCaseName(some_var: u8) -> u8; + // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` + "#, + ); + } + #[test] fn ignores_extern_items() { cov_mark::check!(extern_func_incorrect_case_ignored); @@ -593,7 +668,7 @@ mod CheckBadStyle { } mod F { - //^ 💡 warn: Module `F` should have snake_case name, e.g. `f` + //^ 💡 error: Module `F` should have snake_case name, e.g. `f` #![deny(non_snake_case)] fn CheckItWorksWithModAttr() {} //^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Function `CheckItWorksWithModAttr` should have snake_case name, e.g. `check_it_works_with_mod_attr` @@ -856,4 +931,104 @@ fn func() { "#, ); } + + #[test] + fn override_lint_level() { + check_diagnostics( + r#" +#[warn(nonstandard_style)] +fn foo() { + let BAR; + // ^^^ 💡 warn: Variable `BAR` should have snake_case name, e.g. `bar` + #[allow(non_snake_case)] + let FOO; +} + +#[warn(nonstandard_style)] +fn foo() { + let BAR; + // ^^^ 💡 warn: Variable `BAR` should have snake_case name, e.g. `bar` + #[expect(non_snake_case)] + let FOO; + #[allow(non_snake_case)] + struct qux; + // ^^^ 💡 warn: Structure `qux` should have CamelCase name, e.g. `Qux` + + fn BAZ() { + // ^^^ 💡 error: Function `BAZ` should have snake_case name, e.g. `baz` + #![forbid(bad_style)] + } +} + "#, + ); + } + + #[test] + fn different_files() { + check_diagnostics( + r#" +//- /lib.rs +#![expect(nonstandard_style)] + +mod BAD_CASE; + +fn BAD_CASE() {} + +//- /BAD_CASE.rs +mod OtherBadCase; + // ^^^^^^^^^^^^ 💡 error: Module `OtherBadCase` should have snake_case name, e.g. `other_bad_case` + +//- /BAD_CASE/OtherBadCase.rs +#![deny(non_snake_case)] + +fn FOO() {} +// ^^^ 💡 error: Function `FOO` should have snake_case name, e.g. `foo` + +#[allow(bad_style)] +mod FINE_WITH_BAD_CASE; + +//- /BAD_CASE/OtherBadCase/FINE_WITH_BAD_CASE.rs +struct QUX; +const foo: i32 = 0; +fn BAR() { + let BAZ; +} + "#, + ); + } + + #[test] + fn cfged_lint_attrs() { + check_diagnostics( + r#" +//- /lib.rs cfg:feature=cool_feature +#[cfg_attr(any(), allow(non_snake_case))] +fn FOO() {} +// ^^^ 💡 warn: Function `FOO` should have snake_case name, e.g. `foo` + +#[cfg_attr(non_existent, allow(non_snake_case))] +fn BAR() {} +// ^^^ 💡 warn: Function `BAR` should have snake_case name, e.g. `bar` + +#[cfg_attr(feature = "cool_feature", allow(non_snake_case))] +fn BAZ() {} + +#[cfg_attr(feature = "cool_feature", cfg_attr ( all ( ) , allow ( non_snake_case ) ) ) ] +fn QUX() {} + "#, + ); + } + + #[test] + fn allow_with_comment() { + check_diagnostics( + r#" +#[allow( + // Yo, sup + non_snake_case +)] +fn foo(_HelloWorld: ()) {} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs new file mode 100644 index 0000000000000..ad4baf5e3a406 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs @@ -0,0 +1,1114 @@ +use hir::{CastError, ClosureStyle, HirDisplay}; + +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +macro_rules! format_ty { + ($ctx:expr, $fmt:literal, $($arg:expr),* $(,)?) => {{ + std::format!( + $fmt, + $( + $arg + .display($ctx.sema.db, $ctx.edition) + .with_closure_style(ClosureStyle::ClosureWithId) + ),* + ) + }} +} + +// Diagnostic: invalid-cast +// +// This diagnostic is triggered if the code contains an illegal cast +pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -> Diagnostic { + let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into())); + let (code, message) = match d.error { + CastError::CastToBool => ( + DiagnosticCode::RustcHardError("E0054"), + format_ty!(ctx, "cannot cast `{}` as `bool`", d.expr_ty), + ), + CastError::CastToChar => ( + DiagnosticCode::RustcHardError("E0604"), + format_ty!(ctx, "only `u8` can be cast as `char`, not {}", d.expr_ty), + ), + CastError::DifferingKinds => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: vtable kinds may not match", + d.expr_ty, + d.cast_ty + ), + ), + CastError::SizedUnsizedCast => ( + DiagnosticCode::RustcHardError("E0607"), + format_ty!( + ctx, + "cannot cast thin pointer `{}` to fat pointer `{}`", + d.expr_ty, + d.cast_ty + ), + ), + CastError::Unknown | CastError::IllegalCast => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!(ctx, "casting `{}` as `{}` is invalid", d.expr_ty, d.cast_ty), + ), + CastError::IntToFatCast => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!(ctx, "cannot cast `{}` to a fat pointer `{}`", d.expr_ty, d.cast_ty), + ), + CastError::NeedDeref => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: needs defererence or removal of unneeded borrow", + d.expr_ty, + d.cast_ty + ), + ), + CastError::NeedViaPtr => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: needs casting through a raw pointer first", + d.expr_ty, + d.cast_ty + ), + ), + CastError::NeedViaThinPtr => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: needs casting through a thin pointer first", + d.expr_ty, + d.cast_ty + ), + ), + CastError::NeedViaInt => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: needs casting through an integer first", + d.expr_ty, + d.cast_ty + ), + ), + CastError::NonScalar => ( + DiagnosticCode::RustcHardError("E0605"), + format_ty!(ctx, "non-primitive cast: `{}` as `{}`", d.expr_ty, d.cast_ty), + ), + CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => ( + DiagnosticCode::RustcHardError("E0641"), + "cannot cast to a pointer of an unknown kind".to_owned(), + ), + }; + Diagnostic::new(code, message, display_range) +} + +// Diagnostic: cast-to-unsized +// +// This diagnostic is triggered when casting to an unsized type +pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsized) -> Diagnostic { + let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into())); + Diagnostic::new( + DiagnosticCode::RustcHardError("E0620"), + format_ty!(ctx, "cast to unsized type: `{}`", d.cast_ty), + display_range, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_diagnostics, check_diagnostics_with_disabled}; + + #[test] + fn cast_as_bool() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let u = 5 as bool; + //^^^^^^^^^ error: cannot cast `i32` as `bool` + + let t = (1 + 2) as bool; + //^^^^^^^^^^^^^^^ error: cannot cast `i32` as `bool` + + let _ = 5_u32 as bool; + //^^^^^^^^^^^^^ error: cannot cast `u32` as `bool` + + let _ = 64.0_f64 as bool; + //^^^^^^^^^^^^^^^^ error: cannot cast `f64` as `bool` + + enum IntEnum { + Zero, + One, + Two + } + let _ = IntEnum::One as bool; + //^^^^^^^^^^^^^^^^^^^^ error: cannot cast `IntEnum` as `bool` + + fn uwu(_: u8) -> i32 { + 5 + } + + unsafe fn owo() {} + + let _ = uwu as bool; + //^^^^^^^^^^^ error: cannot cast `fn uwu(u8) -> i32` as `bool` + let _ = owo as bool; + //^^^^^^^^^^^ error: cannot cast `unsafe fn owo()` as `bool` + + let _ = uwu as fn(u8) -> i32 as bool; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot cast `fn(u8) -> i32` as `bool` + let _ = 'x' as bool; + //^^^^^^^^^^^ error: cannot cast `char` as `bool` + + let ptr = 1 as *const (); + + let _ = ptr as bool; + //^^^^^^^^^^^ error: cannot cast `*const ()` as `bool` + let v = "hello" as bool; + //^^^^^^^^^^^^^^^ error: casting `&str` as `bool` is invalid: needs casting through a raw pointer first +} +"#, + ); + } + + #[test] + fn cast_pointee_projection() { + check_diagnostics( + r#" +//- minicore: sized +trait Tag<'a> { + type Type: ?Sized; +} + +trait IntoRaw: for<'a> Tag<'a> { + fn into_raw(this: *const >::Type) -> *mut >::Type; +} + +impl Tag<'a>> IntoRaw for T { + fn into_raw(this: *const >::Type) -> *mut >::Type { + this as *mut T::Type + } +} + +fn main() {} +"#, + ); + } + + #[test] + fn cast_region_to_int() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let x: isize = 3; + let _ = &x as *const isize as usize; +} +"#, + ); + } + + #[test] + fn cast_to_bare_fn() { + check_diagnostics( + r#" +//- minicore: sized +fn foo(_x: isize) { } + +fn main() { + let v: u64 = 5; + let x = foo as extern "C" fn() -> isize; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `fn foo(isize)` as `fn() -> isize` + let y = v as extern "Rust" fn(isize) -> (isize, isize); + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `u64` as `fn(isize) -> (isize, isize)` + y(x()); +} +"#, + ); + } + + #[test] + fn cast_to_unit() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let _ = 0u32 as (); + //^^^^^^^^^^ error: non-primitive cast: `u32` as `()` +} +"#, + ); + } + + #[test] + fn cast_to_slice() { + check_diagnostics_with_disabled( + r#" +//- minicore: sized +fn as_bytes(_: &str) -> &[u8] { + loop {} +} + +fn main() { + as_bytes("example") as [char]; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cast to unsized type: `[char]` + + let arr: &[u8] = &[0, 2, 3]; + arr as [char]; + //^^^^^^^^^^^^^ error: cast to unsized type: `[char]` +} +"#, + &["E0308"], + ); + } + + #[test] + fn cast() { + check_diagnostics( + r#" +//- minicore: sized +fn null_mut() -> *mut T { + loop {} +} + +pub fn main() { + let i: isize = 'Q' as isize; + let _u: u32 = i as u32; + + // Test that `_` is correctly inferred. + let x = &"hello"; + let mut y = x as *const _; + y = null_mut(); +} +"#, + ); + } + + #[test] + fn dyn_tail_need_normalization() { + check_diagnostics( + r#" +//- minicore: dispatch_from_dyn +trait Trait { + type Associated; +} + +impl Trait for i32 { + type Associated = i64; +} + +trait Generic {} + +type TraitObject = dyn Generic<::Associated>; + +struct Wrap(TraitObject); + +fn cast(x: *mut TraitObject) { + x as *mut Wrap; +} +"#, + ); + } + + #[test] + fn enum_to_numeric_cast() { + check_diagnostics( + r#" +//- minicore: sized +pub enum UnitOnly { + Foo, + Bar, + Baz, +} + +pub enum Fieldless { + Tuple(), + Struct{}, + Unit, +} + +pub enum NotUnitOnlyOrFieldless { + Foo, + Bar(u8), + Baz +} + +fn main() { + let unit_only = UnitOnly::Foo; + + let _ = unit_only as isize; + let _ = unit_only as i32; + let _ = unit_only as usize; + let _ = unit_only as u32; + + + let fieldless = Fieldless::Struct{}; + + let _ = fieldless as isize; + let _ = fieldless as i32; + let _ = fieldless as usize; + let _ = fieldless as u32; + + + let not_unit_only_or_fieldless = NotUnitOnlyOrFieldless::Foo; + + let _ = not_unit_only_or_fieldless as isize; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `NotUnitOnlyOrFieldless` as `isize` + let _ = not_unit_only_or_fieldless as i32; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `NotUnitOnlyOrFieldless` as `i32` + let _ = not_unit_only_or_fieldless as usize; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `NotUnitOnlyOrFieldless` as `usize` + let _ = not_unit_only_or_fieldless as u32; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `NotUnitOnlyOrFieldless` as `u32` +} +"#, + ); + } + + #[test] + fn fat_ptr_cast() { + check_diagnostics_with_disabled( + r#" +//- minicore: sized +trait Foo { + fn foo(&self) {} //~ WARN method `foo` is never used +} + +struct Bar; + +impl Foo for Bar {} + +fn to_raw(_: *mut T) -> *mut () { + loop {} +} + +fn main() { + // Test we can turn a fat pointer to array back into a thin pointer. + let a: *const [i32] = &[1, 2, 3]; + let b = a as *const [i32; 2]; + + // Test conversion to an address (usize). + let a: *const [i32; 3] = &[1, 2, 3]; + let b: *const [i32] = a; + + // And conversion to a void pointer/address for trait objects too. + let a: *mut dyn Foo = &mut Bar; + let b = a as *mut () as usize; + let c = a as *const () as usize; + let d = to_raw(a) as usize; +} +"#, + &["E0308"], + ); + + check_diagnostics_with_disabled( + r#" +//- minicore: sized +trait Trait {} + +struct Box; + +impl Box { + fn new(_: T) -> Self { + loop {} + } +} + +fn as_ptr(_: &[i32]) -> *const i32 { + loop {} +} + +fn main() { + let a: &[i32] = &[1, 2, 3]; + let b: Box<[i32]> = Box::new([1, 2, 3]); + let p = a as *const [i32]; + let q = as_ptr(a); + + a as usize; + //^^^^^^^^^^ error: casting `&[i32]` as `usize` is invalid: needs casting through a raw pointer first + a as isize; + //^^^^^^^^^^ error: casting `&[i32]` as `isize` is invalid: needs casting through a raw pointer first + a as i16; + //^^^^^^^^ error: casting `&[i32]` as `i16` is invalid: needs casting through a raw pointer first + a as u32; + //^^^^^^^^ error: casting `&[i32]` as `u32` is invalid: needs casting through a raw pointer first + b as usize; + //^^^^^^^^^^ error: non-primitive cast: `Box<[i32]>` as `usize` + p as usize; + //^^^^^^^^^^ error: casting `*const [i32]` as `usize` is invalid: needs casting through a thin pointer first + q as *const [i32]; + //^^^^^^^^^^^^^^^^^ error: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]` + + let t: *mut (dyn Trait + 'static) = 0 as *mut _; + //^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*mut _` + let mut fail: *const str = 0 as *const str; + //^^^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const str` + let mut fail2: *const str = 0isize as *const str; + //^^^^^^^^^^^^^^^^^^^^ error: cannot cast `isize` to a fat pointer `*const str` +} + +fn foo() { + let s = 0 as *const T; + //^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const T` +} +"#, + &["E0308", "unused_variables"], + ); + } + + #[test] + fn order_dependent_cast_inference() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let x = &"hello"; + let mut y = 0 as *const _; + //^^^^^^^^^^^^^ error: cannot cast to a pointer of an unknown kind + y = x as *const _; +} +"#, + ); + } + + #[test] + fn ptr_to_ptr_different_regions() { + check_diagnostics( + r#" +//- minicore: sized +struct Foo<'a> { a: &'a () } + +fn extend_lifetime_very_very_safely<'a>(v: *const Foo<'a>) -> *const Foo<'static> { + // This should pass because raw pointer casts can do anything they want. + v as *const Foo<'static> +} + +trait Trait {} + +fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) { + ptr as _ +} + +fn main() { + let unit = (); + let foo = Foo { a: &unit }; + let _long: *const Foo<'static> = extend_lifetime_very_very_safely(&foo); +} +"#, + ); + } + + #[test] + fn ptr_to_trait_obj_add_auto() { + check_diagnostics( + r#" +//- minicore: pointee +trait Trait<'a> {} + +fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) { + x as _ +} + +// (to test diagnostic list formatting) +fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + Sync + Unpin) { + x as _ +} +"#, + ); + } + + #[test] + fn ptr_to_trait_obj_add_super_auto() { + check_diagnostics( + r#" +//- minicore: pointee +trait Trait: Send {} +impl Trait for () {} + +fn main() { + // This is OK: `Trait` has `Send` super trait. + &() as *const dyn Trait as *const (dyn Trait + Send); +} +"#, + ); + } + + #[test] + fn ptr_to_trait_obj_ok() { + check_diagnostics( + r#" +//- minicore: pointee +trait Trait<'a> {} + +fn remove_auto<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut dyn Trait<'a> { + x as _ +} + +fn cast_inherent_lt<'a, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trait<'static> + 'b) { + x as _ +} + +fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) { + x as _ +} +"#, + ); + } + + #[ignore = "issue #18047"] + #[test] + fn ptr_to_trait_obj_wrap_upcast() { + check_diagnostics( + r#" +//- minicore: sized +trait Super {} +trait Sub: Super {} + +struct Wrapper(T); + +// This cast should not compile. +// Upcasting can't work here, because we are also changing the type (`Wrapper`), +// and reinterpreting would be confusing/surprising. +// See +fn cast(ptr: *const dyn Sub) -> *const Wrapper { + ptr as _ + //^^^^^^^^ error: casting `*const dyn Sub` as `*const Wrapper` is invalid: vtable kinds may not match +} +"#, + ); + } + + #[test] + fn supported_cast() { + check_diagnostics( + r#" +//- minicore: sized +pub fn main() { + struct String; + + let f = 1_usize as *const String; + + let _ = f as isize; + let _ = f as usize; + let _ = f as i8; + let _ = f as i16; + let _ = f as i32; + let _ = f as i64; + let _ = f as u8; + let _ = f as u16; + let _ = f as u32; + let _ = f as u64; + + let _ = 1 as isize; + let _ = 1 as usize; + let _ = 1 as *const String; + let _ = 1 as i8; + let _ = 1 as i16; + let _ = 1 as i32; + let _ = 1 as i64; + let _ = 1 as u8; + let _ = 1 as u16; + let _ = 1 as u32; + let _ = 1 as u64; + let _ = 1 as f32; + let _ = 1 as f64; + + let _ = 1_usize as isize; + let _ = 1_usize as usize; + let _ = 1_usize as *const String; + let _ = 1_usize as i8; + let _ = 1_usize as i16; + let _ = 1_usize as i32; + let _ = 1_usize as i64; + let _ = 1_usize as u8; + let _ = 1_usize as u16; + let _ = 1_usize as u32; + let _ = 1_usize as u64; + let _ = 1_usize as f32; + let _ = 1_usize as f64; + + let _ = 1i8 as isize; + let _ = 1i8 as usize; + let _ = 1i8 as *const String; + let _ = 1i8 as i8; + let _ = 1i8 as i16; + let _ = 1i8 as i32; + let _ = 1i8 as i64; + let _ = 1i8 as u8; + let _ = 1i8 as u16; + let _ = 1i8 as u32; + let _ = 1i8 as u64; + let _ = 1i8 as f32; + let _ = 1i8 as f64; + + let _ = 1u8 as isize; + let _ = 1u8 as usize; + let _ = 1u8 as *const String; + let _ = 1u8 as i8; + let _ = 1u8 as i16; + let _ = 1u8 as i32; + let _ = 1u8 as i64; + let _ = 1u8 as u8; + let _ = 1u8 as u16; + let _ = 1u8 as u32; + let _ = 1u8 as u64; + let _ = 1u8 as f32; + let _ = 1u8 as f64; + + let _ = 1i16 as isize; + let _ = 1i16 as usize; + let _ = 1i16 as *const String; + let _ = 1i16 as i8; + let _ = 1i16 as i16; + let _ = 1i16 as i32; + let _ = 1i16 as i64; + let _ = 1i16 as u8; + let _ = 1i16 as u16; + let _ = 1i16 as u32; + let _ = 1i16 as u64; + let _ = 1i16 as f32; + let _ = 1i16 as f64; + + let _ = 1u16 as isize; + let _ = 1u16 as usize; + let _ = 1u16 as *const String; + let _ = 1u16 as i8; + let _ = 1u16 as i16; + let _ = 1u16 as i32; + let _ = 1u16 as i64; + let _ = 1u16 as u8; + let _ = 1u16 as u16; + let _ = 1u16 as u32; + let _ = 1u16 as u64; + let _ = 1u16 as f32; + let _ = 1u16 as f64; + + let _ = 1i32 as isize; + let _ = 1i32 as usize; + let _ = 1i32 as *const String; + let _ = 1i32 as i8; + let _ = 1i32 as i16; + let _ = 1i32 as i32; + let _ = 1i32 as i64; + let _ = 1i32 as u8; + let _ = 1i32 as u16; + let _ = 1i32 as u32; + let _ = 1i32 as u64; + let _ = 1i32 as f32; + let _ = 1i32 as f64; + + let _ = 1u32 as isize; + let _ = 1u32 as usize; + let _ = 1u32 as *const String; + let _ = 1u32 as i8; + let _ = 1u32 as i16; + let _ = 1u32 as i32; + let _ = 1u32 as i64; + let _ = 1u32 as u8; + let _ = 1u32 as u16; + let _ = 1u32 as u32; + let _ = 1u32 as u64; + let _ = 1u32 as f32; + let _ = 1u32 as f64; + + let _ = 1i64 as isize; + let _ = 1i64 as usize; + let _ = 1i64 as *const String; + let _ = 1i64 as i8; + let _ = 1i64 as i16; + let _ = 1i64 as i32; + let _ = 1i64 as i64; + let _ = 1i64 as u8; + let _ = 1i64 as u16; + let _ = 1i64 as u32; + let _ = 1i64 as u64; + let _ = 1i64 as f32; + let _ = 1i64 as f64; + + let _ = 1u64 as isize; + let _ = 1u64 as usize; + let _ = 1u64 as *const String; + let _ = 1u64 as i8; + let _ = 1u64 as i16; + let _ = 1u64 as i32; + let _ = 1u64 as i64; + let _ = 1u64 as u8; + let _ = 1u64 as u16; + let _ = 1u64 as u32; + let _ = 1u64 as u64; + let _ = 1u64 as f32; + let _ = 1u64 as f64; + + let _ = 1u64 as isize; + let _ = 1u64 as usize; + let _ = 1u64 as *const String; + let _ = 1u64 as i8; + let _ = 1u64 as i16; + let _ = 1u64 as i32; + let _ = 1u64 as i64; + let _ = 1u64 as u8; + let _ = 1u64 as u16; + let _ = 1u64 as u32; + let _ = 1u64 as u64; + let _ = 1u64 as f32; + let _ = 1u64 as f64; + + let _ = true as isize; + let _ = true as usize; + let _ = true as i8; + let _ = true as i16; + let _ = true as i32; + let _ = true as i64; + let _ = true as u8; + let _ = true as u16; + let _ = true as u32; + let _ = true as u64; + + let _ = 1f32 as isize; + let _ = 1f32 as usize; + let _ = 1f32 as i8; + let _ = 1f32 as i16; + let _ = 1f32 as i32; + let _ = 1f32 as i64; + let _ = 1f32 as u8; + let _ = 1f32 as u16; + let _ = 1f32 as u32; + let _ = 1f32 as u64; + let _ = 1f32 as f32; + let _ = 1f32 as f64; + + let _ = 1f64 as isize; + let _ = 1f64 as usize; + let _ = 1f64 as i8; + let _ = 1f64 as i16; + let _ = 1f64 as i32; + let _ = 1f64 as i64; + let _ = 1f64 as u8; + let _ = 1f64 as u16; + let _ = 1f64 as u32; + let _ = 1f64 as u64; + let _ = 1f64 as f32; + let _ = 1f64 as f64; +} +"#, + ); + } + + #[test] + fn unsized_struct_cast() { + check_diagnostics( + r#" +//- minicore: sized +pub struct Data([u8]); + +fn foo(x: &[u8]) { + let _: *const Data = x as *const Data; + //^^^^^^^^^^^^^^^^ error: casting `&[u8]` as `*const Data` is invalid +} +"#, + ); + } + + #[test] + fn unsupported_cast() { + check_diagnostics( + r#" +//- minicore: sized +struct A; + +fn main() { + let _ = 1.0 as *const A; + //^^^^^^^^^^^^^^^ error: casting `f64` as `*const A` is invalid +} +"#, + ); + } + + #[test] + fn issue_17897() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + _ = ((), ()) as (); + //^^^^^^^^^^^^^^ error: non-primitive cast: `((), ())` as `()` +} +"#, + ); + } + + #[test] + fn rustc_issue_10991() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let nil = (); + let _t = nil as usize; + //^^^^^^^^^^^^ error: non-primitive cast: `()` as `usize` +} +"#, + ); + } + + #[test] + fn rustc_issue_17444() { + check_diagnostics( + r#" +//- minicore: sized +enum Test { + Foo = 0 +} + +fn main() { + let _x = Test::Foo as *const isize; + //^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `Test` as `*const isize` is invalid +} +"#, + ); + } + + #[test] + fn rustc_issue_43825() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let error = error; + //^^^^^ error: no such value in this scope + + 0 as f32; + 0.0 as u32; +} +"#, + ); + } + + #[test] + fn rustc_issue_84213() { + check_diagnostics( + r#" +//- minicore: sized +struct Something { + pub field: u32, +} + +fn main() { + let mut something = Something { field: 1337 }; + let _ = something.field; + + let _pointer_to_something = something as *const Something; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `Something` as `*const Something` + + let _mut_pointer_to_something = something as *mut Something; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `Something` as `*mut Something` +} +"#, + ); + + // Fixed + check_diagnostics( + r#" +//- minicore: sized +struct Something { + pub field: u32, +} + +fn main() { + let mut something = Something { field: 1337 }; + let _ = something.field; + + let _pointer_to_something = &something as *const Something; + + let _mut_pointer_to_something = &mut something as *mut Something; +} +"#, + ); + } + + #[test] + fn rustc_issue_88621() { + check_diagnostics( + r#" +//- minicore: sized +#[repr(u8)] +enum Kind2 { + Foo() = 1, + Bar{} = 2, + Baz = 3, +} + +fn main() { + let _ = Kind2::Foo() as u8; + //^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `Kind2` as `u8` +} +"#, + ); + } + + #[test] + fn rustc_issue_89497() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `*const i32` as `&i32` +} +"#, + ); + + // Fixed + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { &*(pointer as *const i32) }; +} +"#, + ); + } + + #[test] + fn rustc_issue_106883() { + check_diagnostics_with_disabled( + r#" +//- minicore: sized, deref +use core::ops::Deref; + +struct Foo; + +impl Deref for Foo { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &[] + } +} + +fn main() { + let _ = "foo" as bool; + //^^^^^^^^^^^^^ error: casting `&str` as `bool` is invalid: needs casting through a raw pointer first + + let _ = Foo as bool; + //^^^^^^^^^^^ error: non-primitive cast: `Foo` as `bool` +} + +fn _slice(bar: &[i32]) -> bool { + bar as bool + //^^^^^^^^^^^ error: casting `&[i32]` as `bool` is invalid: needs casting through a raw pointer first +} +"#, + &["E0308"], + ); + } + + #[test] + fn trait_upcasting() { + check_diagnostics( + r#" +//- minicore: coerce_unsized, dispatch_from_dyn +#![feature(trait_upcasting)] +trait Foo {} +trait Bar: Foo {} + +impl dyn Bar { + fn bar(&self) { + _ = self as &dyn Foo; + } +} +"#, + ); + } + + #[test] + fn issue_18047() { + check_diagnostics( + r#" +//- minicore: coerce_unsized, dispatch_from_dyn +trait LocalFrom { + fn from(_: T) -> Self; +} +trait LocalInto { + fn into(self) -> T; +} + +impl LocalInto for T +where + U: LocalFrom, +{ + fn into(self) -> U { + U::from(self) + } +} + +impl LocalFrom for T { + fn from(t: T) -> T { + t + } +} + +trait Foo { + type ErrorType; + type Assoc; +} + +trait Bar { + type ErrorType; +} + +struct ErrorLike; + +impl LocalFrom for ErrorLike +where + E: Trait + 'static, +{ + fn from(_: E) -> Self { + loop {} + } +} + +trait Baz { + type Assoc: Bar; + type Error: LocalInto; +} + +impl Baz for T +where + T: Foo, + T::ErrorType: LocalInto, + U: Bar, + ::ErrorType: LocalInto, +{ + type Assoc = U; + type Error = T::ErrorType; +} +struct S; +trait Trait {} +impl Trait for S {} + +fn test() +where + T: Baz, + T::Assoc: 'static, +{ + let _ = &S as &dyn Trait; +} +"#, + ); + } + + #[test] + fn cast_literal_to_char() { + check_diagnostics( + r#" +fn foo() { + 0 as char; +} + "#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index af8ac6005d7a7..5b43f4b2af3d0 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -11,9 +11,14 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; // // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { + let code = if d.only_lint { + DiagnosticCode::RustcLint("unsafe_op_in_unsafe_fn") + } else { + DiagnosticCode::RustcHardError("E0133") + }; Diagnostic::new_with_syntax_node_ptr( ctx, - DiagnosticCode::RustcHardError("E0133"), + code, "this operation is unsafe and requires an unsafe function or block", d.expr.map(|it| it.into()), ) @@ -99,8 +104,9 @@ mod tests { fn missing_unsafe_diagnostic_with_raw_ptr() { check_diagnostics( r#" +//- minicore: sized fn main() { - let x = &5 as *const usize; + let x = &5_usize as *const usize; unsafe { let _y = *x; } let _z = *x; } //^^💡 error: this operation is unsafe and requires an unsafe function or block @@ -112,17 +118,18 @@ fn main() { fn missing_unsafe_diagnostic_with_unsafe_call() { check_diagnostics( r#" +//- minicore: sized struct HasUnsafe; impl HasUnsafe { unsafe fn unsafe_fn(&self) { - let x = &5 as *const usize; + let x = &5_usize as *const usize; let _y = *x; } } unsafe fn unsafe_fn() { - let x = &5 as *const usize; + let x = &5_usize as *const usize; let _y = *x; } @@ -163,6 +170,56 @@ fn main() { ); } + #[test] + fn missing_unsafe_diagnostic_with_extern_static() { + check_diagnostics( + r#" +//- minicore: copy + +extern "C" { + static EXTERN: i32; + static mut EXTERN_MUT: i32; +} + +fn main() { + let _x = EXTERN; + //^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + let _x = EXTERN_MUT; + //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + unsafe { + let _x = EXTERN; + let _x = EXTERN_MUT; + } +} +"#, + ); + } + + #[test] + fn no_unsafe_diagnostic_with_addr_of_static() { + check_diagnostics( + r#" +//- minicore: copy, addr_of + +use core::ptr::{addr_of, addr_of_mut}; + +extern "C" { + static EXTERN: i32; + static mut EXTERN_MUT: i32; +} +static mut STATIC_MUT: i32 = 0; + +fn main() { + let _x = addr_of!(EXTERN); + let _x = addr_of!(EXTERN_MUT); + let _x = addr_of!(STATIC_MUT); + let _x = addr_of_mut!(EXTERN_MUT); + let _x = addr_of_mut!(STATIC_MUT); +} +"#, + ); + } + #[test] fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { check_diagnostics( @@ -200,14 +257,15 @@ fn main() { fn add_unsafe_block_when_dereferencing_a_raw_pointer() { check_fix( r#" +//- minicore: sized fn main() { - let x = &5 as *const usize; + let x = &5_usize as *const usize; let _z = *x$0; } "#, r#" fn main() { - let x = &5 as *const usize; + let x = &5_usize as *const usize; let _z = unsafe { *x }; } "#, @@ -218,8 +276,9 @@ fn main() { fn add_unsafe_block_when_calling_unsafe_function() { check_fix( r#" +//- minicore: sized unsafe fn func() { - let x = &5 as *const usize; + let x = &5_usize as *const usize; let z = *x; } fn main() { @@ -228,7 +287,7 @@ fn main() { "#, r#" unsafe fn func() { - let x = &5 as *const usize; + let x = &5_usize as *const usize; let z = *x; } fn main() { @@ -242,6 +301,7 @@ fn main() { fn add_unsafe_block_when_calling_unsafe_method() { check_fix( r#" +//- minicore: sized struct S(usize); impl S { unsafe fn func(&self) { @@ -507,6 +567,30 @@ fn main() { ed2021::safe(); ed2024::not_safe(); //^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block +} + "#, + ) + } + + #[test] + fn unsafe_op_in_unsafe_fn_allowed_by_default() { + check_diagnostics( + r#" +unsafe fn foo(p: *mut i32) { + *p = 123; +} + "#, + ) + } + + #[test] + fn unsafe_op_in_unsafe_fn() { + check_diagnostics( + r#" +#![warn(unsafe_op_in_unsafe_fn)] +unsafe fn foo(p: *mut i32) { + *p = 123; + //^^💡 warn: this operation is unsafe and requires an unsafe function or block } "#, ) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index 06c6b0f3e4c38..a9ff06fb0ab1e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -190,4 +190,16 @@ fn foo(mut slice: &[u32]) -> usize { "#, ); } + + #[test] + fn regression_16564() { + check_diagnostics( + r#" +//- minicore: copy +fn test() { + let _x = (&(&mut (),)).0 as *const (); +} + "#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index e4b1f3ca95998..955427939150b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -824,13 +824,13 @@ fn f() { #[test] fn or_pattern() { + // FIXME: `None` is inferred as unknown here for some reason check_diagnostics( r#" //- minicore: option fn f(_: i32) {} fn main() { let ((Some(mut x), None) | (_, Some(mut x))) = (None, Some(7)) else { return }; - //^^^^^ 💡 warn: variable does not need to be mutable f(x); } "#, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index 87932bf989f04..18647206236c9 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -84,7 +84,7 @@ fn foo() { fn replace_filter_map_next_dont_work_for_not_sized_issues_16596() { check_diagnostics( r#" -//- minicore: iterators +//- minicore: iterators, dispatch_from_dyn fn foo() { let mut j = [0].into_iter(); let i: &mut dyn Iterator = &mut j; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index b5c242e1e9f82..6994a7ed14656 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -402,4 +402,26 @@ fn f() { ], ); } + + #[test] + fn underscore_in_asm() { + check_diagnostics( + r#" +//- minicore: asm +fn rdtscp() -> u64 { + let hi: u64; + let lo: u64; + unsafe { + core::arch::asm!( + "rdtscp", + out("rdx") hi, + out("rax") lo, + out("rcx") _, + options(nomem, nostack, preserves_flags) + ); + } + (hi << 32) | lo +}"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 9b50a435e4c3a..45c723d09d4c3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -30,6 +30,7 @@ mod handlers { pub(crate) mod inactive_code; pub(crate) mod incoherent_impl; pub(crate) mod incorrect_case; + pub(crate) mod invalid_cast; pub(crate) mod invalid_derive_target; pub(crate) mod macro_error; pub(crate) mod malformed_derive; @@ -75,9 +76,10 @@ mod handlers { #[cfg(test)] mod tests; -use std::sync::LazyLock; +use std::{collections::hash_map, iter, sync::LazyLock}; -use hir::{diagnostics::AnyDiagnostic, InFile, Semantics}; +use either::Either; +use hir::{db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, HirFileId, InFile, Semantics}; use ide_db::{ assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}, base_db::SourceDatabase, @@ -88,10 +90,10 @@ use ide_db::{ syntax_helpers::node_ext::parse_tt_as_comma_sep_paths, EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, SnippetCap, }; -use stdx::never; +use itertools::Itertools; use syntax::{ - ast::{self, AstNode}, - AstPtr, Edition, SyntaxNode, SyntaxNodePtr, TextRange, + ast::{self, AstNode, HasAttrs}, + AstPtr, Edition, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxNodePtr, TextRange, T, }; // FIXME: Make this an enum @@ -390,6 +392,7 @@ pub fn semantic_diagnostics( for diag in diags { let d = match diag { AnyDiagnostic::AwaitOutsideOfAsync(d) => handlers::await_outside_of_async::await_outside_of_async(&ctx, &d), + AnyDiagnostic::CastToUnsized(d) => handlers::invalid_cast::cast_to_unsized(&ctx, &d), AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d), AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { Some(it) => it, @@ -397,6 +400,7 @@ pub fn semantic_diagnostics( } AnyDiagnostic::IncoherentImpl(d) => handlers::incoherent_impl::incoherent_impl(&ctx, &d), AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d), + AnyDiagnostic::InvalidCast(d) => handlers::invalid_cast::invalid_cast(&ctx, &d), AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d), AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d), AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), @@ -473,8 +477,9 @@ pub fn semantic_diagnostics( || ctx.config.disable_experimental && d.experimental) }); - let mut diagnostics_of_range = res + let mut lints = res .iter_mut() + .filter(|it| matches!(it.code, DiagnosticCode::Clippy(_) | DiagnosticCode::RustcLint(_))) .filter_map(|it| { Some(( it.main_node.map(|ptr| { @@ -483,27 +488,31 @@ pub fn semantic_diagnostics( it, )) }) - .collect::>(); + .collect::>(); - if diagnostics_of_range.is_empty() { - return res; - } - - let mut rustc_stack: FxHashMap> = FxHashMap::default(); - let mut clippy_stack: FxHashMap> = FxHashMap::default(); - - // FIXME: This becomes quite expensive for big files - handle_lint_attributes( + // The edition isn't accurate (each diagnostics may have its own edition due to macros), + // but it's okay as it's only being used for error recovery. + handle_lints( &ctx.sema, - parse.syntax(), - &mut rustc_stack, - &mut clippy_stack, - &mut diagnostics_of_range, - ctx.edition, + &mut FxHashMap::default(), + &mut lints, + &mut Vec::new(), + file_id.edition(), ); res.retain(|d| d.severity != Severity::Allow); + res.retain_mut(|diag| { + if let Some(node) = diag + .main_node + .map(|ptr| ptr.map(|node| node.to_node(&ctx.sema.parse_or_expand(ptr.file_id)))) + { + handle_diag_from_macros(&ctx.sema, diag, &node) + } else { + true + } + }); + res } @@ -520,6 +529,35 @@ pub fn full_diagnostics( res } +/// Returns whether to keep this diagnostic (or remove it). +fn handle_diag_from_macros( + sema: &Semantics<'_, RootDatabase>, + diag: &mut Diagnostic, + node: &InFile, +) -> bool { + let Some(macro_file) = node.file_id.macro_file() else { return true }; + let span_map = sema.db.expansion_span_map(macro_file); + let mut spans = span_map.spans_for_range(node.text_range()); + if spans.any(|span| { + sema.db.lookup_intern_syntax_context(span.ctx).outer_expn.is_some_and(|expansion| { + let macro_call = + sema.db.lookup_intern_macro_call(expansion.as_macro_file().macro_call_id); + !Crate::from(macro_call.def.krate).origin(sema.db).is_local() + }) + }) { + // Disable suggestions for external macros, they'll change library code and it's just bad. + diag.fixes = None; + + // All Clippy lints report in macros, see https://github.com/rust-lang/rust-clippy/blob/903293b199364/declare_clippy_lint/src/lib.rs#L172. + if let DiagnosticCode::RustcLint(lint) = diag.code { + if !LINTS_TO_REPORT_IN_EXTERNAL_MACROS.contains(lint) { + return false; + } + }; + } + true +} + // `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros static RUSTC_LINT_GROUPS_DICT: LazyLock>> = @@ -528,153 +566,347 @@ static RUSTC_LINT_GROUPS_DICT: LazyLock>> = static CLIPPY_LINT_GROUPS_DICT: LazyLock>> = LazyLock::new(|| build_group_dict(CLIPPY_LINT_GROUPS, &["__RA_EVERY_LINT"], "clippy::")); +// FIXME: Autogenerate this instead of enumerating by hand. +static LINTS_TO_REPORT_IN_EXTERNAL_MACROS: LazyLock> = + LazyLock::new(|| FxHashSet::from_iter([])); + fn build_group_dict( lint_group: &'static [LintGroup], all_groups: &'static [&'static str], prefix: &'static str, ) -> FxHashMap<&'static str, Vec<&'static str>> { - let mut r: FxHashMap<&str, Vec<&str>> = FxHashMap::default(); + let mut map_with_prefixes: FxHashMap<&str, Vec<&str>> = FxHashMap::default(); for g in lint_group { - for child in g.children { - r.entry(child.strip_prefix(prefix).unwrap()) - .or_default() - .push(g.lint.label.strip_prefix(prefix).unwrap()); + let mut add_children = |label: &'static str| { + for child in g.children { + map_with_prefixes.entry(child).or_default().push(label); + } + }; + add_children(g.lint.label); + + if g.lint.label == "nonstandard_style" { + // Also add `bad_style`, which for some reason isn't listed in the groups. + add_children("bad_style"); } } - for (lint, groups) in r.iter_mut() { + for (lint, groups) in map_with_prefixes.iter_mut() { groups.push(lint); groups.extend_from_slice(all_groups); } - r + map_with_prefixes.into_iter().map(|(k, v)| (k.strip_prefix(prefix).unwrap(), v)).collect() } -fn handle_lint_attributes( +/// Thd default severity for lints that are not warn by default. +// FIXME: Autogenerate this instead of write manually. +static LINTS_DEFAULT_SEVERITY: LazyLock> = + LazyLock::new(|| FxHashMap::from_iter([("unsafe_op_in_unsafe_fn", Severity::Allow)])); + +fn handle_lints( sema: &Semantics<'_, RootDatabase>, - root: &SyntaxNode, - rustc_stack: &mut FxHashMap>, - clippy_stack: &mut FxHashMap>, - diagnostics_of_range: &mut FxHashMap, &mut Diagnostic>, + cache: &mut FxHashMap>, + diagnostics: &mut [(InFile, &mut Diagnostic)], + cache_stack: &mut Vec, edition: Edition, ) { - let _g = tracing::info_span!("handle_lint_attributes").entered(); - let file_id = sema.hir_file_for(root); - let preorder = root.preorder(); - for ev in preorder { - match ev { - syntax::WalkEvent::Enter(node) => { - for attr in node.children().filter_map(ast::Attr::cast) { - parse_lint_attribute( - attr, - rustc_stack, - clippy_stack, - |stack, severity| { - stack.push(severity); - }, - edition, - ); - } - if let Some(it) = - diagnostics_of_range.get_mut(&InFile { file_id, value: node.clone() }) - { - const EMPTY_LINTS: &[&str] = &[]; - let (names, stack) = match it.code { - DiagnosticCode::RustcLint(name) => ( - RUSTC_LINT_GROUPS_DICT.get(name).map_or(EMPTY_LINTS, |it| &**it), - &mut *rustc_stack, - ), - DiagnosticCode::Clippy(name) => ( - CLIPPY_LINT_GROUPS_DICT.get(name).map_or(EMPTY_LINTS, |it| &**it), - &mut *clippy_stack, - ), - _ => continue, - }; - for &name in names { - if let Some(s) = stack.get(name).and_then(|it| it.last()) { - it.severity = *s; + for (node, diag) in diagnostics { + let lint = match diag.code { + DiagnosticCode::RustcLint(lint) | DiagnosticCode::Clippy(lint) => lint, + _ => panic!("non-lint passed to `handle_lints()`"), + }; + if let Some(&default_severity) = LINTS_DEFAULT_SEVERITY.get(lint) { + diag.severity = default_severity; + } + + let mut diag_severity = fill_lint_attrs(sema, node, cache, cache_stack, diag, edition); + + if let outline_diag_severity @ Some(_) = + find_outline_mod_lint_severity(sema, node, diag, edition) + { + diag_severity = outline_diag_severity; + } + + if let Some(diag_severity) = diag_severity { + diag.severity = diag_severity; + } + } +} + +fn find_outline_mod_lint_severity( + sema: &Semantics<'_, RootDatabase>, + node: &InFile, + diag: &Diagnostic, + edition: Edition, +) -> Option { + let mod_node = node.value.ancestors().find_map(ast::Module::cast)?; + if mod_node.item_list().is_some() { + // Inline modules will be handled by `fill_lint_attrs()`. + return None; + } + + let mod_def = sema.to_module_def(&mod_node)?; + let module_source_file = sema.module_definition_node(mod_def); + let mut result = None; + let lint_groups = lint_groups(&diag.code); + lint_attrs( + sema, + ast::AnyHasAttrs::cast(module_source_file.value).expect("SourceFile always has attrs"), + edition, + ) + .for_each(|(lint, severity)| { + if lint_groups.contains(&&*lint) { + result = Some(severity); + } + }); + result +} + +#[derive(Debug, Clone, Copy)] +struct SeverityAttr { + severity: Severity, + /// This field counts how far we are from the main node. Bigger values mean more far. + /// + /// Note this isn't accurate: there can be gaps between values (created when merging severity maps). + /// The important thing is that if an attr is closer to the main node, it will have smaller value. + /// + /// This is necessary even though we take care to never overwrite a value from deeper nesting + /// because of lint groups. For example, in the following code: + /// ``` + /// #[warn(non_snake_case)] + /// mod foo { + /// #[allow(nonstandard_style)] + /// mod bar; + /// } + /// ``` + /// We want to not warn on non snake case inside `bar`. If we are traversing this for the first + /// time, everything will be fine, because we will set `diag_severity` on the first matching group + /// and never overwrite it since then. But if `bar` is cached, the cache will contain both + /// `#[warn(non_snake_case)]` and `#[allow(nonstandard_style)]`, and without this field, we have + /// no way of differentiating between the two. + depth: u32, +} + +fn fill_lint_attrs( + sema: &Semantics<'_, RootDatabase>, + node: &InFile, + cache: &mut FxHashMap>, + cache_stack: &mut Vec, + diag: &Diagnostic, + edition: Edition, +) -> Option { + let mut collected_lint_attrs = FxHashMap::::default(); + let mut diag_severity = None; + + let mut ancestors = node.value.ancestors().peekable(); + let mut depth = 0; + loop { + let ancestor = ancestors.next().expect("we always return from top-level nodes"); + depth += 1; + + if ancestors.peek().is_none() { + // We don't want to insert too many nodes into cache, but top level nodes (aka. outline modules + // or macro expansions) need to touch the database so they seem like a good fit to cache. + + if let Some(cached) = cache.get_mut(&node.file_id) { + // This node (and everything above it) is already cached; the attribute is either here or nowhere. + + // Workaround for the borrow checker. + let cached = std::mem::take(cached); + + cached.iter().for_each(|(lint, severity)| { + for item in &*cache_stack { + let node_cache_entry = cache + .get_mut(item) + .expect("we always insert cached nodes into the cache map"); + let lint_cache_entry = node_cache_entry.entry(lint.clone()); + if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { + // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs + // overwrite top attrs. + lint_cache_entry.insert(SeverityAttr { + severity: severity.severity, + depth: severity.depth + depth, + }); } } + }); + + let all_matching_groups = lint_groups(&diag.code) + .iter() + .filter_map(|lint_group| cached.get(&**lint_group)); + let cached_severity = + all_matching_groups.min_by_key(|it| it.depth).map(|it| it.severity); + + cache.insert(node.file_id, cached); + + return diag_severity.or(cached_severity); + } + + // Insert this node's descendants' attributes into any outline descendant, but not including this node. + // This must come before inserting this node's own attributes to preserve order. + collected_lint_attrs.drain().for_each(|(lint, severity)| { + if diag_severity.is_none() && lint_groups(&diag.code).contains(&&*lint) { + diag_severity = Some(severity.severity); } - if let Some(item) = ast::Item::cast(node.clone()) { - if let Some(me) = sema.expand_attr_macro(&item) { - for stack in [&mut *rustc_stack, &mut *clippy_stack] { - stack - .entry("__RA_EVERY_LINT".to_owned()) - .or_default() - .push(Severity::Allow); - } - handle_lint_attributes( - sema, - &me, - rustc_stack, - clippy_stack, - diagnostics_of_range, - edition, - ); - for stack in [&mut *rustc_stack, &mut *clippy_stack] { - stack.entry("__RA_EVERY_LINT".to_owned()).or_default().pop(); - } + + for item in &*cache_stack { + let node_cache_entry = cache + .get_mut(item) + .expect("we always insert cached nodes into the cache map"); + let lint_cache_entry = node_cache_entry.entry(lint.clone()); + if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { + // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs + // overwrite top attrs. + lint_cache_entry.insert(severity); } } - if let Some(mc) = ast::MacroCall::cast(node) { - if let Some(me) = sema.expand(&mc) { - handle_lint_attributes( - sema, - &me, - rustc_stack, - clippy_stack, - diagnostics_of_range, - edition, - ); + }); + + cache_stack.push(node.file_id); + cache.insert(node.file_id, FxHashMap::default()); + + if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) { + // Insert this node's attributes into any outline descendant, including this node. + lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| { + if diag_severity.is_none() && lint_groups(&diag.code).contains(&&*lint) { + diag_severity = Some(severity); } - } + + for item in &*cache_stack { + let node_cache_entry = cache + .get_mut(item) + .expect("we always insert cached nodes into the cache map"); + let lint_cache_entry = node_cache_entry.entry(lint.clone()); + if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { + // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs + // overwrite top attrs. + lint_cache_entry.insert(SeverityAttr { severity, depth }); + } + } + }); } - syntax::WalkEvent::Leave(node) => { - for attr in node.children().filter_map(ast::Attr::cast) { - parse_lint_attribute( - attr, - rustc_stack, - clippy_stack, - |stack, severity| { - if stack.pop() != Some(severity) { - never!("Mismatched serevity in walking lint attributes"); - } - }, - edition, - ); + + let parent_node = sema.find_parent_file(node.file_id); + if let Some(parent_node) = parent_node { + let parent_severity = + fill_lint_attrs(sema, &parent_node, cache, cache_stack, diag, edition); + if diag_severity.is_none() { + diag_severity = parent_severity; } } + cache_stack.pop(); + return diag_severity; + } else if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) { + lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| { + if diag_severity.is_none() && lint_groups(&diag.code).contains(&&*lint) { + diag_severity = Some(severity); + } + + let lint_cache_entry = collected_lint_attrs.entry(lint); + if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { + // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs + // overwrite top attrs. + lint_cache_entry.insert(SeverityAttr { severity, depth }); + } + }); } } } -fn parse_lint_attribute( - attr: ast::Attr, - rustc_stack: &mut FxHashMap>, - clippy_stack: &mut FxHashMap>, - job: impl Fn(&mut Vec, Severity), +fn lint_attrs<'a>( + sema: &'a Semantics<'a, RootDatabase>, + ancestor: ast::AnyHasAttrs, edition: Edition, +) -> impl Iterator + 'a { + ancestor + .attrs_including_inner() + .filter_map(|attr| { + attr.as_simple_call().and_then(|(name, value)| match &*name { + "allow" | "expect" => Some(Either::Left(iter::once((Severity::Allow, value)))), + "warn" => Some(Either::Left(iter::once((Severity::Warning, value)))), + "forbid" | "deny" => Some(Either::Left(iter::once((Severity::Error, value)))), + "cfg_attr" => { + let mut lint_attrs = Vec::new(); + cfg_attr_lint_attrs(sema, &value, &mut lint_attrs); + Some(Either::Right(lint_attrs.into_iter())) + } + _ => None, + }) + }) + .flatten() + .flat_map(move |(severity, lints)| { + parse_tt_as_comma_sep_paths(lints, edition).into_iter().flat_map(move |lints| { + // Rejoin the idents with `::`, so we have no spaces in between. + lints.into_iter().map(move |lint| { + ( + lint.segments().filter_map(|segment| segment.name_ref()).join("::").into(), + severity, + ) + }) + }) + }) +} + +fn cfg_attr_lint_attrs( + sema: &Semantics<'_, RootDatabase>, + value: &ast::TokenTree, + lint_attrs: &mut Vec<(Severity, ast::TokenTree)>, ) { - let Some((tag, args_tt)) = attr.as_simple_call() else { - return; - }; - let severity = match tag.as_str() { - "allow" => Severity::Allow, - "warn" => Severity::Warning, - "forbid" | "deny" => Severity::Error, - _ => return, - }; - for lint in parse_tt_as_comma_sep_paths(args_tt, edition).into_iter().flatten() { - if let Some(lint) = lint.as_single_name_ref() { - job(rustc_stack.entry(lint.to_string()).or_default(), severity); + let prev_len = lint_attrs.len(); + + let mut iter = value.token_trees_and_tokens().filter(|it| match it { + NodeOrToken::Node(_) => true, + NodeOrToken::Token(it) => !it.kind().is_trivia(), + }); + + // Skip the condition. + for value in &mut iter { + if value.as_token().is_some_and(|it| it.kind() == T![,]) { + break; } - if let Some(tool) = lint.qualifier().and_then(|it| it.as_single_name_ref()) { - if let Some(name_ref) = &lint.segment().and_then(|it| it.name_ref()) { - if tool.to_string() == "clippy" { - job(clippy_stack.entry(name_ref.to_string()).or_default(), severity); + } + + while let Some(value) = iter.next() { + if let Some(token) = value.as_token() { + if token.kind() == SyntaxKind::IDENT { + let severity = match token.text() { + "allow" | "expect" => Some(Severity::Allow), + "warn" => Some(Severity::Warning), + "forbid" | "deny" => Some(Severity::Error), + "cfg_attr" => { + if let Some(NodeOrToken::Node(value)) = iter.next() { + cfg_attr_lint_attrs(sema, &value, lint_attrs); + } + None + } + _ => None, + }; + if let Some(severity) = severity { + let lints = iter.next(); + if let Some(NodeOrToken::Node(lints)) = lints { + lint_attrs.push((severity, lints)); + } } } } } + + if prev_len != lint_attrs.len() { + if let Some(false) | None = sema.check_cfg_attr(value) { + // Discard the attributes when the condition is false. + lint_attrs.truncate(prev_len); + } + } +} + +fn lint_groups(lint: &DiagnosticCode) -> &'static [&'static str] { + match lint { + DiagnosticCode::RustcLint(name) => { + RUSTC_LINT_GROUPS_DICT.get(name).map(|it| &**it).unwrap_or_default() + } + DiagnosticCode::Clippy(name) => { + CLIPPY_LINT_GROUPS_DICT.get(name).map(|it| &**it).unwrap_or_default() + } + _ => &[], + } } fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index 925ae620231d2..ea16a11d56d02 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -219,7 +219,9 @@ pub(crate) fn resolve_doc_path_for_def( | Definition::Local(_) | Definition::GenericParam(_) | Definition::Label(_) - | Definition::DeriveHelper(_) => None, + | Definition::DeriveHelper(_) + | Definition::InlineAsmRegOrRegClass(_) + | Definition::InlineAsmOperand(_) => None, } .map(Definition::from) } @@ -672,7 +674,9 @@ fn filename_and_frag_for_def( | Definition::BuiltinAttr(_) | Definition::BuiltinLifetime(_) | Definition::ToolModule(_) - | Definition::DeriveHelper(_) => return None, + | Definition::DeriveHelper(_) + | Definition::InlineAsmRegOrRegClass(_) + | Definition::InlineAsmOperand(_) => return None, }; Some((def, res, None)) diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index a939ed214ad85..79fdf75b7f7a9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -1,9 +1,10 @@ +use hir::db::ExpandDatabase; use hir::{InFile, MacroFileIdExt, Semantics}; +use ide_db::base_db::CrateId; use ide_db::{ - helpers::pick_best_token, syntax_helpers::insert_whitespace_into_node::insert_ws_into, FileId, - RootDatabase, + helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, FileId, RootDatabase, }; -use span::Edition; +use span::{Edition, SpanMap, SyntaxContextId, TextRange, TextSize}; use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T}; use crate::FilePosition; @@ -27,6 +28,7 @@ pub struct ExpandedMacro { pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option { let sema = Semantics::new(db); let file = sema.parse_guess_edition(position.file_id); + let krate = sema.file_to_module_def(position.file_id)?.krate().into(); let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { SyntaxKind::IDENT => 1, @@ -61,8 +63,17 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< .take_while(|it| it != &token) .filter(|it| it.kind() == T![,]) .count(); - let expansion = - format(db, SyntaxKind::MACRO_ITEMS, position.file_id, expansions.get(idx).cloned()?); + let expansion = expansions.get(idx)?.clone(); + let expansion_file_id = sema.hir_file_for(&expansion).macro_file()?; + let expansion_span_map = db.expansion_span_map(expansion_file_id); + let expansion = format( + db, + SyntaxKind::MACRO_ITEMS, + position.file_id, + expansion, + &expansion_span_map, + krate, + ); Some(ExpandedMacro { name, expansion }) }); @@ -71,6 +82,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< } let mut anc = tok.parent_ancestors(); + let mut span_map = SpanMap::empty(); let (name, expanded, kind) = loop { let node = anc.next()?; @@ -85,7 +97,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< .unwrap_or(Edition::CURRENT), ) .to_string(), - expand_macro_recur(&sema, &item)?, + expand_macro_recur(&sema, &item, &mut span_map, TextSize::new(0))?, SyntaxKind::MACRO_ITEMS, ); } @@ -95,14 +107,23 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< name.push('!'); let syntax_kind = mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS); - break (name, expand_macro_recur(&sema, &ast::Item::MacroCall(mac))?, syntax_kind); + break ( + name, + expand_macro_recur( + &sema, + &ast::Item::MacroCall(mac), + &mut span_map, + TextSize::new(0), + )?, + syntax_kind, + ); } }; // FIXME: // macro expansion may lose all white space information // But we hope someday we can use ra_fmt for that - let expansion = format(db, kind, position.file_id, expanded); + let expansion = format(db, kind, position.file_id, expanded, &span_map, krate); Some(ExpandedMacro { name, expansion }) } @@ -110,6 +131,8 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< fn expand_macro_recur( sema: &Semantics<'_, RootDatabase>, macro_call: &ast::Item, + result_span_map: &mut SpanMap, + offset_in_original_node: TextSize, ) -> Option { let expanded = match macro_call { item @ ast::Item::MacroCall(macro_call) => sema @@ -118,29 +141,60 @@ fn expand_macro_recur( .clone_for_update(), item => sema.expand_attr_macro(item)?.clone_for_update(), }; - expand(sema, expanded) + let file_id = + sema.hir_file_for(&expanded).macro_file().expect("expansion must produce a macro file"); + let expansion_span_map = sema.db.expansion_span_map(file_id); + result_span_map.merge( + TextRange::at(offset_in_original_node, macro_call.syntax().text_range().len()), + expanded.text_range().len(), + &expansion_span_map, + ); + Some(expand(sema, expanded, result_span_map, u32::from(offset_in_original_node) as i32)) } -fn expand(sema: &Semantics<'_, RootDatabase>, expanded: SyntaxNode) -> Option { +fn expand( + sema: &Semantics<'_, RootDatabase>, + expanded: SyntaxNode, + result_span_map: &mut SpanMap, + mut offset_in_original_node: i32, +) -> SyntaxNode { let children = expanded.descendants().filter_map(ast::Item::cast); let mut replacements = Vec::new(); for child in children { - if let Some(new_node) = expand_macro_recur(sema, &child) { + if let Some(new_node) = expand_macro_recur( + sema, + &child, + result_span_map, + TextSize::new( + (offset_in_original_node + (u32::from(child.syntax().text_range().start()) as i32)) + as u32, + ), + ) { + offset_in_original_node = offset_in_original_node + + (u32::from(new_node.text_range().len()) as i32) + - (u32::from(child.syntax().text_range().len()) as i32); // check if the whole original syntax is replaced if expanded == *child.syntax() { - return Some(new_node); + return new_node; } replacements.push((child, new_node)); } } replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new)); - Some(expanded) + expanded } -fn format(db: &RootDatabase, kind: SyntaxKind, file_id: FileId, expanded: SyntaxNode) -> String { - let expansion = insert_ws_into(expanded).to_string(); +fn format( + db: &RootDatabase, + kind: SyntaxKind, + file_id: FileId, + expanded: SyntaxNode, + span_map: &SpanMap, + krate: CrateId, +) -> String { + let expansion = prettify_macro_expansion(db, expanded, span_map, krate).to_string(); _format(db, kind, file_id, &expansion).unwrap_or(expansion) } @@ -498,7 +552,7 @@ struct Foo {} "#, expect![[r#" Clone - impl < >$crate::clone::Clone for Foo< >where { + impl < >core::clone::Clone for Foo< >where { fn clone(&self) -> Self { match self { Foo{} @@ -524,7 +578,7 @@ struct Foo {} "#, expect![[r#" Copy - impl < >$crate::marker::Copy for Foo< >where{}"#]], + impl < >core::marker::Copy for Foo< >where{}"#]], ); } @@ -539,7 +593,7 @@ struct Foo {} "#, expect![[r#" Copy - impl < >$crate::marker::Copy for Foo< >where{}"#]], + impl < >core::marker::Copy for Foo< >where{}"#]], ); check( r#" @@ -550,7 +604,7 @@ struct Foo {} "#, expect![[r#" Clone - impl < >$crate::clone::Clone for Foo< >where { + impl < >core::clone::Clone for Foo< >where { fn clone(&self) -> Self { match self { Foo{} @@ -563,4 +617,44 @@ struct Foo {} }"#]], ); } + + #[test] + fn dollar_crate() { + check( + r#" +//- /a.rs crate:a +pub struct Foo; +#[macro_export] +macro_rules! m { + ( $i:ident ) => { $crate::Foo; $crate::Foo; $i::Foo; }; +} +//- /b.rs crate:b deps:a +pub struct Foo; +#[macro_export] +macro_rules! m { + () => { a::m!($crate); $crate::Foo; $crate::Foo; }; +} +//- /c.rs crate:c deps:b,a +pub struct Foo; +#[macro_export] +macro_rules! m { + () => { b::m!(); $crate::Foo; $crate::Foo; }; +} +fn bar() { + m$0!(); +} +"#, + expect![[r#" +m! +a::Foo; +a::Foo; +b::Foo; +; +b::Foo; +b::Foo; +; +crate::Foo; +crate::Foo;"#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 971cd3ef585c4..8836166d969df 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -2750,4 +2750,36 @@ fn foo() { "#, ); } + + #[test] + fn issue_18138() { + check( + r#" +mod foo { + macro_rules! x { + () => { + pub struct Foo; + // ^^^ + }; + } + pub(crate) use x as m; +} + +mod bar { + use crate::m; + + m!(); + // ^^^^^ + + fn qux() { + Foo$0; + } +} + +mod m {} + +use foo::m; +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 5348e855be4b0..4c8e3fc3040c2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -2004,6 +2004,36 @@ fn main() { { return; } +"#, + ) + } + + #[test] + fn asm() { + check( + r#" +//- minicore: asm +#[inline] +pub unsafe fn bootstrap() -> ! { + builtin#asm( + "blabla", + "mrs {tmp}, CONTROL", + // ^^^ read + "blabla", + "bics {tmp}, {spsel}", + // ^^^ read + "blabla", + "msr CONTROL, {tmp}", + // ^^^ read + "blabla", + tmp$0 = inout(reg) 0, + // ^^^ + aaa = in(reg) 2, + aaa = in(reg) msp, + aaa = in(reg) rv, + options(noreturn, nomem, nostack), + ); +} "#, ) } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 3e41b42be44b1..83adf6548a890 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -3,8 +3,9 @@ use std::{mem, ops::Not}; use either::Either; use hir::{ - Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, - LayoutError, Name, Semantics, Trait, Type, TypeInfo, + db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, + HirDisplay, Layout, LayoutError, MethodViolationCode, Name, ObjectSafetyViolation, Semantics, + Trait, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -12,7 +13,7 @@ use ide_db::{ documentation::HasDocs, famous_defs::FamousDefs, generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES}, - syntax_helpers::insert_whitespace_into_node, + syntax_helpers::prettify_macro_expansion, RootDatabase, }; use itertools::Itertools; @@ -328,7 +329,7 @@ pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option (false, FEATURES), - "allow" | "deny" | "forbid" | "warn" => { + "allow" | "deny" | "expect" | "forbid" | "warn" => { let is_clippy = algo::non_trivia_sibling(token.clone().into(), Direction::Prev) .filter(|t| t.kind() == T![:]) .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev)) @@ -475,8 +476,9 @@ pub(super) fn definition( Err(_) => { let source = it.source(db)?; let mut body = source.value.body()?.syntax().clone(); - if source.file_id.is_macro() { - body = insert_whitespace_into_node::insert_ws_into(body); + if let Some(macro_file) = source.file_id.macro_file() { + let span_map = db.expansion_span_map(macro_file); + body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into()); } Some(body.to_string()) } @@ -485,8 +487,9 @@ pub(super) fn definition( Definition::Static(it) => { let source = it.source(db)?; let mut body = source.value.body()?.syntax().clone(); - if source.file_id.is_macro() { - body = insert_whitespace_into_node::insert_ws_into(body); + if let Some(macro_file) = source.file_id.macro_file() { + let span_map = db.expansion_span_map(macro_file); + body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into()); } Some(body.to_string()) } @@ -526,6 +529,14 @@ pub(super) fn definition( _ => None, }; + let object_safety_info = if let Definition::Trait(it) = def { + let mut object_safety_info = String::new(); + render_object_safety(db, &mut object_safety_info, it.object_safety(db)); + Some(object_safety_info) + } else { + None + }; + let mut desc = String::new(); if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits, edition) { desc.push_str(¬able_traits); @@ -535,6 +546,10 @@ pub(super) fn definition( desc.push_str(&layout_info); desc.push('\n'); } + if let Some(object_safety_info) = object_safety_info { + desc.push_str(&object_safety_info); + desc.push('\n'); + } desc.push_str(&label); if let Some(value) = value { desc.push_str(" = "); @@ -964,3 +979,62 @@ fn keyword_hints( _ => KeywordHint::new(token.text().to_owned(), format!("{}_keyword", token.text())), } } + +fn render_object_safety( + db: &RootDatabase, + buf: &mut String, + safety: Option, +) { + let Some(osv) = safety else { + buf.push_str("// Object Safety: Yes"); + return; + }; + buf.push_str("// Object Safety: No\n// - Reason: "); + match osv { + ObjectSafetyViolation::SizedSelf => { + buf.push_str("has a `Self: Sized` bound"); + } + ObjectSafetyViolation::SelfReferential => { + buf.push_str("has a bound that references `Self`"); + } + ObjectSafetyViolation::Method(func, mvc) => { + let name = hir::Function::from(func).name(db); + format_to!( + buf, + "has a method `{}` that is non dispatchable because of:\n// - ", + name.as_str() + ); + let desc = match mvc { + MethodViolationCode::StaticMethod => "missing a receiver", + MethodViolationCode::ReferencesSelfInput => "a parameter references `Self`", + MethodViolationCode::ReferencesSelfOutput => "the return type references `Self`", + MethodViolationCode::ReferencesImplTraitInTrait => { + "the return type contains `impl Trait`" + } + MethodViolationCode::AsyncFn => "being async", + MethodViolationCode::WhereClauseReferencesSelf => { + "a where clause references `Self`" + } + MethodViolationCode::Generic => "a non-lifetime generic parameter", + MethodViolationCode::UndispatchableReceiver => "a non-dispatchable receiver type", + }; + buf.push_str(desc); + } + ObjectSafetyViolation::AssocConst(const_) => { + let name = hir::Const::from(const_).name(db); + if let Some(name) = name { + format_to!(buf, "has an associated constant `{}`", name.as_str()); + } else { + buf.push_str("has an associated constant"); + } + } + ObjectSafetyViolation::GAT(alias) => { + let name = hir::TypeAlias::from(alias).name(db); + format_to!(buf, "has a generic associated type `{}`", name.as_str()); + } + ObjectSafetyViolation::HasNonSafeSuperTrait(super_trait) => { + let name = hir::Trait::from(super_trait).name(db); + format_to!(buf, "has a object unsafe supertrait `{}`", name.as_str()); + } + } +} diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 9585bdbe4c545..cca62d2181f46 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -182,13 +182,26 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { fn check_actions(ra_fixture: &str, expect: Expect) { let (analysis, file_id, position) = fixture::range_or_position(ra_fixture); - let hover = analysis + let mut hover = analysis .hover( &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, FileRange { file_id, range: position.range_or_empty() }, ) .unwrap() .unwrap(); + // stub out ranges into minicore as they can change every now and then + hover.info.actions.iter_mut().for_each(|action| match action { + super::HoverAction::GoToType(act) => act.iter_mut().for_each(|data| { + if data.nav.file_id == file_id { + return; + } + data.nav.full_range = TextRange::empty(span::TextSize::new(!0)); + if let Some(range) = &mut data.nav.focus_range { + *range = TextRange::empty(span::TextSize::new(!0)); + } + }), + _ => (), + }); expect.assert_debug_eq(&hover.info.actions) } @@ -200,10 +213,23 @@ fn check_hover_range(ra_fixture: &str, expect: Expect) { fn check_hover_range_actions(ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); - let hover = analysis + let mut hover = analysis .hover(&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, range) .unwrap() .unwrap(); + // stub out ranges into minicore as they can change every now and then + hover.info.actions.iter_mut().for_each(|action| match action { + super::HoverAction::GoToType(act) => act.iter_mut().for_each(|data| { + if data.nav.file_id == range.file_id { + return; + } + data.nav.full_range = TextRange::empty(span::TextSize::new(!0)); + if let Some(range) = &mut data.nav.focus_range { + *range = TextRange::empty(span::TextSize::new(!0)); + } + }), + _ => (), + }); expect.assert_debug_eq(&hover.info.actions); } @@ -483,8 +509,8 @@ fn main() { file_id: FileId( 1, ), - full_range: 632..867, - focus_range: 693..699, + full_range: 4294967295..4294967295, + focus_range: 4294967295..4294967295, name: "FnOnce", kind: Trait, container_name: "function", @@ -1470,6 +1496,24 @@ const foo$0: u32 = { ); } +#[test] +fn hover_unsigned_max_const() { + check( + r#"const $0A: u128 = -1_i128 as u128;"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + const A: u128 = 340282366920938463463374607431768211455 (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + ``` + "#]], + ); +} + #[test] fn hover_eval_complex_constants() { check( @@ -3104,26 +3148,26 @@ struct S{ f1: u32 } fn main() { let s$0t = S{ f1:0 }; } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..19, - focus_range: 7..8, - name: "S", - kind: Struct, - description: "struct S", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..19, + focus_range: 7..8, + name: "S", + kind: Struct, + description: "struct S", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3616,8 +3660,8 @@ pub mod future { file_id: FileId( 1, ), - full_range: 21..69, - focus_range: 60..66, + full_range: 4294967295..4294967295, + focus_range: 4294967295..4294967295, name: "Future", kind: Trait, container_name: "future", @@ -5442,7 +5486,7 @@ const FOO$0: Option<&i32> = Some(2).as_ref(); fn hover_const_eval_dyn_trait() { check( r#" -//- minicore: fmt, coerce_unsized, builtin_impls +//- minicore: fmt, coerce_unsized, builtin_impls, dispatch_from_dyn use core::fmt::Debug; const FOO$0: &dyn Debug = &2i32; @@ -6292,7 +6336,19 @@ fn hover_lint() { arithmetic operation overflows "#]], - ) + ); + check( + r#"#![expect(arithmetic_overflow$0)]"#, + expect![[r#" + *arithmetic_overflow* + ``` + arithmetic_overflow + ``` + ___ + + arithmetic operation overflows + "#]], + ); } #[test] @@ -6308,7 +6364,19 @@ fn hover_clippy_lint() { Checks for `foo = bar; bar = foo` sequences. "#]], - ) + ); + check( + r#"#![expect(clippy::almost_swapped$0)]"#, + expect![[r#" + *almost_swapped* + ``` + clippy::almost_swapped + ``` + ___ + + Checks for `foo = bar; bar = foo` sequences. + "#]], + ); } #[test] @@ -7107,6 +7175,7 @@ impl T$0 for () {} ``` ```rust + // Object Safety: Yes trait T {} ``` "#]], @@ -7126,6 +7195,7 @@ impl T$0 for () {} ``` ```rust + // Object Safety: Yes trait T {} ``` "#]], @@ -7149,6 +7219,9 @@ impl T$0 for () {} ``` ```rust + // Object Safety: No + // - Reason: has a method `func` that is non dispatchable because of: + // - missing a receiver trait T { /* … */ } ``` "#]], @@ -7172,6 +7245,9 @@ impl T$0 for () {} ``` ```rust + // Object Safety: No + // - Reason: has a method `func` that is non dispatchable because of: + // - missing a receiver trait T { fn func(); const FLAG: i32; @@ -7199,6 +7275,9 @@ impl T$0 for () {} ``` ```rust + // Object Safety: No + // - Reason: has a method `func` that is non dispatchable because of: + // - missing a receiver trait T { fn func(); const FLAG: i32; @@ -7226,6 +7305,9 @@ impl T$0 for () {} ``` ```rust + // Object Safety: No + // - Reason: has a method `func` that is non dispatchable because of: + // - missing a receiver trait T { fn func(); const FLAG: i32; @@ -8465,8 +8547,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 7800..8042, - focus_range: 7865..7871, + full_range: 4294967295..4294967295, + focus_range: 4294967295..4294967295, name: "Future", kind: Trait, container_name: "future", @@ -8479,8 +8561,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 8672..9171, - focus_range: 8749..8757, + full_range: 4294967295..4294967295, + focus_range: 4294967295..4294967295, name: "Iterator", kind: Trait, container_name: "iterator", @@ -8702,3 +8784,181 @@ fn foo() { "#]], ); } + +#[test] +fn test_hover_function_with_pat_param() { + check( + r#"fn test_1$0((start_range, end_range): (u32, u32), a: i32) {}"#, + expect![[r#" + *test_1* + + ```rust + test + ``` + + ```rust + fn test_1((start_range, end_range): (u32, u32), a: i32) + ``` + "#]], + ); + + // Test case with tuple pattern and mutable parameters + check( + r#"fn test_2$0((mut x, y): (i32, i32)) {}"#, + expect![[r#" + *test_2* + + ```rust + test + ``` + + ```rust + fn test_2((mut x, y): (i32, i32)) + ``` + "#]], + ); + + // Test case with a pattern in a reference type + check( + r#"fn test_3$0(&(a, b): &(i32, i32)) {}"#, + expect![[r#" + *test_3* + + ```rust + test + ``` + + ```rust + fn test_3(&(a, b): &(i32, i32)) + ``` + "#]], + ); + + // Test case with complex pattern (struct destructuring) + check( + r#"struct Point { x: i32, y: i32 } fn test_4$0(Point { x, y }: Point) {}"#, + expect![[r#" + *test_4* + + ```rust + test + ``` + + ```rust + fn test_4(Point { x, y }: Point) + ``` + "#]], + ); + + // Test case with a nested pattern + check( + r#"fn test_5$0(((a, b), c): ((i32, i32), i32)) {}"#, + expect![[r#" + *test_5* + + ```rust + test + ``` + + ```rust + fn test_5(((a, b), c): ((i32, i32), i32)) + ``` + "#]], + ); + + // Test case with an unused variable in the pattern + check( + r#"fn test_6$0((_, y): (i32, i64)) {}"#, + expect![[r#" + *test_6* + + ```rust + test + ``` + + ```rust + fn test_6((_, y): (i32, i64)) + ``` + "#]], + ); + + // Test case with a complex pattern involving both tuple and struct + check( + r#"struct Foo { a: i32, b: i32 } fn test_7$0((x, Foo { a, b }): (i32, Foo)) {}"#, + expect![[r#" + *test_7* + + ```rust + test + ``` + + ```rust + fn test_7((x, Foo { a, b }): (i32, Foo)) + ``` + "#]], + ); + + // Test case with Enum and Or pattern + check( + r#"enum MyEnum { A(i32), B(i32) } fn test_8$0((MyEnum::A(x) | MyEnum::B(x)): MyEnum) {}"#, + expect![[r#" + *test_8* + + ```rust + test + ``` + + ```rust + fn test_8((MyEnum::A(x) | MyEnum::B(x)): MyEnum) + ``` + "#]], + ); + + // Test case with a pattern as a function parameter + check( + r#"struct Foo { a: i32, b: i32 } fn test_9$0(Foo { a, b }: Foo) {}"#, + expect![[r#" + *test_9* + + ```rust + test + ``` + + ```rust + fn test_9(Foo { a, b }: Foo) + ``` + "#]], + ); + + // Test case with a pattern as a function parameter with a different name + check( + r#"struct Foo { a: i32, b: i32 } fn test_10$0(Foo { a, b: b1 }: Foo) {}"#, + expect![[r#" + *test_10* + + ```rust + test + ``` + + ```rust + fn test_10(Foo { a, b: b1 }: Foo) + ``` + "#]], + ); + + // Test case with a pattern as a function parameter with annotations + check( + r#"struct Foo { a: i32, b: i32 } fn test_10$0(Foo { a, b: mut b }: Foo) {}"#, + expect![[r#" + *test_10* + + ```rust + test + ``` + + ```rust + fn test_10(Foo { a, b: mut b }: Foo) + ``` + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 6a5d5e26a4f05..97e712356b54d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -14,8 +14,8 @@ use smallvec::{smallvec, SmallVec}; use span::{Edition, EditionedFileId}; use stdx::never; use syntax::{ - ast::{self, AstNode}, - match_ast, NodeOrToken, SyntaxNode, TextRange, TextSize, + ast::{self, AstNode, HasGenericParams}, + format_smolstr, match_ast, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent, }; use text_edit::TextEdit; @@ -29,13 +29,230 @@ mod closing_brace; mod closure_captures; mod closure_ret; mod discriminant; -mod fn_lifetime_fn; mod generic_param; mod implicit_drop; mod implicit_static; +mod lifetime; mod param_name; mod range_exclusive; +// Feature: Inlay Hints +// +// rust-analyzer shows additional information inline with the source code. +// Editors usually render this using read-only virtual text snippets interspersed with code. +// +// rust-analyzer by default shows hints for +// +// * types of local variables +// * names of function arguments +// * names of const generic parameters +// * types of chained expressions +// +// Optionally, one can enable additional hints for +// +// * return types of closure expressions +// * elided lifetimes +// * compiler inserted reborrows +// * names of generic type and lifetime parameters +// +// Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if +// any of the +// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99[following criteria] +// are met: +// +// * the parameter name is a suffix of the function's name +// * the argument is a qualified constructing or call expression where the qualifier is an ADT +// * exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix +// of argument with _ splitting it off +// * the parameter name starts with `ra_fixture` +// * the parameter name is a +// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200[well known name] +// in a unary function +// * the parameter name is a +// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201[single character] +// in a unary function +// +// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] +pub(crate) fn inlay_hints( + db: &RootDatabase, + file_id: FileId, + range_limit: Option, + config: &InlayHintsConfig, +) -> Vec { + let _p = tracing::info_span!("inlay_hints").entered(); + let sema = Semantics::new(db); + let file_id = sema + .attach_first_edition(file_id) + .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); + let file = sema.parse(file_id); + let file = file.syntax(); + + let mut acc = Vec::new(); + + let Some(scope) = sema.scope(file) else { + return acc; + }; + let famous_defs = FamousDefs(&sema, scope.krate()); + + let ctx = &mut InlayHintCtx::default(); + let mut hints = |event| { + if let Some(node) = handle_event(ctx, event) { + hints(&mut acc, ctx, &famous_defs, config, file_id, node); + } + }; + let mut preorder = file.preorder(); + while let Some(event) = preorder.next() { + // FIXME: This can miss some hints that require the parent of the range to calculate + if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none()) + { + preorder.skip_subtree(); + continue; + } + hints(event); + } + acc +} + +#[derive(Default)] +struct InlayHintCtx { + lifetime_stacks: Vec>, +} + +pub(crate) fn inlay_hints_resolve( + db: &RootDatabase, + file_id: FileId, + resolve_range: TextRange, + hash: u64, + config: &InlayHintsConfig, + hasher: impl Fn(&InlayHint) -> u64, +) -> Option { + let _p = tracing::info_span!("inlay_hints_resolve").entered(); + let sema = Semantics::new(db); + let file_id = sema + .attach_first_edition(file_id) + .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); + let file = sema.parse(file_id); + let file = file.syntax(); + + let scope = sema.scope(file)?; + let famous_defs = FamousDefs(&sema, scope.krate()); + let mut acc = Vec::new(); + + let ctx = &mut InlayHintCtx::default(); + let mut hints = |event| { + if let Some(node) = handle_event(ctx, event) { + hints(&mut acc, ctx, &famous_defs, config, file_id, node); + } + }; + + let mut preorder = file.preorder(); + while let Some(event) = preorder.next() { + // FIXME: This can miss some hints that require the parent of the range to calculate + if matches!(&event, WalkEvent::Enter(node) if resolve_range.intersect(node.text_range()).is_none()) + { + preorder.skip_subtree(); + continue; + } + hints(event); + } + acc.into_iter().find(|hint| hasher(hint) == hash) +} + +fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent) -> Option { + match node { + WalkEvent::Enter(node) => { + if let Some(node) = ast::AnyHasGenericParams::cast(node.clone()) { + let params = node + .generic_param_list() + .map(|it| { + it.lifetime_params() + .filter_map(|it| { + it.lifetime().map(|it| format_smolstr!("{}", &it.text()[1..])) + }) + .collect() + }) + .unwrap_or_default(); + ctx.lifetime_stacks.push(params); + } + Some(node) + } + WalkEvent::Leave(n) => { + if ast::AnyHasGenericParams::can_cast(n.kind()) { + ctx.lifetime_stacks.pop(); + } + None + } + } +} + +// FIXME: At some point when our hir infra is fleshed out enough we should flip this and traverse the +// HIR instead of the syntax tree. +fn hints( + hints: &mut Vec, + ctx: &mut InlayHintCtx, + famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, + config: &InlayHintsConfig, + file_id: EditionedFileId, + node: SyntaxNode, +) { + closing_brace::hints(hints, sema, config, file_id, node.clone()); + if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) { + generic_param::hints(hints, sema, config, any_has_generic_args); + } + + match_ast! { + match node { + ast::Expr(expr) => { + chaining::hints(hints, famous_defs, config, file_id, &expr); + adjustment::hints(hints, famous_defs, config, file_id, &expr); + match expr { + ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)), + ast::Expr::MethodCallExpr(it) => { + param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)) + } + ast::Expr::ClosureExpr(it) => { + closure_captures::hints(hints, famous_defs, config, file_id, it.clone()); + closure_ret::hints(hints, famous_defs, config, file_id, it) + }, + ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id, it), + _ => Some(()), + } + }, + ast::Pat(it) => { + binding_mode::hints(hints, famous_defs, config, file_id, &it); + match it { + ast::Pat::IdentPat(it) => { + bind_pat::hints(hints, famous_defs, config, file_id, &it); + } + ast::Pat::RangePat(it) => { + range_exclusive::hints(hints, famous_defs, config, file_id, it); + } + _ => {} + } + Some(()) + }, + ast::Item(it) => match it { + ast::Item::Fn(it) => { + implicit_drop::hints(hints, famous_defs, config, file_id, &it); + lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it) + }, + // static type elisions + ast::Item::Static(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)), + ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)), + ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it), + _ => None, + }, + // FIXME: trait object type elisions + ast::Type(ty) => match ty { + ast::Type::FnPtrType(ptr) => lifetime::fn_ptr_hints(hints, ctx, famous_defs, config, file_id, ptr), + ast::Type::PathType(path) => lifetime::fn_path_hints(hints, ctx, famous_defs, config, file_id, path), + _ => Some(()), + }, + _ => Some(()), + } + }; +} + #[derive(Clone, Debug, PartialEq, Eq)] pub struct InlayHintsConfig { pub render_colons: bool, @@ -162,6 +379,9 @@ pub struct InlayHint { pub label: InlayHintLabel, /// Text edit to apply when "accepting" this inlay hint. pub text_edit: Option, + /// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the + /// hint does not support resolving. + pub resolve_parent: Option, } impl std::hash::Hash for InlayHint { @@ -186,6 +406,7 @@ impl InlayHint { position: InlayHintPosition::After, pad_left: false, pad_right: false, + resolve_parent: None, } } @@ -198,11 +419,12 @@ impl InlayHint { position: InlayHintPosition::Before, pad_left: false, pad_right: false, + resolve_parent: None, } } - pub fn needs_resolve(&self) -> bool { - self.text_edit.is_some() || self.label.needs_resolve() + pub fn needs_resolve(&self) -> Option { + self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve()) } } @@ -355,11 +577,14 @@ impl HirWrite for InlayHintLabelBuilder<'_> { impl InlayHintLabelBuilder<'_> { fn make_new_part(&mut self) { - self.result.parts.push(InlayHintLabelPart { - text: take(&mut self.last_part), - linked_location: self.location.take(), - tooltip: None, - }); + let text = take(&mut self.last_part); + if !text.is_empty() { + self.result.parts.push(InlayHintLabelPart { + text, + linked_location: self.location.take(), + tooltip: None, + }); + } } fn finish(mut self) -> InlayHintLabel { @@ -434,190 +659,6 @@ fn label_of_ty( Some(r) } -fn ty_to_text_edit( - sema: &Semantics<'_, RootDatabase>, - node_for_hint: &SyntaxNode, - ty: &hir::Type, - offset_to_insert: TextSize, - prefix: String, -) -> Option { - let scope = sema.scope(node_for_hint)?; - // FIXME: Limit the length and bail out on excess somehow? - let rendered = ty.display_source_code(scope.db, scope.module().into(), false).ok()?; - - let mut builder = TextEdit::builder(); - builder.insert(offset_to_insert, prefix); - builder.insert(offset_to_insert, rendered); - Some(builder.finish()) -} - -// Feature: Inlay Hints -// -// rust-analyzer shows additional information inline with the source code. -// Editors usually render this using read-only virtual text snippets interspersed with code. -// -// rust-analyzer by default shows hints for -// -// * types of local variables -// * names of function arguments -// * names of const generic parameters -// * types of chained expressions -// -// Optionally, one can enable additional hints for -// -// * return types of closure expressions -// * elided lifetimes -// * compiler inserted reborrows -// * names of generic type and lifetime parameters -// -// Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if -// any of the -// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99[following criteria] -// are met: -// -// * the parameter name is a suffix of the function's name -// * the argument is a qualified constructing or call expression where the qualifier is an ADT -// * exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix -// of argument with _ splitting it off -// * the parameter name starts with `ra_fixture` -// * the parameter name is a -// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200[well known name] -// in a unary function -// * the parameter name is a -// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201[single character] -// in a unary function -// -// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] -pub(crate) fn inlay_hints( - db: &RootDatabase, - file_id: FileId, - range_limit: Option, - config: &InlayHintsConfig, -) -> Vec { - let _p = tracing::info_span!("inlay_hints").entered(); - let sema = Semantics::new(db); - let file_id = sema - .attach_first_edition(file_id) - .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); - let file = sema.parse(file_id); - let file = file.syntax(); - - let mut acc = Vec::new(); - - if let Some(scope) = sema.scope(file) { - let famous_defs = FamousDefs(&sema, scope.krate()); - - let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node); - match range_limit { - Some(range) => match file.covering_element(range) { - NodeOrToken::Token(_) => return acc, - NodeOrToken::Node(n) => n - .descendants() - .filter(|descendant| range.intersect(descendant.text_range()).is_some()) - .for_each(hints), - }, - None => file.descendants().for_each(hints), - }; - } - - acc -} - -pub(crate) fn inlay_hints_resolve( - db: &RootDatabase, - file_id: FileId, - position: TextSize, - hash: u64, - config: &InlayHintsConfig, - hasher: impl Fn(&InlayHint) -> u64, -) -> Option { - let _p = tracing::info_span!("inlay_hints_resolve").entered(); - let sema = Semantics::new(db); - let file_id = sema - .attach_first_edition(file_id) - .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); - let file = sema.parse(file_id); - let file = file.syntax(); - - let scope = sema.scope(file)?; - let famous_defs = FamousDefs(&sema, scope.krate()); - let mut acc = Vec::new(); - - let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node); - let token = file.token_at_offset(position).left_biased()?; - if let Some(parent_block) = token.parent_ancestors().find_map(ast::BlockExpr::cast) { - parent_block.syntax().descendants().for_each(hints) - } else if let Some(parent_item) = token.parent_ancestors().find_map(ast::Item::cast) { - parent_item.syntax().descendants().for_each(hints) - } else { - return None; - } - - acc.into_iter().find(|hint| hasher(hint) == hash) -} - -fn hints( - hints: &mut Vec, - famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, - file_id: EditionedFileId, - node: SyntaxNode, -) { - closing_brace::hints(hints, sema, config, file_id, node.clone()); - if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) { - generic_param::hints(hints, sema, config, any_has_generic_args); - } - match_ast! { - match node { - ast::Expr(expr) => { - chaining::hints(hints, famous_defs, config, file_id, &expr); - adjustment::hints(hints, sema, config, file_id, &expr); - match expr { - ast::Expr::CallExpr(it) => param_name::hints(hints, sema, config, ast::Expr::from(it)), - ast::Expr::MethodCallExpr(it) => { - param_name::hints(hints, sema, config, ast::Expr::from(it)) - } - ast::Expr::ClosureExpr(it) => { - closure_captures::hints(hints, famous_defs, config, file_id, it.clone()); - closure_ret::hints(hints, famous_defs, config, file_id, it) - }, - ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, config, it), - _ => None, - } - }, - ast::Pat(it) => { - binding_mode::hints(hints, sema, config, &it); - match it { - ast::Pat::IdentPat(it) => { - bind_pat::hints(hints, famous_defs, config, file_id, &it); - } - ast::Pat::RangePat(it) => { - range_exclusive::hints(hints, config, it); - } - _ => {} - } - Some(()) - }, - ast::Item(it) => match it { - // FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints - ast::Item::Impl(_) => None, - ast::Item::Fn(it) => { - implicit_drop::hints(hints, sema, config, file_id, &it); - fn_lifetime_fn::hints(hints, config, it) - }, - // static type elisions - ast::Item::Static(it) => implicit_static::hints(hints, config, Either::Left(it)), - ast::Item::Const(it) => implicit_static::hints(hints, config, Either::Right(it)), - ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it), - _ => None, - }, - // FIXME: fn-ptr type, dyn fn type, and trait object type elisions - ast::Type(_) => None, - _ => None, - } - }; -} - /// Checks if the type is an Iterator from std::iter and returns the iterator trait and the item type of the concrete iterator. fn hint_iterator( sema: &Semantics<'_, RootDatabase>, @@ -653,6 +694,23 @@ fn hint_iterator( None } +fn ty_to_text_edit( + sema: &Semantics<'_, RootDatabase>, + node_for_hint: &SyntaxNode, + ty: &hir::Type, + offset_to_insert: TextSize, + prefix: String, +) -> Option { + let scope = sema.scope(node_for_hint)?; + // FIXME: Limit the length and bail out on excess somehow? + let rendered = ty.display_source_code(scope.db, scope.module().into(), false).ok()?; + + let mut builder = TextEdit::builder(); + builder.insert(offset_to_insert, prefix); + builder.insert(offset_to_insert, rendered); + Some(builder.finish()) +} + fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool { matches!(closure.body(), Some(ast::Expr::BlockExpr(_))) } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 756198d0c0110..c37c469dff4e1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -6,9 +6,8 @@ use either::Either; use hir::{ Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety, - Semantics, }; -use ide_db::RootDatabase; +use ide_db::famous_defs::FamousDefs; use span::EditionedFileId; use stdx::never; @@ -24,7 +23,7 @@ use crate::{ pub(super) fn hints( acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, + FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, file_id: EditionedFileId, expr: &ast::Expr, @@ -156,6 +155,7 @@ pub(super) fn hints( kind: InlayKind::Adjustment, label, text_edit: None, + resolve_parent: Some(expr.syntax().text_range()), }); } if !postfix && needs_inner_parens { @@ -288,7 +288,7 @@ mod tests { check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized, fn, eq, index +//- minicore: coerce_unsized, fn, eq, index, dispatch_from_dyn fn main() { let _: u32 = loop {}; //^^^^^^^ @@ -313,6 +313,7 @@ fn main() { //^^^^^^^^^^^^ //^^^^^^^^^^^^( //^^^^^^^^^^^^) + //^^^^ let _: fn() = || {}; //^^^^^ let _: unsafe fn() = || {}; @@ -321,6 +322,8 @@ fn main() { //^^^^^^^^^^^^^^^^^^^^^ //^^^^^^^^^^^^^^^^^^^^^( //^^^^^^^^^^^^^^^^^^^^^) + //^^^^^^^^^&raw mut $ + //^^^^^^^^^* let _: &mut [_] = &mut [0; 0]; //^^^^^^^^^^^ //^^^^^^^^^^^&mut $ @@ -428,7 +431,7 @@ impl core::ops::IndexMut for Struct {} ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized, fn, eq, index +//- minicore: coerce_unsized, fn, eq, index, dispatch_from_dyn fn main() { Struct.consume(); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 82b0a6ffcf135..7a808fb4a929d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -110,6 +110,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: !render_colons, pad_right: false, + resolve_parent: Some(pat.syntax().text_range()), }); Some(()) diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs index f27390ee898bb..d1c0677863db7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs @@ -2,17 +2,19 @@ //! ```no_run //! let /* & */ (/* ref */ x,) = &(0,); //! ``` -use hir::{Mutability, Semantics}; -use ide_db::RootDatabase; +use hir::Mutability; +use ide_db::famous_defs::FamousDefs; +use span::EditionedFileId; use syntax::ast::{self, AstNode}; use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, + FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, + _file_id: EditionedFileId, pat: &ast::Pat, ) -> Option<()> { if !config.binding_mode_hints { @@ -57,6 +59,7 @@ pub(super) fn hints( position: InlayHintPosition::Before, pad_left: false, pad_right: mut_reference, + resolve_parent: Some(pat.syntax().text_range()), }); }); match pat { @@ -75,6 +78,7 @@ pub(super) fn hints( position: InlayHintPosition::Before, pad_left: false, pad_right: true, + resolve_parent: Some(pat.syntax().text_range()), }); } ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index 35f4d46e187c4..58d8f97a8ced7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -67,6 +67,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: true, pad_right: false, + resolve_parent: Some(expr.syntax().text_range()), }); } } @@ -139,7 +140,6 @@ fn main() { ( 147..172, [ - "", InlayHintLabelPart { text: "B", linked_location: Some( @@ -152,13 +152,11 @@ fn main() { ), tooltip: "", }, - "", ], ), ( 147..154, [ - "", InlayHintLabelPart { text: "A", linked_location: Some( @@ -171,7 +169,6 @@ fn main() { ), tooltip: "", }, - "", ], ), ] @@ -222,7 +219,6 @@ fn main() { ( 143..190, [ - "", InlayHintLabelPart { text: "C", linked_location: Some( @@ -235,13 +231,11 @@ fn main() { ), tooltip: "", }, - "", ], ), ( 143..179, [ - "", InlayHintLabelPart { text: "B", linked_location: Some( @@ -254,7 +248,6 @@ fn main() { ), tooltip: "", }, - "", ], ), ] @@ -289,7 +282,6 @@ fn main() { ( 143..190, [ - "", InlayHintLabelPart { text: "C", linked_location: Some( @@ -302,13 +294,11 @@ fn main() { ), tooltip: "", }, - "", ], ), ( 143..179, [ - "", InlayHintLabelPart { text: "B", linked_location: Some( @@ -321,7 +311,6 @@ fn main() { ), tooltip: "", }, - "", ], ), ] @@ -357,7 +346,6 @@ fn main() { ( 246..283, [ - "", InlayHintLabelPart { text: "B", linked_location: Some( @@ -389,7 +377,6 @@ fn main() { ( 246..265, [ - "", InlayHintLabelPart { text: "A", linked_location: Some( @@ -562,7 +549,6 @@ fn main() { ), tooltip: "", }, - "", ], ), ] @@ -597,7 +583,6 @@ fn main() { ( 124..130, [ - "", InlayHintLabelPart { text: "Struct", linked_location: Some( @@ -610,13 +595,11 @@ fn main() { ), tooltip: "", }, - "", ], ), ( 145..185, [ - "", InlayHintLabelPart { text: "Struct", linked_location: Some( @@ -629,13 +612,11 @@ fn main() { ), tooltip: "", }, - "", ], ), ( 145..168, [ - "", InlayHintLabelPart { text: "Struct", linked_location: Some( @@ -648,7 +629,6 @@ fn main() { ), tooltip: "", }, - "", ], ), ( diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index d78fd64bdf4dc..90b8be64a46d2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -18,12 +18,13 @@ pub(super) fn hints( sema: &Semantics<'_, RootDatabase>, config: &InlayHintsConfig, file_id: EditionedFileId, - mut node: SyntaxNode, + original_node: SyntaxNode, ) -> Option<()> { let min_lines = config.closing_brace_hints_min_lines?; let name = |it: ast::Name| it.syntax().text_range(); + let mut node = original_node.clone(); let mut closing_token; let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { closing_token = item_list.r_curly_token()?; @@ -77,7 +78,7 @@ pub(super) fn hints( } closing_token = block.r_curly_token()?; - let lifetime = label.lifetime().map_or_else(String::new, |it| it.to_string()); + let lifetime = label.lifetime()?.to_string(); (lifetime, Some(label.syntax().text_range())) } else if let Some(block) = ast::BlockExpr::cast(node.clone()) { @@ -145,6 +146,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: true, pad_right: false, + resolve_parent: Some(original_node.text_range()), }); None diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs index e87e10d8504ed..f399bd01d071a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs @@ -3,7 +3,7 @@ //! Tests live in [`bind_pat`][super::bind_pat] module. use ide_db::famous_defs::FamousDefs; use span::EditionedFileId; -use stdx::TupleExt; +use stdx::{never, TupleExt}; use syntax::ast::{self, AstNode}; use text_edit::{TextRange, TextSize}; @@ -40,6 +40,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: false, pad_right: false, + resolve_parent: Some(closure.syntax().text_range()), }); range } @@ -52,6 +53,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: false, pad_right: false, + resolve_parent: None, }); let last = captures.len() - 1; for (idx, capture) in captures.into_iter().enumerate() { @@ -61,17 +63,21 @@ pub(super) fn hints( // force cache the source file, otherwise sema lookup will potentially panic _ = sema.parse_or_expand(source.file()); + let label = format!( + "{}{}", + match capture.kind() { + hir::CaptureKind::SharedRef => "&", + hir::CaptureKind::UniqueSharedRef => "&unique ", + hir::CaptureKind::MutableRef => "&mut ", + hir::CaptureKind::Move => "", + }, + capture.display_place(sema.db) + ); + if never!(label.is_empty()) { + continue; + } let label = InlayHintLabel::simple( - format!( - "{}{}", - match capture.kind() { - hir::CaptureKind::SharedRef => "&", - hir::CaptureKind::UniqueSharedRef => "&unique ", - hir::CaptureKind::MutableRef => "&mut ", - hir::CaptureKind::Move => "", - }, - capture.display_place(sema.db) - ), + label, None, source.name().and_then(|name| { name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(Into::into) @@ -85,6 +91,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: false, pad_right: false, + resolve_parent: Some(closure.syntax().text_range()), }); if idx != last { @@ -96,6 +103,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: false, pad_right: false, + resolve_parent: None, }); } } @@ -107,6 +115,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: false, pad_right: true, + resolve_parent: None, }); Some(()) diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs index 325c2040691b1..6827540fa82c0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs @@ -72,6 +72,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: false, pad_right: false, + resolve_parent: Some(closure.syntax().text_range()), }); Some(()) } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index eca0ebe629f48..35b62878329fc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -35,7 +35,7 @@ pub(super) fn enum_hints( return None; } for variant in enum_.variant_list()?.variants() { - variant_hints(acc, sema, &variant); + variant_hints(acc, sema, &enum_, &variant); } Some(()) } @@ -43,6 +43,7 @@ pub(super) fn enum_hints( fn variant_hints( acc: &mut Vec, sema: &Semantics<'_, RootDatabase>, + enum_: &ast::Enum, variant: &ast::Variant, ) -> Option<()> { if variant.expr().is_some() { @@ -90,6 +91,7 @@ fn variant_hints( position: InlayHintPosition::After, pad_left: false, pad_right: false, + resolve_parent: Some(enum_.syntax().text_range()), }); Some(()) diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs deleted file mode 100644 index d3666754e2be9..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs +++ /dev/null @@ -1,332 +0,0 @@ -//! Implementation of "lifetime elision" inlay hints: -//! ```no_run -//! fn example/* <'0> */(a: &/* '0 */()) {} -//! ``` -use ide_db::{syntax_helpers::node_ext::walk_ty, FxHashMap}; -use itertools::Itertools; -use syntax::{ - ast::{self, AstNode, HasGenericParams, HasName}, - SyntaxToken, -}; -use syntax::{format_smolstr, SmolStr}; - -use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints}; - -pub(super) fn hints( - acc: &mut Vec, - config: &InlayHintsConfig, - func: ast::Fn, -) -> Option<()> { - if config.lifetime_elision_hints == LifetimeElisionHints::Never { - return None; - } - - let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint { - range: t.text_range(), - kind: InlayKind::Lifetime, - label: label.into(), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: true, - }; - - let param_list = func.param_list()?; - let generic_param_list = func.generic_param_list(); - let ret_type = func.ret_type(); - let self_param = param_list.self_param().filter(|it| it.amp_token().is_some()); - - let is_elided = |lt: &Option| match lt { - Some(lt) => matches!(lt.text().as_str(), "'_"), - None => true, - }; - - let potential_lt_refs = { - let mut acc: Vec<_> = vec![]; - if let Some(self_param) = &self_param { - let lifetime = self_param.lifetime(); - let is_elided = is_elided(&lifetime); - acc.push((None, self_param.amp_token(), lifetime, is_elided)); - } - param_list.params().filter_map(|it| Some((it.pat(), it.ty()?))).for_each(|(pat, ty)| { - // FIXME: check path types - walk_ty(&ty, &mut |ty| match ty { - ast::Type::RefType(r) => { - let lifetime = r.lifetime(); - let is_elided = is_elided(&lifetime); - acc.push(( - pat.as_ref().and_then(|it| match it { - ast::Pat::IdentPat(p) => p.name(), - _ => None, - }), - r.amp_token(), - lifetime, - is_elided, - )); - false - } - ast::Type::FnPtrType(_) => true, - ast::Type::PathType(t) => { - t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() - } - _ => false, - }) - }); - acc - }; - - // allocate names - let mut gen_idx_name = { - let mut gen = (0u8..).map(|idx| match idx { - idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]), - idx => format_smolstr!("'{idx}"), - }); - move || gen.next().unwrap_or_default() - }; - let mut allocated_lifetimes = vec![]; - - let mut used_names: FxHashMap = - match config.param_names_for_lifetime_elision_hints { - true => generic_param_list - .iter() - .flat_map(|gpl| gpl.lifetime_params()) - .filter_map(|param| param.lifetime()) - .filter_map(|lt| Some((SmolStr::from(lt.text().as_str().get(1..)?), 0))) - .collect(), - false => Default::default(), - }; - { - let mut potential_lt_refs = potential_lt_refs.iter().filter(|&&(.., is_elided)| is_elided); - if self_param.is_some() && potential_lt_refs.next().is_some() { - allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints { - // self can't be used as a lifetime, so no need to check for collisions - "'self".into() - } else { - gen_idx_name() - }); - } - potential_lt_refs.for_each(|(name, ..)| { - let name = match name { - Some(it) if config.param_names_for_lifetime_elision_hints => { - if let Some(c) = used_names.get_mut(it.text().as_str()) { - *c += 1; - SmolStr::from(format!("'{text}{c}", text = it.text().as_str())) - } else { - used_names.insert(it.text().as_str().into(), 0); - SmolStr::from_iter(["\'", it.text().as_str()]) - } - } - _ => gen_idx_name(), - }; - allocated_lifetimes.push(name); - }); - } - - // fetch output lifetime if elision rule applies - let output = match potential_lt_refs.as_slice() { - [(_, _, lifetime, _), ..] if self_param.is_some() || potential_lt_refs.len() == 1 => { - match lifetime { - Some(lt) => match lt.text().as_str() { - "'_" => allocated_lifetimes.first().cloned(), - "'static" => None, - name => Some(name.into()), - }, - None => allocated_lifetimes.first().cloned(), - } - } - [..] => None, - }; - - if allocated_lifetimes.is_empty() && output.is_none() { - return None; - } - - // apply hints - // apply output if required - let mut is_trivial = true; - if let (Some(output_lt), Some(r)) = (&output, ret_type) { - if let Some(ty) = r.ty() { - walk_ty(&ty, &mut |ty| match ty { - ast::Type::RefType(ty) if ty.lifetime().is_none() => { - if let Some(amp) = ty.amp_token() { - is_trivial = false; - acc.push(mk_lt_hint(amp, output_lt.to_string())); - } - false - } - ast::Type::FnPtrType(_) => true, - ast::Type::PathType(t) => { - t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() - } - _ => false, - }) - } - } - - if config.lifetime_elision_hints == LifetimeElisionHints::SkipTrivial && is_trivial { - return None; - } - - let mut a = allocated_lifetimes.iter(); - for (_, amp_token, _, is_elided) in potential_lt_refs { - if is_elided { - let t = amp_token?; - let lt = a.next()?; - acc.push(mk_lt_hint(t, lt.to_string())); - } - } - - // generate generic param list things - match (generic_param_list, allocated_lifetimes.as_slice()) { - (_, []) => (), - (Some(gpl), allocated_lifetimes) => { - let angle_tok = gpl.l_angle_token()?; - let is_empty = gpl.generic_params().next().is_none(); - acc.push(InlayHint { - range: angle_tok.text_range(), - kind: InlayKind::Lifetime, - label: format!( - "{}{}", - allocated_lifetimes.iter().format(", "), - if is_empty { "" } else { ", " } - ) - .into(), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: true, - }); - } - (None, allocated_lifetimes) => acc.push(InlayHint { - range: func.name()?.syntax().text_range(), - kind: InlayKind::GenericParamList, - label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: false, - }), - } - Some(()) -} - -#[cfg(test)] -mod tests { - use crate::{ - inlay_hints::tests::{check, check_with_config, TEST_CONFIG}, - InlayHintsConfig, LifetimeElisionHints, - }; - - #[test] - fn hints_lifetimes() { - check( - r#" -fn empty() {} - -fn no_gpl(a: &()) {} - //^^^^^^<'0> - // ^'0 -fn empty_gpl<>(a: &()) {} - // ^'0 ^'0 -fn partial<'b>(a: &(), b: &'b ()) {} -// ^'0, $ ^'0 -fn partial<'a>(a: &'a (), b: &()) {} -// ^'0, $ ^'0 - -fn single_ret(a: &()) -> &() {} -// ^^^^^^^^^^<'0> - // ^'0 ^'0 -fn full_mul(a: &(), b: &()) {} -// ^^^^^^^^<'0, '1> - // ^'0 ^'1 - -fn foo<'c>(a: &'c ()) -> &() {} - // ^'c - -fn nested_in(a: & &X< &()>) {} -// ^^^^^^^^^<'0, '1, '2> - //^'0 ^'1 ^'2 -fn nested_out(a: &()) -> & &X< &()>{} -// ^^^^^^^^^^<'0> - //^'0 ^'0 ^'0 ^'0 - -impl () { - fn foo(&self) {} - // ^^^<'0> - // ^'0 - fn foo(&self) -> &() {} - // ^^^<'0> - // ^'0 ^'0 - fn foo(&self, a: &()) -> &() {} - // ^^^<'0, '1> - // ^'0 ^'1 ^'0 -} -"#, - ); - } - - #[test] - fn hints_lifetimes_named() { - check_with_config( - InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG }, - r#" -fn nested_in<'named>(named: & &X< &()>) {} -// ^'named1, 'named2, 'named3, $ - //^'named1 ^'named2 ^'named3 -"#, - ); - } - - #[test] - fn hints_lifetimes_trivial_skip() { - check_with_config( - InlayHintsConfig { - lifetime_elision_hints: LifetimeElisionHints::SkipTrivial, - ..TEST_CONFIG - }, - r#" -fn no_gpl(a: &()) {} -fn empty_gpl<>(a: &()) {} -fn partial<'b>(a: &(), b: &'b ()) {} -fn partial<'a>(a: &'a (), b: &()) {} - -fn single_ret(a: &()) -> &() {} -// ^^^^^^^^^^<'0> - // ^'0 ^'0 -fn full_mul(a: &(), b: &()) {} - -fn foo<'c>(a: &'c ()) -> &() {} - // ^'c - -fn nested_in(a: & &X< &()>) {} -fn nested_out(a: &()) -> & &X< &()>{} -// ^^^^^^^^^^<'0> - //^'0 ^'0 ^'0 ^'0 - -impl () { - fn foo(&self) {} - fn foo(&self) -> &() {} - // ^^^<'0> - // ^'0 ^'0 - fn foo(&self, a: &()) -> &() {} - // ^^^<'0, '1> - // ^'0 ^'1 ^'0 -} -"#, - ); - } - - #[test] - fn hints_lifetimes_skip_fn_likes() { - check_with_config( - InlayHintsConfig { - lifetime_elision_hints: LifetimeElisionHints::Always, - ..TEST_CONFIG - }, - r#" -fn fn_ptr(a: fn(&()) -> &()) {} -fn fn_trait<>(a: impl Fn(&()) -> &()) {} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs index b60a80a8ac6b5..ed7ebc3b1e7ad 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs @@ -92,6 +92,7 @@ pub(crate) fn hints( kind: InlayKind::GenericParameter, label, text_edit: None, + resolve_parent: Some(node.syntax().text_range()), }) }); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index b4695a2b3519a..dd4b3efeecfe1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -8,9 +8,9 @@ use hir::{ db::{DefDatabase as _, HirDatabase as _}, mir::{MirSpan, TerminatorKind}, - ChalkTyInterner, DefWithBody, Semantics, + ChalkTyInterner, DefWithBody, }; -use ide_db::{FileRange, RootDatabase}; +use ide_db::{famous_defs::FamousDefs, FileRange}; use span::EditionedFileId; use syntax::{ @@ -22,16 +22,16 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla pub(super) fn hints( acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, + FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, file_id: EditionedFileId, - def: &ast::Fn, + node: &ast::Fn, ) -> Option<()> { if !config.implicit_drop_hints { return None; } - let def = sema.to_def(def)?; + let def = sema.to_def(node)?; let def: DefWithBody = def.into(); let (hir, source_map) = sema.db.body_with_source_map(def.into()); @@ -121,6 +121,7 @@ pub(super) fn hints( kind: InlayKind::Drop, label, text_edit: None, + resolve_parent: Some(node.syntax().text_range()), }) } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs index 42223ddf580e3..8d422478cbfcc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs @@ -3,6 +3,8 @@ //! static S: &/* 'static */str = ""; //! ``` use either::Either; +use ide_db::famous_defs::FamousDefs; +use span::EditionedFileId; use syntax::{ ast::{self, AstNode}, SyntaxKind, @@ -12,7 +14,9 @@ use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeE pub(super) fn hints( acc: &mut Vec, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, + _file_id: EditionedFileId, statik_or_const: Either, ) -> Option<()> { if config.lifetime_elision_hints != LifetimeElisionHints::Always { @@ -38,6 +42,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: false, pad_right: true, + resolve_parent: None, }); } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs new file mode 100644 index 0000000000000..2163c959b18ae --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs @@ -0,0 +1,566 @@ +//! Implementation of "lifetime elision" inlay hints: +//! ```no_run +//! fn example/* <'0> */(a: &/* '0 */()) {} +//! ``` +use std::iter; + +use ide_db::{famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap}; +use itertools::Itertools; +use span::EditionedFileId; +use syntax::{ + ast::{self, AstNode, HasGenericParams, HasName}, + SyntaxKind, SyntaxToken, +}; +use syntax::{format_smolstr, SmolStr}; + +use crate::{ + inlay_hints::InlayHintCtx, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, + LifetimeElisionHints, +}; + +pub(super) fn fn_hints( + acc: &mut Vec, + ctx: &mut InlayHintCtx, + fd: &FamousDefs<'_, '_>, + config: &InlayHintsConfig, + file_id: EditionedFileId, + func: ast::Fn, +) -> Option<()> { + if config.lifetime_elision_hints == LifetimeElisionHints::Never { + return None; + } + + let param_list = func.param_list()?; + let generic_param_list = func.generic_param_list(); + let ret_type = func.ret_type(); + let self_param = param_list.self_param().filter(|it| it.amp_token().is_some()); + let gpl_append_range = func.name()?.syntax().text_range(); + hints_( + acc, + ctx, + fd, + config, + file_id, + param_list, + generic_param_list, + ret_type, + self_param, + |acc, allocated_lifetimes| { + acc.push(InlayHint { + range: gpl_append_range, + kind: InlayKind::GenericParamList, + label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, + resolve_parent: None, + }) + }, + true, + ) +} + +pub(super) fn fn_ptr_hints( + acc: &mut Vec, + ctx: &mut InlayHintCtx, + fd: &FamousDefs<'_, '_>, + config: &InlayHintsConfig, + file_id: EditionedFileId, + func: ast::FnPtrType, +) -> Option<()> { + if config.lifetime_elision_hints == LifetimeElisionHints::Never { + return None; + } + + let parent_for_type = func + .syntax() + .ancestors() + .skip(1) + .take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE)) + .find_map(ast::ForType::cast); + + let param_list = func.param_list()?; + let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list()); + let ret_type = func.ret_type(); + let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token()); + hints_( + acc, + ctx, + fd, + config, + file_id, + param_list, + generic_param_list, + ret_type, + None, + |acc, allocated_lifetimes| { + let has_for = for_kw.is_some(); + let for_ = if has_for { "" } else { "for" }; + acc.push(InlayHint { + range: for_kw.map_or_else( + || func.syntax().first_token().unwrap().text_range(), + |it| it.text_range(), + ), + kind: InlayKind::GenericParamList, + label: format!("{for_}<{}>", allocated_lifetimes.iter().format(", "),).into(), + text_edit: None, + position: if has_for { + InlayHintPosition::After + } else { + InlayHintPosition::Before + }, + pad_left: false, + pad_right: true, + resolve_parent: None, + }); + }, + false, + ) +} + +pub(super) fn fn_path_hints( + acc: &mut Vec, + ctx: &mut InlayHintCtx, + fd: &FamousDefs<'_, '_>, + config: &InlayHintsConfig, + file_id: EditionedFileId, + func: ast::PathType, +) -> Option<()> { + if config.lifetime_elision_hints == LifetimeElisionHints::Never { + return None; + } + + // FIXME: Support general path types + let (param_list, ret_type) = func.path().as_ref().and_then(path_as_fn)?; + let parent_for_type = func + .syntax() + .ancestors() + .skip(1) + .take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE)) + .find_map(ast::ForType::cast); + + let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list()); + let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token()); + hints_( + acc, + ctx, + fd, + config, + file_id, + param_list, + generic_param_list, + ret_type, + None, + |acc, allocated_lifetimes| { + let has_for = for_kw.is_some(); + let for_ = if has_for { "" } else { "for" }; + acc.push(InlayHint { + range: for_kw.map_or_else( + || func.syntax().first_token().unwrap().text_range(), + |it| it.text_range(), + ), + kind: InlayKind::GenericParamList, + label: format!("{for_}<{}>", allocated_lifetimes.iter().format(", "),).into(), + text_edit: None, + position: if has_for { + InlayHintPosition::After + } else { + InlayHintPosition::Before + }, + pad_left: false, + pad_right: true, + resolve_parent: None, + }); + }, + false, + ) +} + +fn path_as_fn(path: &ast::Path) -> Option<(ast::ParamList, Option)> { + path.segment().and_then(|it| it.param_list().zip(Some(it.ret_type()))) +} + +fn hints_( + acc: &mut Vec, + ctx: &mut InlayHintCtx, + FamousDefs(_, _): &FamousDefs<'_, '_>, + config: &InlayHintsConfig, + _file_id: EditionedFileId, + param_list: ast::ParamList, + generic_param_list: Option, + ret_type: Option, + self_param: Option, + on_missing_gpl: impl FnOnce(&mut Vec, &[SmolStr]), + mut is_trivial: bool, +) -> Option<()> { + let is_elided = |lt: &Option| match lt { + Some(lt) => matches!(lt.text().as_str(), "'_"), + None => true, + }; + + let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint { + range: t.text_range(), + kind: InlayKind::Lifetime, + label: label.into(), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: true, + resolve_parent: None, + }; + + let potential_lt_refs = { + let mut acc: Vec<_> = vec![]; + if let Some(self_param) = &self_param { + let lifetime = self_param.lifetime(); + let is_elided = is_elided(&lifetime); + acc.push((None, self_param.amp_token(), lifetime, is_elided)); + } + param_list + .params() + .filter_map(|it| { + Some(( + it.pat().and_then(|it| match it { + ast::Pat::IdentPat(p) => p.name(), + _ => None, + }), + it.ty()?, + )) + }) + .for_each(|(name, ty)| { + // FIXME: check path types + walk_ty(&ty, &mut |ty| match ty { + ast::Type::RefType(r) => { + let lifetime = r.lifetime(); + let is_elided = is_elided(&lifetime); + acc.push((name.clone(), r.amp_token(), lifetime, is_elided)); + false + } + ast::Type::FnPtrType(_) => { + is_trivial = false; + true + } + ast::Type::PathType(t) => { + if t.path() + .and_then(|it| it.segment()) + .and_then(|it| it.param_list()) + .is_some() + { + is_trivial = false; + true + } else { + false + } + } + _ => false, + }) + }); + acc + }; + + let mut used_names: FxHashMap = + ctx.lifetime_stacks.iter().flat_map(|it| it.iter()).cloned().zip(iter::repeat(0)).collect(); + // allocate names + let mut gen_idx_name = { + let mut gen = (0u8..).map(|idx| match idx { + idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]), + idx => format_smolstr!("'{idx}"), + }); + let ctx = &*ctx; + move || { + gen.by_ref() + .find(|s| ctx.lifetime_stacks.iter().flat_map(|it| it.iter()).all(|n| n != s)) + .unwrap_or_default() + } + }; + let mut allocated_lifetimes = vec![]; + + { + let mut potential_lt_refs = potential_lt_refs.iter().filter(|&&(.., is_elided)| is_elided); + if self_param.is_some() && potential_lt_refs.next().is_some() { + allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints { + // self can't be used as a lifetime, so no need to check for collisions + "'self".into() + } else { + gen_idx_name() + }); + } + potential_lt_refs.for_each(|(name, ..)| { + let name = match name { + Some(it) if config.param_names_for_lifetime_elision_hints => { + if let Some(c) = used_names.get_mut(it.text().as_str()) { + *c += 1; + format_smolstr!("'{}{c}", it.text().as_str()) + } else { + used_names.insert(it.text().as_str().into(), 0); + format_smolstr!("'{}", it.text().as_str()) + } + } + _ => gen_idx_name(), + }; + allocated_lifetimes.push(name); + }); + } + + // fetch output lifetime if elision rule applies + let output = match potential_lt_refs.as_slice() { + [(_, _, lifetime, _), ..] if self_param.is_some() || potential_lt_refs.len() == 1 => { + match lifetime { + Some(lt) => match lt.text().as_str() { + "'_" => allocated_lifetimes.first().cloned(), + "'static" => None, + name => Some(name.into()), + }, + None => allocated_lifetimes.first().cloned(), + } + } + [..] => None, + }; + + if allocated_lifetimes.is_empty() && output.is_none() { + return None; + } + + // apply hints + // apply output if required + if let (Some(output_lt), Some(r)) = (&output, ret_type) { + if let Some(ty) = r.ty() { + walk_ty(&ty, &mut |ty| match ty { + ast::Type::RefType(ty) if ty.lifetime().is_none() => { + if let Some(amp) = ty.amp_token() { + is_trivial = false; + acc.push(mk_lt_hint(amp, output_lt.to_string())); + } + false + } + ast::Type::FnPtrType(_) => { + is_trivial = false; + true + } + ast::Type::PathType(t) => { + if t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() + { + is_trivial = false; + true + } else { + false + } + } + _ => false, + }) + } + } + + if config.lifetime_elision_hints == LifetimeElisionHints::SkipTrivial && is_trivial { + return None; + } + + let mut a = allocated_lifetimes.iter(); + for (_, amp_token, _, is_elided) in potential_lt_refs { + if is_elided { + let t = amp_token?; + let lt = a.next()?; + acc.push(mk_lt_hint(t, lt.to_string())); + } + } + + // generate generic param list things + match (generic_param_list, allocated_lifetimes.as_slice()) { + (_, []) => (), + (Some(gpl), allocated_lifetimes) => { + let angle_tok = gpl.l_angle_token()?; + let is_empty = gpl.generic_params().next().is_none(); + acc.push(InlayHint { + range: angle_tok.text_range(), + kind: InlayKind::Lifetime, + label: format!( + "{}{}", + allocated_lifetimes.iter().format(", "), + if is_empty { "" } else { ", " } + ) + .into(), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: true, + resolve_parent: None, + }); + } + (None, allocated_lifetimes) => on_missing_gpl(acc, allocated_lifetimes), + } + if let Some(stack) = ctx.lifetime_stacks.last_mut() { + stack.extend(allocated_lifetimes); + } + Some(()) +} + +#[cfg(test)] +mod tests { + use crate::{ + inlay_hints::tests::{check, check_with_config, TEST_CONFIG}, + InlayHintsConfig, LifetimeElisionHints, + }; + + #[test] + fn hints_lifetimes() { + check( + r#" +fn empty() {} + +fn no_gpl(a: &()) {} + //^^^^^^<'0> + // ^'0 +fn empty_gpl<>(a: &()) {} + // ^'0 ^'0 +fn partial<'b>(a: &(), b: &'b ()) {} +// ^'0, $ ^'0 +fn partial<'a>(a: &'a (), b: &()) {} +// ^'0, $ ^'0 + +fn single_ret(a: &()) -> &() {} +// ^^^^^^^^^^<'0> + // ^'0 ^'0 +fn full_mul(a: &(), b: &()) {} +// ^^^^^^^^<'0, '1> + // ^'0 ^'1 + +fn foo<'c>(a: &'c ()) -> &() {} + // ^'c + +fn nested_in(a: & &X< &()>) {} +// ^^^^^^^^^<'0, '1, '2> + //^'0 ^'1 ^'2 +fn nested_out(a: &()) -> & &X< &()>{} +// ^^^^^^^^^^<'0> + //^'0 ^'0 ^'0 ^'0 + +impl () { + fn foo(&self) {} + // ^^^<'0> + // ^'0 + fn foo(&self) -> &() {} + // ^^^<'0> + // ^'0 ^'0 + fn foo(&self, a: &()) -> &() {} + // ^^^<'0, '1> + // ^'0 ^'1 ^'0 +} +"#, + ); + } + + #[test] + fn hints_lifetimes_named() { + check_with_config( + InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG }, + r#" +fn nested_in<'named>(named: & &X< &()>) {} +// ^'named1, 'named2, 'named3, $ + //^'named1 ^'named2 ^'named3 +"#, + ); + } + + #[test] + fn hints_lifetimes_trivial_skip() { + check_with_config( + InlayHintsConfig { + lifetime_elision_hints: LifetimeElisionHints::SkipTrivial, + ..TEST_CONFIG + }, + r#" +fn no_gpl(a: &()) {} +fn empty_gpl<>(a: &()) {} +fn partial<'b>(a: &(), b: &'b ()) {} +fn partial<'a>(a: &'a (), b: &()) {} + +fn single_ret(a: &()) -> &() {} +// ^^^^^^^^^^<'0> + // ^'0 ^'0 +fn full_mul(a: &(), b: &()) {} + +fn foo<'c>(a: &'c ()) -> &() {} + // ^'c + +fn nested_in(a: & &X< &()>) {} +fn nested_out(a: &()) -> & &X< &()>{} +// ^^^^^^^^^^<'0> + //^'0 ^'0 ^'0 ^'0 + +impl () { + fn foo(&self) {} + fn foo(&self) -> &() {} + // ^^^<'0> + // ^'0 ^'0 + fn foo(&self, a: &()) -> &() {} + // ^^^<'0, '1> + // ^'0 ^'1 ^'0 +} +"#, + ); + } + + #[test] + fn no_collide() { + check_with_config( + InlayHintsConfig { + lifetime_elision_hints: LifetimeElisionHints::Always, + param_names_for_lifetime_elision_hints: true, + ..TEST_CONFIG + }, + r#" +impl<'foo> { + fn foo(foo: &()) {} + // ^^^ <'foo1> + // ^ 'foo1 +} +"#, + ); + } + + #[test] + fn hints_lifetimes_fn_ptr() { + check_with_config( + InlayHintsConfig { + lifetime_elision_hints: LifetimeElisionHints::Always, + ..TEST_CONFIG + }, + r#" +fn fn_ptr(a: fn(&()) -> &fn(&()) -> &()) {} + //^^ for<'0> + //^'0 + //^'0 + //^^ for<'1> + //^'1 + //^'1 +fn fn_ptr2(a: for<'a> fn(&()) -> &()) {} + //^'0, $ + //^'0 + //^'0 +fn fn_trait(a: &impl Fn(&()) -> &()) {} +// ^^^^^^^^<'0> + // ^'0 + // ^^ for<'1> + //^'1 + // ^'1 +"#, + ); + } + + #[test] + fn hints_in_non_gen_defs() { + check_with_config( + InlayHintsConfig { + lifetime_elision_hints: LifetimeElisionHints::Always, + ..TEST_CONFIG + }, + r#" +const _: fn(&()) -> &(); + //^^ for<'0> + //^'0 + //^'0 +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index 0f3142ef3f88b..28b0fa6dd4d1a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -7,8 +7,9 @@ use std::fmt::Display; use either::Either; use hir::{Callable, Semantics}; -use ide_db::RootDatabase; +use ide_db::{famous_defs::FamousDefs, RootDatabase}; +use span::EditionedFileId; use stdx::to_lower_snake_case; use syntax::{ ast::{self, AstNode, HasArgList, HasName, UnaryOp}, @@ -19,8 +20,9 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla pub(super) fn hints( acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, + FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, + _file_id: EditionedFileId, expr: ast::Expr, ) -> Option<()> { if !config.parameter_hints { @@ -60,6 +62,7 @@ pub(super) fn hints( position: InlayHintPosition::Before, pad_left: false, pad_right: true, + resolve_parent: Some(expr.syntax().text_range()), } }); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs index bfb92838857ca..de9b0e98a4beb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs @@ -3,13 +3,17 @@ //! for i in 0../* < */10 {} //! if let ../* < */100 = 50 {} //! ``` +use ide_db::famous_defs::FamousDefs; +use span::EditionedFileId; use syntax::{ast, SyntaxToken, T}; use crate::{InlayHint, InlayHintsConfig}; pub(super) fn hints( acc: &mut Vec, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, + _file_id: EditionedFileId, range: impl ast::RangeItem, ) -> Option<()> { (config.range_exclusive_hints && range.end().is_some()) @@ -30,6 +34,7 @@ fn inlay_hint(token: SyntaxToken) -> InlayHint { kind: crate::InlayKind::RangeExclusive, label: crate::InlayHintLabel::from("<"), text_edit: None, + resolve_parent: None, } } diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index ba0aaae19c9fd..547286c3f4d64 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -57,7 +57,7 @@ mod view_item_tree; mod view_memory_layout; mod view_mir; -use std::panic::UnwindSafe; +use std::{iter, panic::UnwindSafe}; use cfg::CfgOptions; use fetch_crates::CrateInfo; @@ -65,7 +65,8 @@ use hir::{sym, ChangeWithProcMacros}; use ide_db::{ base_db::{ salsa::{self, ParallelDatabase}, - CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, SourceRootDatabase, VfsPath, + CrateOrigin, CrateWorkspaceData, Env, FileLoader, FileSet, SourceDatabase, + SourceRootDatabase, VfsPath, }, prime_caches, symbol_index, FxHashMap, FxIndexSet, LineIndexDatabase, }; @@ -256,9 +257,16 @@ impl Analysis { CrateOrigin::Local { repo: None, name: None }, ); change.change_file(file_id, Some(text)); - change.set_crate_graph(crate_graph); - change.set_target_data_layouts(vec![Err("fixture has no layout".into())]); - change.set_toolchains(vec![None]); + let ws_data = crate_graph + .iter() + .zip(iter::repeat(Arc::new(CrateWorkspaceData { + proc_macro_cwd: None, + data_layout: Err("fixture has no layout".into()), + toolchain: None, + }))) + .collect(); + change.set_crate_graph(crate_graph, ws_data); + host.apply_change(change); (host.analysis(), file_id) } @@ -439,12 +447,12 @@ impl Analysis { &self, config: &InlayHintsConfig, file_id: FileId, - position: TextSize, + resolve_range: TextRange, hash: u64, hasher: impl Fn(&InlayHint) -> u64 + Send + UnwindSafe, ) -> Cancellable> { self.with_db(|db| { - inlay_hints::inlay_hints_resolve(db, file_id, position, hash, config, hasher) + inlay_hints::inlay_hints_resolve(db, file_id, resolve_range, hash, config, hasher) }) } diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 4be1b570981f6..14781b2129693 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -223,11 +223,12 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati Variable } } - Definition::Label(..) => Variable, // For lack of a better variant + Definition::Label(..) | Definition::InlineAsmOperand(_) => Variable, // For lack of a better variant Definition::DeriveHelper(..) => Attribute, Definition::BuiltinAttr(..) => Attribute, Definition::ToolModule(..) => Module, Definition::ExternCrateDecl(..) => Module, + Definition::InlineAsmRegOrRegClass(..) => Module, } } @@ -320,7 +321,9 @@ pub(crate) fn def_to_moniker( | Definition::DeriveHelper(_) | Definition::BuiltinLifetime(_) | Definition::BuiltinAttr(_) - | Definition::ToolModule(_) => return None, + | Definition::ToolModule(_) + | Definition::InlineAsmRegOrRegClass(_) + | Definition::InlineAsmOperand(_) => return None, Definition::Local(local) => { if !local.is_param(db) { diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 9ace9fda62b97..9bc7bf411f05e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -237,11 +237,13 @@ impl TryToNav for Definition { Definition::Trait(it) => it.try_to_nav(db), Definition::TraitAlias(it) => it.try_to_nav(db), Definition::TypeAlias(it) => it.try_to_nav(db), - Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?), + Definition::ExternCrateDecl(it) => it.try_to_nav(db), + Definition::InlineAsmOperand(it) => it.try_to_nav(db), Definition::BuiltinLifetime(_) | Definition::BuiltinType(_) | Definition::TupleField(_) | Definition::ToolModule(_) + | Definition::InlineAsmRegOrRegClass(_) | Definition::BuiltinAttr(_) => None, // FIXME: The focus range should be set to the helper declaration Definition::DeriveHelper(it) => it.derive().try_to_nav(db), @@ -693,6 +695,31 @@ impl TryToNav for hir::ConstParam { } } +impl TryToNav for hir::InlineAsmOperand { + fn try_to_nav(&self, db: &RootDatabase) -> Option> { + let InFile { file_id, value } = &self.source(db)?; + let file_id = *file_id; + Some(orig_range_with_focus(db, file_id, value.syntax(), value.name()).map( + |(FileRange { file_id, range: full_range }, focus_range)| { + let edition = self.parent(db).module(db).krate().edition(db); + NavigationTarget { + file_id, + name: self + .name(db) + .map_or_else(|| "_".into(), |it| it.display(db, edition).to_smolstr()), + alias: None, + kind: Some(SymbolKind::Local), + full_range, + focus_range, + container_name: None, + description: None, + docs: None, + } + }, + )) + } +} + #[derive(Debug)] pub struct UpmappingResult { /// The macro call site. diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 42b7472c645f3..e46cb5a781f4a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -2975,6 +2975,62 @@ fn test() { ); } + #[test] + fn asm_operand() { + check( + "bose", + r#" +//- minicore: asm +fn test() { + core::arch::asm!( + "push {base}", + base$0 = const 0 + ); +} +"#, + r#" +fn test() { + core::arch::asm!( + "push {bose}", + bose = const 0 + ); +} +"#, + ); + } + + #[test] + fn asm_operand2() { + check( + "bose", + r#" +//- minicore: asm +fn test() { + core::arch::asm!( + "push {base$0}", + "push {base}", + boo = const 0, + virtual_free = sym VIRTUAL_FREE, + base = const 0, + boo = const 0, + ); +} +"#, + r#" +fn test() { + core::arch::asm!( + "push {bose}", + "push {bose}", + boo = const 0, + virtual_free = sym VIRTUAL_FREE, + bose = const 0, + boo = const 0, + ); +} +"#, + ); + } + #[test] fn rename_path_inside_use_tree() { check( diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs index 518e71454798f..7234108701a34 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs @@ -19,21 +19,21 @@ pub(super) fn highlight_format_string( expanded_string: &ast::String, range: TextRange, ) { - if !is_format_string(expanded_string) { + if is_format_string(expanded_string) { + // FIXME: Replace this with the HIR info we have now. + lex_format_specifiers(string, &mut |piece_range, kind| { + if let Some(highlight) = highlight_format_specifier(kind) { + stack.add(HlRange { + range: piece_range + range.start(), + highlight: highlight.into(), + binding_hash: None, + }); + } + }); + return; } - // FIXME: Replace this with the HIR info we have now. - lex_format_specifiers(string, &mut |piece_range, kind| { - if let Some(highlight) = highlight_format_specifier(kind) { - stack.add(HlRange { - range: piece_range + range.start(), - highlight: highlight.into(), - binding_hash: None, - }); - } - }); - if let Some(parts) = sema.as_format_args_parts(string) { parts.into_iter().for_each(|(range, res)| { if let Some(res) = res { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index eeba9cf35c997..96375937a12e8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -534,6 +534,10 @@ pub(super) fn highlight_def( Definition::BuiltinAttr(_) => Highlight::new(HlTag::Symbol(SymbolKind::BuiltinAttr)), Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)), Definition::DeriveHelper(_) => Highlight::new(HlTag::Symbol(SymbolKind::DeriveHelper)), + Definition::InlineAsmRegOrRegClass(_) => { + Highlight::new(HlTag::Symbol(SymbolKind::InlineAsmRegOrRegClass)) + } + Definition::InlineAsmOperand(_) => Highlight::new(HlTag::Symbol(SymbolKind::Local)), }; let def_crate = def.krate(db); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index bc1ec530076ce..5583f1bc8df92 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -315,6 +315,8 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag { Definition::BuiltinAttr(_) => SymbolKind::BuiltinAttr, Definition::ToolModule(_) => SymbolKind::ToolModule, Definition::DeriveHelper(_) => SymbolKind::DeriveHelper, + Definition::InlineAsmRegOrRegClass(_) => SymbolKind::InlineAsmRegOrRegClass, + Definition::InlineAsmOperand(_) => SymbolKind::Local, }; HlTag::Symbol(symbol) } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs index e329023606a1b..3b5d1af0ac72a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs @@ -146,6 +146,7 @@ impl HlTag { SymbolKind::Field => "field", SymbolKind::Function => "function", SymbolKind::Impl => "self_type", + SymbolKind::InlineAsmRegOrRegClass => "reg", SymbolKind::Label => "label", SymbolKind::LifetimeParam => "lifetime", SymbolKind::Local => "variable", diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html new file mode 100644 index 0000000000000..15a6386aa3c88 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html @@ -0,0 +1,119 @@ + + +
fn main() {
+    unsafe {
+        let foo = 1;
+        let mut o = 0;
+        core::arch::asm!(
+            "%input = OpLoad _ {0}",
+            concat!("%result = ", "bar", " _ %input"),
+            "OpStore {1} %result",
+            in(reg) &foo,
+            in(reg) &mut o,
+        );
+
+        let thread_id: usize;
+        core::arch::asm!("
+            mov {0}, gs:[0x30]
+            mov {0}, [{0}+0x48]
+        ", out(reg) thread_id, options(pure, readonly, nostack));
+
+        static UNMAP_BASE: usize;
+        const MEM_RELEASE: usize;
+        static VirtualFree: usize;
+        const OffPtr: usize;
+        const OffFn: usize;
+        core::arch::asm!("
+            push {free_type}
+            push {free_size}
+            push {base}
+
+            mov eax, fs:[30h]
+            mov eax, [eax+8h]
+            add eax, {off_fn}
+            mov [eax-{off_fn}+{off_ptr}], eax
+
+            push eax
+
+            jmp {virtual_free}
+            ",
+            off_ptr = const OffPtr,
+            off_fn  = const OffFn,
+
+            free_size = const 0,
+            free_type = const MEM_RELEASE,
+
+            virtual_free = sym VirtualFree,
+
+            base = sym UNMAP_BASE,
+            options(noreturn),
+        );
+    }
+}
+// taken from https://github.com/rust-embedded/cortex-m/blob/47921b51f8b960344fcfa1255a50a0d19efcde6d/cortex-m/src/asm.rs#L254-L274
+#[inline]
+pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
+    // Ensure thumb mode is set.
+    let rv = (rv as u32) | 1;
+    let msp = msp as u32;
+    core::arch::asm!(
+        "mrs {tmp}, CONTROL",
+        "bics {tmp}, {spsel}",
+        "msr CONTROL, {tmp}",
+        "isb",
+        "msr MSP, {msp}",
+        "bx {rv}",
+        // `out(reg) _` is not permitted in a `noreturn` asm! call,
+        // so instead use `in(reg) 0` and don't restore it afterwards.
+        tmp = in(reg) 0,
+        spsel = in(reg) 2,
+        msp = in(reg) msp,
+        rv = in(reg) rv,
+        options(noreturn, nomem, nostack),
+    );
+}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html new file mode 100644 index 0000000000000..d07ba74db2499 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html @@ -0,0 +1,53 @@ + + +
fn main() {
+    template!(template);
+}
+
+#[proc_macros::issue_18089]
+fn template() {}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html new file mode 100644 index 0000000000000..a790b385786d8 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html @@ -0,0 +1,74 @@ + + +
extern crate self;
+
+use crate;
+use self;
+mod __ {
+    use super::*;
+}
+
+macro_rules! void {
+    ($($tt:tt)*) => {}
+}
+
+struct __ where Self:;
+fn __(_: Self) {}
+void!(Self);
+
+// edition dependent
+void!(try async await gen);
+// edition and context dependent
+void!(dyn);
+// builtin custom syntax
+void!(builtin offset_of format_args asm);
+// contextual
+void!(macro_rules, union, default, raw, auto, yeet);
+// reserved
+void!(abstract become box do final macro override priv typeof unsized virtual yield);
+void!('static 'self 'unsafe)
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html new file mode 100644 index 0000000000000..6dac066bfaa19 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html @@ -0,0 +1,74 @@ + + +
extern crate self;
+
+use crate;
+use self;
+mod __ {
+    use super::*;
+}
+
+macro_rules! void {
+    ($($tt:tt)*) => {}
+}
+
+struct __ where Self:;
+fn __(_: Self) {}
+void!(Self);
+
+// edition dependent
+void!(try async await gen);
+// edition and context dependent
+void!(dyn);
+// builtin custom syntax
+void!(builtin offset_of format_args asm);
+// contextual
+void!(macro_rules, union, default, raw, auto, yeet);
+// reserved
+void!(abstract become box do final macro override priv typeof unsized virtual yield);
+void!('static 'self 'unsafe)
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html new file mode 100644 index 0000000000000..6dac066bfaa19 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html @@ -0,0 +1,74 @@ + + +
extern crate self;
+
+use crate;
+use self;
+mod __ {
+    use super::*;
+}
+
+macro_rules! void {
+    ($($tt:tt)*) => {}
+}
+
+struct __ where Self:;
+fn __(_: Self) {}
+void!(Self);
+
+// edition dependent
+void!(try async await gen);
+// edition and context dependent
+void!(dyn);
+// builtin custom syntax
+void!(builtin offset_of format_args asm);
+// contextual
+void!(macro_rules, union, default, raw, auto, yeet);
+// reserved
+void!(abstract become box do final macro override priv typeof unsized virtual yield);
+void!('static 'self 'unsafe)
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html new file mode 100644 index 0000000000000..4ccc40799088a --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html @@ -0,0 +1,74 @@ + + +
extern crate self;
+
+use crate;
+use self;
+mod __ {
+    use super::*;
+}
+
+macro_rules! void {
+    ($($tt:tt)*) => {}
+}
+
+struct __ where Self:;
+fn __(_: Self) {}
+void!(Self);
+
+// edition dependent
+void!(try async await gen);
+// edition and context dependent
+void!(dyn);
+// builtin custom syntax
+void!(builtin offset_of format_args asm);
+// contextual
+void!(macro_rules, union, default, raw, auto, yeet);
+// reserved
+void!(abstract become box do final macro override priv typeof unsized virtual yield);
+void!('static 'self 'unsafe)
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index cb47fc68bc1b6..5594a36e7318f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -165,16 +165,16 @@ toho!("{}fmt", 0); let i: u64 = 3; let o: u64; - asm!( - "mov {0}, {1}", - "add {0}, 5", - out(reg) o, - in(reg) i, + core::arch::asm!( + "mov {0}, {1}", + "add {0}, 5", + out(reg) o, + in(reg) i, ); const CONSTANT: () = (): let mut m = (); format_args!(concat!("{}"), "{}"); - format_args!("{} {} {} {} {} {} {backslash} {CONSTANT} {m}", backslash, format_args!("{}", 0), foo, "bar", toho!(), backslash); - reuse_twice!("{backslash}"); + format_args!("{} {} {} {} {} {} {backslash} {CONSTANT} {m}", backslash, format_args!("{}", 0), foo, "bar", toho!(), backslash); + reuse_twice!("{backslash}"); } \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index 2070022d4183c..94cee4ef43b18 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -2,6 +2,7 @@ use std::time::Instant; use expect_test::{expect_file, ExpectFile}; use ide_db::SymbolKind; +use span::Edition; use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear}; use crate::{fixture, FileRange, HighlightConfig, HlTag, TextRange}; @@ -383,8 +384,10 @@ where #[test] fn test_keyword_highlighting() { - check_highlighting( - r#" + for edition in Edition::iter() { + check_highlighting( + &(format!("//- /main.rs crate:main edition:{edition}") + + r#" extern crate self; use crate; @@ -396,13 +399,27 @@ mod __ { macro_rules! void { ($($tt:tt)*) => {} } -void!(Self); + struct __ where Self:; fn __(_: Self) {} -"#, - expect_file!["./test_data/highlight_keywords.html"], - false, - ); +void!(Self); + +// edition dependent +void!(try async await gen); +// edition and context dependent +void!(dyn); +// builtin custom syntax +void!(builtin offset_of format_args asm); +// contextual +void!(macro_rules, union, default, raw, auto, yeet); +// reserved +void!(abstract become box do final macro override priv typeof unsized virtual yield); +void!('static 'self 'unsafe) +"#), + expect_file![format!("./test_data/highlight_keywords_{edition}.html")], + false, + ); + } } #[test] @@ -532,7 +549,7 @@ fn main() { toho!("{}fmt", 0); let i: u64 = 3; let o: u64; - asm!( + core::arch::asm!( "mov {0}, {1}", "add {0}, 5", out(reg) o, @@ -554,6 +571,7 @@ fn main() { fn test_unsafe_highlighting() { check_highlighting( r#" +//- minicore: sized macro_rules! id { ($($tt:tt)*) => { $($tt)* @@ -1257,3 +1275,103 @@ fn f<'de, T: Deserialize<'de>>() { ); let _ = analysis.highlight(HL_CONFIG, file_id).unwrap(); } + +#[test] +fn test_asm_highlighting() { + check_highlighting( + r#" +//- minicore: asm, concat +fn main() { + unsafe { + let foo = 1; + let mut o = 0; + core::arch::asm!( + "%input = OpLoad _ {0}", + concat!("%result = ", "bar", " _ %input"), + "OpStore {1} %result", + in(reg) &foo, + in(reg) &mut o, + ); + + let thread_id: usize; + core::arch::asm!(" + mov {0}, gs:[0x30] + mov {0}, [{0}+0x48] + ", out(reg) thread_id, options(pure, readonly, nostack)); + + static UNMAP_BASE: usize; + const MEM_RELEASE: usize; + static VirtualFree: usize; + const OffPtr: usize; + const OffFn: usize; + core::arch::asm!(" + push {free_type} + push {free_size} + push {base} + + mov eax, fs:[30h] + mov eax, [eax+8h] + add eax, {off_fn} + mov [eax-{off_fn}+{off_ptr}], eax + + push eax + + jmp {virtual_free} + ", + off_ptr = const OffPtr, + off_fn = const OffFn, + + free_size = const 0, + free_type = const MEM_RELEASE, + + virtual_free = sym VirtualFree, + + base = sym UNMAP_BASE, + options(noreturn), + ); + } +} +// taken from https://github.com/rust-embedded/cortex-m/blob/47921b51f8b960344fcfa1255a50a0d19efcde6d/cortex-m/src/asm.rs#L254-L274 +#[inline] +pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! { + // Ensure thumb mode is set. + let rv = (rv as u32) | 1; + let msp = msp as u32; + core::arch::asm!( + "mrs {tmp}, CONTROL", + "bics {tmp}, {spsel}", + "msr CONTROL, {tmp}", + "isb", + "msr MSP, {msp}", + "bx {rv}", + // `out(reg) _` is not permitted in a `noreturn` asm! call, + // so instead use `in(reg) 0` and don't restore it afterwards. + tmp = in(reg) 0, + spsel = in(reg) 2, + msp = in(reg) msp, + rv = in(reg) rv, + options(noreturn, nomem, nostack), + ); +} +"#, + expect_file!["./test_data/highlight_asm.html"], + false, + ); +} + +#[test] +fn issue_18089() { + check_highlighting( + r#" +//- proc_macros: issue_18089 +fn main() { + template!(template); +} + +#[proc_macros::issue_18089] +fn template() {} +"#, + expect_file!["./test_data/highlight_issue_18089.html"], + false, + ); +} diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 7eb8e4a5e2e52..a62cbc7fb29f3 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -15,7 +15,7 @@ macro_rules! define_symbols { (@WITH_NAME: $($alias:ident = $value:literal,)* @PLAIN: $($name:ident,)*) => { // Ideally we would be emitting `const` here, but then we no longer have stable addresses // which is what we are relying on for equality! In the future if consts can refer to - // statics we should swap these for `const`s and have the the string literal being pointed + // statics we should swap these for `const`s and have the string literal being pointed // to be statics to refer to such that their address is stable. $( pub static $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) }; @@ -94,6 +94,7 @@ define_symbols! { avr_dash_interrupt = "avr-interrupt", avr_dash_non_dash_blocking_dash_interrupt = "avr-non-blocking-interrupt", C_dash_cmse_dash_nonsecure_dash_call = "C-cmse-nonsecure-call", + C_dash_cmse_dash_nonsecure_dash_entry = "C-cmse-nonsecure-entry", C_dash_unwind = "C-unwind", cdecl_dash_unwind = "cdecl-unwind", fastcall_dash_unwind = "fastcall-unwind", @@ -242,6 +243,7 @@ define_symbols! { future_output, Future, ge, + generic_associated_type_extended, get_context, global_allocator, global_asm, diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index abad7e9f7d22a..baa45174236cf 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -10,7 +10,7 @@ use hir_expand::proc_macro::{ ProcMacros, }; use ide_db::{ - base_db::{CrateGraph, Env, SourceRoot, SourceRootId}, + base_db::{CrateGraph, CrateWorkspaceData, Env, SourceRoot, SourceRootId}, prime_caches, ChangeWithProcMacros, FxHashMap, RootDatabase, }; use itertools::Itertools; @@ -447,12 +447,16 @@ fn load_crate_graph( let source_roots = source_root_config.partition(vfs); analysis_change.set_roots(source_roots); - let num_crates = crate_graph.len(); - analysis_change.set_crate_graph(crate_graph); + let ws_data = crate_graph + .iter() + .zip(iter::repeat(From::from(CrateWorkspaceData { + proc_macro_cwd: None, + data_layout: target_layout.clone(), + toolchain: toolchain.clone(), + }))) + .collect(); + analysis_change.set_crate_graph(crate_graph, ws_data); analysis_change.set_proc_macros(proc_macros); - analysis_change - .set_target_data_layouts(iter::repeat(target_layout.clone()).take(num_crates).collect()); - analysis_change.set_toolchains(iter::repeat(toolchain.clone()).take(num_crates).collect()); db.apply_change(analysis_change); db @@ -489,8 +493,17 @@ impl ProcMacroExpander for Expander { def_site: Span, call_site: Span, mixed_site: Span, + current_dir: Option, ) -> Result, ProcMacroExpansionError> { - match self.0.expand(subtree, attrs, env.clone(), def_site, call_site, mixed_site) { + match self.0.expand( + subtree, + attrs, + env.clone(), + def_site, + call_site, + mixed_site, + current_dir, + ) { Ok(Ok(subtree)) => Ok(subtree), Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)), Err(err) => Err(ProcMacroExpansionError::System(err.to_string())), diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml index 756d42ef573fc..b37d57f28012e 100644 --- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml +++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml @@ -18,6 +18,7 @@ rustc-hash.workspace = true smallvec.workspace = true tracing.workspace = true arrayvec.workspace = true +ra-ap-rustc_lexer.workspace = true # local deps syntax.workspace = true @@ -30,6 +31,7 @@ syntax-bridge.workspace = true [dev-dependencies] test-utils.workspace = true +expect-test.workspace = true [features] in-rust-tree = ["parser/in-rust-tree", "tt/in-rust-tree", "syntax/in-rust-tree"] diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs index 43604eb232dc9..9e4ef14074080 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs @@ -146,7 +146,7 @@ fn invocation_fixtures( Some(MetaVarKind::Pat) => token_trees.push(make_ident("foo")), Some(MetaVarKind::Path) => token_trees.push(make_ident("foo")), Some(MetaVarKind::Literal) => token_trees.push(make_literal("1")), - Some(MetaVarKind::Expr) => token_trees.push(make_ident("foo")), + Some(MetaVarKind::Expr(_)) => token_trees.push(make_ident("foo")), Some(MetaVarKind::Lifetime) => { token_trees.push(make_punct('\'')); token_trees.push(make_ident("a")); @@ -216,7 +216,11 @@ fn invocation_fixtures( token_trees.push(subtree.into()); } - Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. } => {} + Op::Ignore { .. } + | Op::Index { .. } + | Op::Count { .. } + | Op::Len { .. } + | Op::Concat { .. } => {} }; // Simple linear congruential generator for deterministic result diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs index e69d7d14e253a..95641abc0f37b 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs @@ -69,7 +69,7 @@ use tt::{iter::TtIter, DelimSpan}; use crate::{ expander::{Binding, Bindings, ExpandResult, Fragment}, expect_fragment, - parser::{MetaVarKind, Op, RepeatKind, Separator}, + parser::{ExprKind, MetaVarKind, Op, RepeatKind, Separator}, ExpandError, ExpandErrorKind, MetaTemplate, ValueResult, }; @@ -584,7 +584,11 @@ fn match_loop_inner<'t>( error_items.push(item); } OpDelimited::Op( - Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. }, + Op::Ignore { .. } + | Op::Index { .. } + | Op::Count { .. } + | Op::Len { .. } + | Op::Concat { .. }, ) => { stdx::never!("metavariable expression in lhs found"); } @@ -769,23 +773,28 @@ fn match_meta_var( it.map(|it| tt::TokenTree::subtree_or_wrap(it, delim_span)).map(Fragment::Path) }); } - MetaVarKind::Expr => { - // `expr` should not match underscores, let expressions, or inline const. The latter - // two are for [backwards compatibility][0]. + MetaVarKind::Expr(expr) => { + // `expr_2021` should not match underscores, let expressions, or inline const. + // The latter two are for [backwards compatibility][0]. + // And `expr` also should not contain let expressions but may contain the other two + // since `Edition2024`. // HACK: Macro expansion should not be done using "rollback and try another alternative". // rustc [explicitly checks the next token][1]. // [0]: https://github.com/rust-lang/rust/issues/86730 // [1]: https://github.com/rust-lang/rust/blob/f0c4da499/compiler/rustc_expand/src/mbe/macro_parser.rs#L576 match input.peek_n(0) { - Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) - if it.sym == sym::underscore - || it.sym == sym::let_ - || it.sym == sym::const_ => - { - return ExpandResult::only_err(ExpandError::new( - it.span, - ExpandErrorKind::NoMatchingRule, - )) + Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) => { + let is_err = if it.is_raw.no() && matches!(expr, ExprKind::Expr2021) { + it.sym == sym::underscore || it.sym == sym::let_ || it.sym == sym::const_ + } else { + it.sym == sym::let_ + }; + if is_err { + return ExpandResult::only_err(ExpandError::new( + it.span, + ExpandErrorKind::NoMatchingRule, + )); + } } _ => {} }; @@ -874,7 +883,11 @@ fn collect_vars(collector_fun: &mut impl FnMut(Symbol), pattern: &MetaTemplate) Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens), Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens), Op::Literal(_) | Op::Ident(_) | Op::Punct(_) => {} - Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. } => { + Op::Ignore { .. } + | Op::Index { .. } + | Op::Count { .. } + | Op::Len { .. } + | Op::Concat { .. } => { stdx::never!("metavariable expression in lhs found"); } } diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index 286bd748cbe7e..1db2f35d26232 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -2,12 +2,12 @@ //! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` use intern::{sym, Symbol}; -use span::Span; +use span::{Edition, Span}; use tt::Delimiter; use crate::{ expander::{Binding, Bindings, Fragment}, - parser::{MetaVarKind, Op, RepeatKind, Separator}, + parser::{ConcatMetaVarExprElem, MetaVarKind, Op, RepeatKind, Separator}, ExpandError, ExpandErrorKind, ExpandResult, MetaTemplate, }; @@ -97,7 +97,7 @@ impl Bindings { | MetaVarKind::Ty | MetaVarKind::Pat | MetaVarKind::PatParam - | MetaVarKind::Expr + | MetaVarKind::Expr(_) | MetaVarKind::Ident => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym: sym::missing.clone(), @@ -312,6 +312,82 @@ fn expand_subtree( .into(), ); } + Op::Concat { elements, span: concat_span } => { + let mut concatenated = String::new(); + for element in elements { + match element { + ConcatMetaVarExprElem::Ident(ident) => { + concatenated.push_str(ident.sym.as_str()) + } + ConcatMetaVarExprElem::Literal(lit) => { + // FIXME: This isn't really correct wrt. escaping, but that's what rustc does and anyway + // escaping is used most of the times for characters that are invalid in identifiers. + concatenated.push_str(lit.symbol.as_str()) + } + ConcatMetaVarExprElem::Var(var) => { + // Handling of repetitions in `${concat}` isn't fleshed out in rustc, so we currently + // err at it. + // FIXME: Do what rustc does for repetitions. + let var_value = match ctx.bindings.get_fragment( + &var.sym, + var.span, + &mut ctx.nesting, + marker, + ) { + Ok(var) => var, + Err(e) => { + if err.is_none() { + err = Some(e); + }; + continue; + } + }; + let value = match &var_value { + Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => { + ident.sym.as_str() + } + Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) => { + lit.symbol.as_str() + } + _ => { + if err.is_none() { + err = Some(ExpandError::binding_error(var.span, "metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`")) + } + continue; + } + }; + concatenated.push_str(value); + } + } + } + + // `${concat}` span comes from the macro (at least for now). + // See https://github.com/rust-lang/rust/blob/b0af276da341/compiler/rustc_expand/src/mbe/transcribe.rs#L724-L726. + let mut result_span = *concat_span; + marker(&mut result_span); + + // FIXME: NFC normalize the result. + if !rustc_lexer::is_ident(&concatenated) { + if err.is_none() { + err = Some(ExpandError::binding_error( + *concat_span, + "`${concat(..)}` is not generating a valid identifier", + )); + } + // Insert a dummy identifier for better parsing. + concatenated.clear(); + concatenated.push_str("__ra_concat_dummy"); + } + + let needs_raw = + parser::SyntaxKind::from_keyword(&concatenated, Edition::LATEST).is_some(); + let is_raw = if needs_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No }; + arena.push(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { + is_raw, + span: result_span, + sym: Symbol::intern(&concatenated), + }))); + } } } // drain the elements added in this instance of expand_subtree diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index 88785537c7d20..ca10a2be27328 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -6,11 +6,20 @@ //! The tests for this functionality live in another crate: //! `hir_def::macro_expansion_tests::mbe`. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_lexer as rustc_lexer; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_lexer; + mod expander; mod parser; #[cfg(test)] mod benchmark; +#[cfg(test)] +mod tests; use span::{Edition, Span, SyntaxContextId}; use syntax_bridge::to_parser_input; diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs index 218c04640f12e..b55edf4a5e0cd 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs @@ -84,6 +84,10 @@ pub(crate) enum Op { // FIXME: `usize`` once we drop support for 1.76 depth: Option, }, + Concat { + elements: Box<[ConcatMetaVarExprElem]>, + span: Span, + }, Repeat { tokens: MetaTemplate, kind: RepeatKind, @@ -98,6 +102,18 @@ pub(crate) enum Op { Ident(tt::Ident), } +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) enum ConcatMetaVarExprElem { + /// There is NO preceding dollar sign, which means that this identifier should be interpreted + /// as a literal. + Ident(tt::Ident), + /// There is a preceding dollar sign, which means that this identifier should be expanded + /// and interpreted as a variable. + Var(tt::Ident), + /// For example, a number or a string. + Literal(tt::Literal), +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum RepeatKind { ZeroOrMore, @@ -105,6 +121,16 @@ pub(crate) enum RepeatKind { ZeroOrOne, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum ExprKind { + // Matches expressions using the post-edition 2024. Was written using + // `expr` in edition 2024 or later. + Expr, + // Matches expressions using the pre-edition 2024 rules. + // Either written using `expr` in edition 2021 or earlier or.was written using `expr_2021`. + Expr2021, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum MetaVarKind { Path, @@ -116,7 +142,7 @@ pub(crate) enum MetaVarKind { Meta, Item, Vis, - Expr, + Expr(ExprKind), Ident, Tt, Lifetime, @@ -277,17 +303,27 @@ fn eat_fragment_kind( let kind = match ident.sym.as_str() { "path" => MetaVarKind::Path, "ty" => MetaVarKind::Ty, - "pat" => match edition(ident.span.ctx) { - Edition::Edition2015 | Edition::Edition2018 => MetaVarKind::PatParam, - Edition::Edition2021 | Edition::Edition2024 => MetaVarKind::Pat, - }, + "pat" => { + if edition(ident.span.ctx).at_least_2021() { + MetaVarKind::Pat + } else { + MetaVarKind::PatParam + } + } "pat_param" => MetaVarKind::PatParam, "stmt" => MetaVarKind::Stmt, "block" => MetaVarKind::Block, "meta" => MetaVarKind::Meta, "item" => MetaVarKind::Item, "vis" => MetaVarKind::Vis, - "expr" => MetaVarKind::Expr, + "expr" => { + if edition(ident.span.ctx).at_least_2024() { + MetaVarKind::Expr(ExprKind::Expr) + } else { + MetaVarKind::Expr(ExprKind::Expr2021) + } + } + "expr_2021" => MetaVarKind::Expr(ExprKind::Expr2021), "ident" => MetaVarKind::Ident, "tt" => MetaVarKind::Tt, "lifetime" => MetaVarKind::Lifetime, @@ -364,6 +400,32 @@ fn parse_metavar_expr(src: &mut TtIter<'_, Span>) -> Result { let depth = if try_eat_comma(&mut args) { Some(parse_depth(&mut args)?) } else { None }; Op::Count { name: ident.sym.clone(), depth } } + s if sym::concat == *s => { + let mut elements = Vec::new(); + while let Some(next) = args.peek_n(0) { + let element = if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = next { + args.next().expect("already peeked"); + ConcatMetaVarExprElem::Literal(lit.clone()) + } else { + let is_var = try_eat_dollar(&mut args); + let ident = args.expect_ident_or_underscore()?.clone(); + + if is_var { + ConcatMetaVarExprElem::Var(ident) + } else { + ConcatMetaVarExprElem::Ident(ident) + } + }; + elements.push(element); + if args.peek_n(0).is_some() { + args.expect_comma()?; + } + } + if elements.len() < 2 { + return Err(()); + } + Op::Concat { elements: elements.into_boxed_slice(), span: func.span } + } _ => return Err(()), }; @@ -394,3 +456,11 @@ fn try_eat_comma(src: &mut TtIter<'_, Span>) -> bool { } false } + +fn try_eat_dollar(src: &mut TtIter<'_, Span>) -> bool { + if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. }))) = src.peek_n(0) { + let _ = src.next(); + return true; + } + false +} diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs new file mode 100644 index 0000000000000..e63ad113ffd23 --- /dev/null +++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs @@ -0,0 +1,332 @@ +//! Tests specific to declarative macros, aka macros by example. This covers +//! both stable `macro_rules!` macros as well as unstable `macro` macros. +// FIXME: Move more of the nameres independent tests from +// crates\hir-def\src\macro_expansion_tests\mod.rs to this +use expect_test::expect; +use span::{Edition, EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContextId}; +use stdx::format_to; +use tt::{TextRange, TextSize}; + +use crate::DeclarativeMacro; + +#[expect(deprecated)] +fn check_( + def_edition: Edition, + call_edition: Edition, + macro2: bool, + decl: &str, + arg: &str, + render_debug: bool, + expect: expect_test::Expect, + parse: parser::TopEntryPoint, +) { + let decl_tt = &syntax_bridge::parse_to_token_tree( + def_edition, + SpanAnchor { + file_id: EditionedFileId::new(FileId::from_raw(0), def_edition), + ast_id: ErasedFileAstId::from_raw(0), + }, + SyntaxContextId::ROOT, + decl, + ) + .unwrap(); + let mac = if macro2 { + DeclarativeMacro::parse_macro2(None, decl_tt, |_| def_edition) + } else { + DeclarativeMacro::parse_macro_rules(decl_tt, |_| def_edition) + }; + let call_anchor = SpanAnchor { + file_id: EditionedFileId::new(FileId::from_raw(1), call_edition), + ast_id: ErasedFileAstId::from_raw(0), + }; + let arg_tt = + syntax_bridge::parse_to_token_tree(call_edition, call_anchor, SyntaxContextId::ROOT, arg) + .unwrap(); + let res = mac.expand( + &arg_tt, + |_| (), + Span { + range: TextRange::up_to(TextSize::of(arg)), + anchor: call_anchor, + ctx: SyntaxContextId::ROOT, + }, + def_edition, + ); + let mut expect_res = String::new(); + if let Some(err) = res.err { + format_to!(expect_res, "{err:#?}\n\n",); + } + if render_debug { + format_to!(expect_res, "{:#?}\n\n", res.value.0); + } + let (node, _) = syntax_bridge::token_tree_to_syntax_node(&res.value.0, parse, def_edition); + format_to!( + expect_res, + "{}", + syntax_bridge::prettify_macro_expansion::prettify_macro_expansion( + node.syntax_node(), + &mut |it| it.clone() + ) + ); + expect.assert_eq(&expect_res); +} + +fn check( + def_edition: Edition, + call_edition: Edition, + decl: &str, + arg: &str, + expect: expect_test::Expect, +) { + check_( + def_edition, + call_edition, + false, + decl, + arg, + true, + expect, + parser::TopEntryPoint::SourceFile, + ); +} + +#[test] +fn token_mapping_smoke_test() { + check( + Edition::CURRENT, + Edition::CURRENT, + r#" +( struct $ident:ident ) => { + struct $ident { + map: ::std::collections::HashSet<()>, + } +}; +"#, + r#" +struct MyTraitMap2 +"#, + expect![[r#" + SUBTREE $$ 1:0@0..20#0 1:0@0..20#0 + IDENT struct 0:0@34..40#0 + IDENT MyTraitMap2 1:0@8..19#0 + SUBTREE {} 0:0@48..49#0 0:0@100..101#0 + IDENT map 0:0@58..61#0 + PUNCH : [alone] 0:0@61..62#0 + PUNCH : [joint] 0:0@63..64#0 + PUNCH : [alone] 0:0@64..65#0 + IDENT std 0:0@65..68#0 + PUNCH : [joint] 0:0@68..69#0 + PUNCH : [alone] 0:0@69..70#0 + IDENT collections 0:0@70..81#0 + PUNCH : [joint] 0:0@81..82#0 + PUNCH : [alone] 0:0@82..83#0 + IDENT HashSet 0:0@83..90#0 + PUNCH < [alone] 0:0@90..91#0 + SUBTREE () 0:0@91..92#0 0:0@92..93#0 + PUNCH > [joint] 0:0@93..94#0 + PUNCH , [alone] 0:0@94..95#0 + + struct MyTraitMap2 { + map: ::std::collections::HashSet<()>, + }"#]], + ); +} + +#[test] +fn token_mapping_floats() { + // Regression test for https://github.com/rust-lang/rust-analyzer/issues/12216 + // (and related issues) + check( + Edition::CURRENT, + Edition::CURRENT, + r#" +($($tt:tt)*) => { + $($tt)* +}; +"#, + r#" +fn main() { + 1; + 1.0; + ((1,),).0.0; + let x = 1; +} +"#, + expect![[r#" + SUBTREE $$ 1:0@0..63#0 1:0@0..63#0 + IDENT fn 1:0@1..3#0 + IDENT main 1:0@4..8#0 + SUBTREE () 1:0@8..9#0 1:0@9..10#0 + SUBTREE {} 1:0@11..12#0 1:0@61..62#0 + LITERAL Integer 1 1:0@17..18#0 + PUNCH ; [alone] 1:0@18..19#0 + LITERAL Float 1.0 1:0@24..27#0 + PUNCH ; [alone] 1:0@27..28#0 + SUBTREE () 1:0@33..34#0 1:0@39..40#0 + SUBTREE () 1:0@34..35#0 1:0@37..38#0 + LITERAL Integer 1 1:0@35..36#0 + PUNCH , [alone] 1:0@36..37#0 + PUNCH , [alone] 1:0@38..39#0 + PUNCH . [alone] 1:0@40..41#0 + LITERAL Float 0.0 1:0@41..44#0 + PUNCH ; [alone] 1:0@44..45#0 + IDENT let 1:0@50..53#0 + IDENT x 1:0@54..55#0 + PUNCH = [alone] 1:0@56..57#0 + LITERAL Integer 1 1:0@58..59#0 + PUNCH ; [alone] 1:0@59..60#0 + + fn main(){ + 1; + 1.0; + ((1,),).0.0; + let x = 1; + }"#]], + ); +} + +#[test] +fn expr_2021() { + check( + Edition::Edition2024, + Edition::Edition2024, + r#" +($($e:expr),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + _, + const { 1 }, +"#, + expect![[r#" + SUBTREE $$ 1:0@0..25#0 1:0@0..25#0 + IDENT _ 1:0@5..6#0 + PUNCH ; [joint] 0:0@36..37#0 + SUBTREE () 0:0@34..35#0 0:0@34..35#0 + IDENT const 1:0@12..17#0 + SUBTREE {} 1:0@18..19#0 1:0@22..23#0 + LITERAL Integer 1 1:0@20..21#0 + PUNCH ; [alone] 0:0@39..40#0 + + _; + (const { + 1 + });"#]], + ); + check( + Edition::Edition2021, + Edition::Edition2024, + r#" +($($e:expr),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + _, +"#, + expect![[r#" + ExpandError { + inner: ( + 1:0@5..6#0, + NoMatchingRule, + ), + } + + SUBTREE $$ 1:0@0..8#0 1:0@0..8#0 + PUNCH ; [alone] 0:0@39..40#0 + + ;"#]], + ); + check( + Edition::Edition2021, + Edition::Edition2024, + r#" +($($e:expr),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + const { 1 }, +"#, + expect![[r#" + ExpandError { + inner: ( + 1:0@5..10#0, + NoMatchingRule, + ), + } + + SUBTREE $$ 1:0@0..18#0 1:0@0..18#0 + PUNCH ; [alone] 0:0@39..40#0 + + ;"#]], + ); + check( + Edition::Edition2024, + Edition::Edition2024, + r#" +($($e:expr_2021),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + 4, + "literal", + funcall(), + future.await, + break 'foo bar, +"#, + expect![[r#" + SUBTREE $$ 1:0@0..76#0 1:0@0..76#0 + LITERAL Integer 4 1:0@5..6#0 + PUNCH ; [joint] 0:0@41..42#0 + LITERAL Str literal 1:0@12..21#0 + PUNCH ; [joint] 0:0@41..42#0 + SUBTREE () 0:0@39..40#0 0:0@39..40#0 + IDENT funcall 1:0@27..34#0 + SUBTREE () 1:0@34..35#0 1:0@35..36#0 + PUNCH ; [joint] 0:0@41..42#0 + SUBTREE () 0:0@39..40#0 0:0@39..40#0 + IDENT future 1:0@42..48#0 + PUNCH . [alone] 1:0@48..49#0 + IDENT await 1:0@49..54#0 + PUNCH ; [joint] 0:0@41..42#0 + SUBTREE () 0:0@39..40#0 0:0@39..40#0 + IDENT break 1:0@60..65#0 + PUNCH ' [joint] 1:0@66..67#0 + IDENT foo 1:0@67..70#0 + IDENT bar 1:0@71..74#0 + PUNCH ; [alone] 0:0@44..45#0 + + 4; + "literal"; + (funcall()); + (future.await); + (break 'foo bar);"#]], + ); + check( + Edition::Edition2024, + Edition::Edition2024, + r#" +($($e:expr_2021),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + _, +"#, + expect![[r#" + ExpandError { + inner: ( + 1:0@5..6#0, + NoMatchingRule, + ), + } + + SUBTREE $$ 1:0@0..8#0 1:0@0..8#0 + PUNCH ; [alone] 0:0@44..45#0 + + ;"#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/parser/src/edition.rs b/src/tools/rust-analyzer/crates/parser/src/edition.rs index be0a2c794e58c..702b16252d4e7 100644 --- a/src/tools/rust-analyzer/crates/parser/src/edition.rs +++ b/src/tools/rust-analyzer/crates/parser/src/edition.rs @@ -30,6 +30,12 @@ impl Edition { pub fn at_least_2018(self) -> bool { self >= Edition::Edition2018 } + + pub fn iter() -> impl Iterator { + [Edition::Edition2015, Edition::Edition2018, Edition::Edition2021, Edition::Edition2024] + .iter() + .copied() + } } #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index a678c1f3a70e6..2333e6c862be5 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -245,7 +245,7 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker { // test builtin_expr // fn foo() { -// builtin#asm(0); +// builtin#asm(""); // builtin#format_args("", 0, 1, a = 2 + 3, a + b); // builtin#offset_of(Foo, bar.baz.0); // } @@ -297,18 +297,188 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option { p.expect(T![')']); Some(m.complete(p, FORMAT_ARGS_EXPR)) } else if p.at_contextual_kw(T![asm]) { - p.bump_remap(T![asm]); - p.expect(T!['(']); - // FIXME: We just put expression here so highlighting kind of keeps working - expr(p); - p.expect(T![')']); - Some(m.complete(p, ASM_EXPR)) + parse_asm_expr(p, m) } else { m.abandon(p); None } } +// test asm_expr +// fn foo() { +// builtin#asm( +// "mov {tmp}, {x}", +// "shl {tmp}, 1", +// "shl {x}, 2", +// "add {x}, {tmp}", +// x = inout(reg) x, +// tmp = out(reg) _, +// ); +// } +fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { + p.bump_remap(T![asm]); + p.expect(T!['(']); + if expr(p).is_none() { + p.err_and_bump("expected asm template"); + } + let mut allow_templates = true; + while !p.at(EOF) && !p.at(T![')']) { + p.expect(T![,]); + // accept trailing commas + if p.at(T![')']) { + break; + } + + let op_n = p.start(); + // Parse clobber_abi + if p.eat_contextual_kw(T![clobber_abi]) { + parse_clobber_abi(p); + op_n.complete(p, ASM_CLOBBER_ABI); + allow_templates = false; + continue; + } + + // Parse options + if p.eat_contextual_kw(T![options]) { + parse_options(p); + op_n.complete(p, ASM_OPTIONS); + allow_templates = false; + continue; + } + + // Parse operand names + if p.at(T![ident]) && p.nth_at(1, T![=]) { + name(p); + p.bump(T![=]); + allow_templates = false; + true + } else { + false + }; + + let op = p.start(); + let dir_spec = p.start(); + if p.eat(T![in]) || p.eat_contextual_kw(T![out]) || p.eat_contextual_kw(T![lateout]) { + dir_spec.complete(p, ASM_DIR_SPEC); + parse_reg(p); + let op_expr = p.start(); + expr(p); + op_expr.complete(p, ASM_OPERAND_EXPR); + op.complete(p, ASM_REG_OPERAND); + op_n.complete(p, ASM_OPERAND_NAMED); + } else if p.eat_contextual_kw(T![inout]) || p.eat_contextual_kw(T![inlateout]) { + dir_spec.complete(p, ASM_DIR_SPEC); + parse_reg(p); + let op_expr = p.start(); + expr(p); + if p.eat(T![=>]) { + expr(p); + } + op_expr.complete(p, ASM_OPERAND_EXPR); + op.complete(p, ASM_REG_OPERAND); + op_n.complete(p, ASM_OPERAND_NAMED); + } else if p.eat_contextual_kw(T![label]) { + dir_spec.abandon(p); + block_expr(p); + op.complete(p, ASM_OPERAND_NAMED); + op_n.complete(p, ASM_LABEL); + } else if p.eat(T![const]) { + dir_spec.abandon(p); + expr(p); + op.complete(p, ASM_CONST); + op_n.complete(p, ASM_OPERAND_NAMED); + } else if p.eat_contextual_kw(T![sym]) { + dir_spec.abandon(p); + paths::type_path(p); + op.complete(p, ASM_SYM); + op_n.complete(p, ASM_OPERAND_NAMED); + } else if allow_templates { + dir_spec.abandon(p); + op.abandon(p); + op_n.abandon(p); + if expr(p).is_none() { + p.err_and_bump("expected asm template"); + } + continue; + } else { + dir_spec.abandon(p); + op.abandon(p); + op_n.abandon(p); + p.err_and_bump("expected asm operand"); + if p.at(T!['}']) { + break; + } + continue; + }; + allow_templates = false; + } + p.expect(T![')']); + Some(m.complete(p, ASM_EXPR)) +} + +fn parse_options(p: &mut Parser<'_>) { + p.expect(T!['(']); + + while !p.eat(T![')']) && !p.at(EOF) { + const OPTIONS: &[SyntaxKind] = &[ + T![pure], + T![nomem], + T![readonly], + T![preserves_flags], + T![noreturn], + T![nostack], + T![may_unwind], + T![att_syntax], + T![raw], + ]; + let m = p.start(); + if !OPTIONS.iter().any(|&syntax| p.eat_contextual_kw(syntax)) { + p.err_and_bump("expected asm option"); + m.abandon(p); + continue; + } + m.complete(p, ASM_OPTION); + + // Allow trailing commas + if p.eat(T![')']) { + break; + } + p.expect(T![,]); + } +} + +fn parse_clobber_abi(p: &mut Parser<'_>) { + p.expect(T!['(']); + + while !p.eat(T![')']) && !p.at(EOF) { + if !p.expect(T![string]) { + break; + } + + // Allow trailing commas + if p.eat(T![')']) { + break; + } + p.expect(T![,]); + } +} + +fn parse_reg(p: &mut Parser<'_>) { + p.expect(T!['(']); + if p.at(T![ident]) { + let m = p.start(); + name_ref(p); + m.complete(p, ASM_REG_SPEC); + } else if p.at(T![string]) { + let m = p.start(); + p.bump_any(); + m.complete(p, ASM_REG_SPEC); + } else { + p.err_and_bump("expected register name"); + } + p.expect(T![')']); +} + // test array_expr // fn foo() { // []; diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index ff924830ae017..dceac815e0b5c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -198,6 +198,11 @@ impl<'a> Converter<'a> { } LIFETIME_IDENT } + rustc_lexer::TokenKind::UnknownPrefixLifetime => { + err = "Unknown lifetime prefix"; + LIFETIME_IDENT + } + rustc_lexer::TokenKind::RawLifetime => LIFETIME_IDENT, rustc_lexer::TokenKind::Semi => T![;], rustc_lexer::TokenKind::Comma => T![,], diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs index 7d3eb5de25f9a..f6b3783d1cace 100644 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs @@ -131,6 +131,14 @@ impl<'t> Parser<'t> { true } + pub(crate) fn eat_contextual_kw(&mut self, kind: SyntaxKind) -> bool { + if !self.at_contextual_kw(kind) { + return false; + } + self.bump_remap(kind); + true + } + fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool { self.inp.kind(self.pos + n) == k1 && self.inp.kind(self.pos + n + 1) == k2 diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index 00f212487ae68..288a07ef44dc6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -111,16 +111,32 @@ pub enum SyntaxKind { YIELD_KW, ASM_KW, ASYNC_KW, + ATT_SYNTAX_KW, AUTO_KW, AWAIT_KW, BUILTIN_KW, + CLOBBER_ABI_KW, DEFAULT_KW, DYN_KW, FORMAT_ARGS_KW, GEN_KW, + INLATEOUT_KW, + INOUT_KW, + LABEL_KW, + LATEOUT_KW, MACRO_RULES_KW, + MAY_UNWIND_KW, + NOMEM_KW, + NORETURN_KW, + NOSTACK_KW, OFFSET_OF_KW, + OPTIONS_KW, + OUT_KW, + PRESERVES_FLAGS_KW, + PURE_KW, RAW_KW, + READONLY_KW, + SYM_KW, TRY_KW, UNION_KW, YEET_KW, @@ -146,7 +162,20 @@ pub enum SyntaxKind { ARG_LIST, ARRAY_EXPR, ARRAY_TYPE, + ASM_CLOBBER_ABI, + ASM_CONST, + ASM_DIR_SPEC, ASM_EXPR, + ASM_LABEL, + ASM_OPERAND, + ASM_OPERAND_EXPR, + ASM_OPERAND_NAMED, + ASM_OPTION, + ASM_OPTIONS, + ASM_PIECE, + ASM_REG_OPERAND, + ASM_REG_SPEC, + ASM_SYM, ASSOC_ITEM, ASSOC_ITEM_LIST, ASSOC_TYPE_ARG, @@ -364,14 +393,30 @@ impl SyntaxKind { pub fn is_contextual_keyword(self, edition: Edition) -> bool { match self { ASM_KW => true, + ATT_SYNTAX_KW => true, AUTO_KW => true, BUILTIN_KW => true, + CLOBBER_ABI_KW => true, DEFAULT_KW => true, DYN_KW if edition < Edition::Edition2018 => true, FORMAT_ARGS_KW => true, + INLATEOUT_KW => true, + INOUT_KW => true, + LABEL_KW => true, + LATEOUT_KW => true, MACRO_RULES_KW => true, + MAY_UNWIND_KW => true, + NOMEM_KW => true, + NORETURN_KW => true, + NOSTACK_KW => true, OFFSET_OF_KW => true, + OPTIONS_KW => true, + OUT_KW => true, + PRESERVES_FLAGS_KW => true, + PURE_KW => true, RAW_KW => true, + READONLY_KW => true, + SYM_KW => true, UNION_KW => true, YEET_KW => true, _ => false, @@ -435,14 +480,30 @@ impl SyntaxKind { GEN_KW if Edition::Edition2024 <= edition => true, TRY_KW if Edition::Edition2018 <= edition => true, ASM_KW => true, + ATT_SYNTAX_KW => true, AUTO_KW => true, BUILTIN_KW => true, + CLOBBER_ABI_KW => true, DEFAULT_KW => true, DYN_KW if edition < Edition::Edition2018 => true, FORMAT_ARGS_KW => true, + INLATEOUT_KW => true, + INOUT_KW => true, + LABEL_KW => true, + LATEOUT_KW => true, MACRO_RULES_KW => true, + MAY_UNWIND_KW => true, + NOMEM_KW => true, + NORETURN_KW => true, + NOSTACK_KW => true, OFFSET_OF_KW => true, + OPTIONS_KW => true, + OUT_KW => true, + PRESERVES_FLAGS_KW => true, + PURE_KW => true, RAW_KW => true, + READONLY_KW => true, + SYM_KW => true, UNION_KW => true, YEET_KW => true, _ => false, @@ -580,14 +641,30 @@ impl SyntaxKind { pub fn from_contextual_keyword(ident: &str, edition: Edition) -> Option { let kw = match ident { "asm" => ASM_KW, + "att_syntax" => ATT_SYNTAX_KW, "auto" => AUTO_KW, "builtin" => BUILTIN_KW, + "clobber_abi" => CLOBBER_ABI_KW, "default" => DEFAULT_KW, "dyn" if edition < Edition::Edition2018 => DYN_KW, "format_args" => FORMAT_ARGS_KW, + "inlateout" => INLATEOUT_KW, + "inout" => INOUT_KW, + "label" => LABEL_KW, + "lateout" => LATEOUT_KW, "macro_rules" => MACRO_RULES_KW, + "may_unwind" => MAY_UNWIND_KW, + "nomem" => NOMEM_KW, + "noreturn" => NORETURN_KW, + "nostack" => NOSTACK_KW, "offset_of" => OFFSET_OF_KW, + "options" => OPTIONS_KW, + "out" => OUT_KW, + "preserves_flags" => PRESERVES_FLAGS_KW, + "pure" => PURE_KW, "raw" => RAW_KW, + "readonly" => READONLY_KW, + "sym" => SYM_KW, "union" => UNION_KW, "yeet" => YEET_KW, _ => return None, @@ -630,4 +707,4 @@ impl SyntaxKind { } } #[macro_export] -macro_rules ! T { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } +macro_rules ! T { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 9ce5a2ae748fd..164d0f36f1be2 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -19,6 +19,8 @@ mod ok { #[test] fn as_precedence() { run_and_expect_no_errors("test_data/parser/inline/ok/as_precedence.rs"); } #[test] + fn asm_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_expr.rs"); } + #[test] fn assoc_const_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_const_eq.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_expr.rast new file mode 100644 index 0000000000000..f0213d0b5e36a --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_expr.rast @@ -0,0 +1,85 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + ASM_EXPR + BUILTIN_KW "builtin" + POUND "#" + ASM_KW "asm" + L_PAREN "(" + WHITESPACE "\n " + LITERAL + STRING "\"mov {tmp}, {x}\"" + COMMA "," + WHITESPACE "\n " + LITERAL + STRING "\"shl {tmp}, 1\"" + COMMA "," + WHITESPACE "\n " + LITERAL + STRING "\"shl {x}, 2\"" + COMMA "," + WHITESPACE "\n " + LITERAL + STRING "\"add {x}, {tmp}\"" + COMMA "," + WHITESPACE "\n " + ASM_OPERAND_NAMED + NAME + IDENT "x" + WHITESPACE " " + EQ "=" + WHITESPACE " " + ASM_REG_OPERAND + ASM_DIR_SPEC + INOUT_KW "inout" + L_PAREN "(" + ASM_REG_SPEC + NAME_REF + IDENT "reg" + R_PAREN ")" + WHITESPACE " " + ASM_OPERAND_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + COMMA "," + WHITESPACE "\n " + ASM_OPERAND_NAMED + NAME + IDENT "tmp" + WHITESPACE " " + EQ "=" + WHITESPACE " " + ASM_REG_OPERAND + ASM_DIR_SPEC + OUT_KW "out" + L_PAREN "(" + ASM_REG_SPEC + NAME_REF + IDENT "reg" + R_PAREN ")" + WHITESPACE " " + ASM_OPERAND_EXPR + UNDERSCORE_EXPR + UNDERSCORE "_" + COMMA "," + WHITESPACE "\n " + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_expr.rs new file mode 100644 index 0000000000000..0906cd3e7197d --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_expr.rs @@ -0,0 +1,10 @@ +fn foo() { + builtin#asm( + "mov {tmp}, {x}", + "shl {tmp}, 1", + "shl {x}, 2", + "add {x}, {tmp}", + x = inout(reg) x, + tmp = out(reg) _, + ); +} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rast index 361900b6d3e4b..19a84ac540961 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rast @@ -19,7 +19,7 @@ SOURCE_FILE ASM_KW "asm" L_PAREN "(" LITERAL - INT_NUMBER "0" + STRING "\"\"" R_PAREN ")" SEMICOLON ";" WHITESPACE "\n " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rs index 14431b0210ea8..920d0f794f242 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rs @@ -1,5 +1,5 @@ fn foo() { - builtin#asm(0); + builtin#asm(""); builtin#format_args("", 0, 1, a = 2 + 3, a + b); builtin#offset_of(Foo, bar.baz.0); } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index d50a3cdbf72da..011baad65f7d0 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -152,10 +152,9 @@ impl ProcMacro { def_site: Span, call_site: Span, mixed_site: Span, + current_dir: Option, ) -> Result, PanicMessage>, ServerError> { let version = self.process.version(); - let current_dir = - env.get("CARGO_RUSTC_CURRENT_DIR").or_else(|| env.get("CARGO_MANIFEST_DIR")); let mut span_data_table = SpanDataIndexMap::default(); let def_site = span_data_table.insert_full(def_site).0; diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index b8ac55ed0d5d1..91bdef4889ca1 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -52,6 +52,15 @@ pub use crate::{ }; pub use cargo_metadata::Metadata; +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ProjectJsonFromCommand { + /// The data describing this project, such as its dependencies. + pub data: ProjectJsonData, + /// The build system specific file that describes this project, + /// such as a `my-project/BUCK` file. + pub buildfile: AbsPathBuf, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ProjectManifest { ProjectJson(ManifestPath), diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs index a09c7a77abceb..6a88cf022dfb0 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs @@ -66,6 +66,8 @@ pub struct ProjectJson { /// e.g. `path/to/sysroot/lib/rustlib/src/rust` pub(crate) sysroot_src: Option, project_root: AbsPathBuf, + /// The path to the rust-project.json file. May be None if this + /// data was generated by the discoverConfig command. manifest: Option, crates: Vec, /// Configuration for CLI commands. diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index f540bb94c1963..30d1ddb636ef1 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -45,39 +45,6 @@ fn load_cargo_with_overrides( to_crate_graph(project_workspace) } -fn load_cargo_with_fake_sysroot( - file_map: &mut FxHashMap, - file: &str, -) -> (CrateGraph, ProcMacroPaths) { - let meta: Metadata = get_test_json_file(file); - let manifest_path = - ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap(); - let cargo_workspace = CargoWorkspace::new(meta, manifest_path); - let project_workspace = ProjectWorkspace { - kind: ProjectWorkspaceKind::Cargo { - cargo: cargo_workspace, - build_scripts: WorkspaceBuildScripts::default(), - rustc: Err(None), - cargo_config_extra_env: Default::default(), - error: None, - }, - sysroot: get_fake_sysroot(), - rustc_cfg: Vec::new(), - cfg_overrides: Default::default(), - toolchain: None, - target_layout: Err("target_data_layout not loaded".into()), - }; - project_workspace.to_crate_graph( - &mut { - |path| { - let len = file_map.len(); - Some(*file_map.entry(path.to_path_buf()).or_insert(FileId::from_raw(len as u32))) - } - }, - &Default::default(), - ) -} - fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) { let data = get_test_json_file(file); let project = rooted_project_json(data); @@ -253,34 +220,6 @@ fn rust_project_is_proc_macro_has_proc_macro_dep() { crate_data.dependencies.iter().find(|&dep| dep.name.deref() == "proc_macro").unwrap(); } -#[test] -fn crate_graph_dedup_identical() { - let (mut crate_graph, proc_macros) = - load_cargo_with_fake_sysroot(&mut Default::default(), "regex-metadata.json"); - crate_graph.sort_deps(); - - let (d_crate_graph, mut d_proc_macros) = (crate_graph.clone(), proc_macros.clone()); - - crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros, |(_, a), (_, b)| a == b); - assert!(crate_graph.iter().eq(d_crate_graph.iter())); - assert_eq!(proc_macros, d_proc_macros); -} - -#[test] -fn crate_graph_dedup() { - let path_map = &mut Default::default(); - let (mut crate_graph, _proc_macros) = - load_cargo_with_fake_sysroot(path_map, "ripgrep-metadata.json"); - assert_eq!(crate_graph.iter().count(), 81); - crate_graph.sort_deps(); - let (regex_crate_graph, mut regex_proc_macros) = - load_cargo_with_fake_sysroot(path_map, "regex-metadata.json"); - assert_eq!(regex_crate_graph.iter().count(), 60); - - crate_graph.extend(regex_crate_graph, &mut regex_proc_macros, |(_, a), (_, b)| a == b); - assert_eq!(crate_graph.iter().count(), 118); -} - #[test] // FIXME Remove the ignore #[ignore = "requires nightly until the sysroot ships a cargo workspace for library on stable"] diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 7834238acefdf..17b40a87cda90 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -109,7 +109,7 @@ impl fmt::Debug for ProjectWorkspace { ProjectWorkspaceKind::Cargo { cargo, error: _, - build_scripts: _, + build_scripts, rustc, cargo_config_extra_env, } => f @@ -126,6 +126,7 @@ impl fmt::Debug for ProjectWorkspace { .field("toolchain", &toolchain) .field("data_layout", &target_layout) .field("cargo_config_extra_env", &cargo_config_extra_env) + .field("build_scripts", &build_scripts.error().unwrap_or("ok")) .finish(), ProjectWorkspaceKind::Json(project) => { let mut debug_struct = f.debug_struct("Json"); @@ -1456,7 +1457,7 @@ fn sysroot_to_crate_graph( // Remove all crates except the ones we are interested in to keep the sysroot graph small. let removed_mapping = cg.remove_crates_except(&marker_set); - let mapping = crate_graph.extend(cg, &mut pm, |(_, a), (_, b)| a == b); + let mapping = crate_graph.extend(cg, &mut pm); // Map the id through the removal mapping first, then through the crate graph extension mapping. pub_deps.iter_mut().for_each(|(_, cid, _)| { @@ -1554,6 +1555,6 @@ fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) { if let Err(err) = graph.add_dep(from, dep) { - tracing::error!("{}", err) + tracing::warn!("{}", err) } } diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/regex-metadata.json b/src/tools/rust-analyzer/crates/project-model/test_data/regex-metadata.json deleted file mode 100644 index 371464dd20aa1..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/test_data/regex-metadata.json +++ /dev/null @@ -1,6420 +0,0 @@ -{ - "packages": [ - { - "name": "aho-corasick", - "version": "0.7.20", - "id": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Fast multiple substring searching.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.4.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "aho_corasick", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-0.7.20/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "default": [ - "std" - ], - "std": [ - "memchr/std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-0.7.20/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "text-processing" - ], - "keywords": [ - "string", - "search", - "text", - "aho", - "multi" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/aho-corasick", - "homepage": "https://github.com/BurntSushi/aho-corasick", - "documentation": null, - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "cc", - "version": "1.0.79", - "id": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "jobserver", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.16", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tempfile", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "cc", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bin" - ], - "crate_types": [ - "bin" - ], - "name": "gcc-shim", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/src/bin/gcc-shim.rs", - "edition": "2018", - "doc": true, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "cc_env", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cc_env.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "cflags", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cflags.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "cxxflags", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cxxflags.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "jobserver": [ - "dep:jobserver" - ], - "parallel": [ - "jobserver" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [ - "development-tools::build-utils" - ], - "keywords": [ - "build-dependencies" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang/cc-rs", - "homepage": "https://github.com/rust-lang/cc-rs", - "documentation": "https://docs.rs/cc", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "cfg-if", - "version": "0.1.10", - "id": "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "cfg-if", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-0.1.10/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "xcrate", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-0.1.10/tests/xcrate.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "rustc-dep-of-std": [ - "core", - "compiler_builtins" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-0.1.10/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/alexcrichton/cfg-if", - "homepage": "https://github.com/alexcrichton/cfg-if", - "documentation": "https://docs.rs/cfg-if", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "cfg-if", - "version": "1.0.0", - "id": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "cfg-if", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "xcrate", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/tests/xcrate.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "rustc-dep-of-std": [ - "core", - "compiler_builtins" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/alexcrichton/cfg-if", - "homepage": "https://github.com/alexcrichton/cfg-if", - "documentation": "https://docs.rs/cfg-if", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "docopt", - "version": "1.1.1", - "id": "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "Command line argument parsing.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.4.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "std", - "unicode" - ], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - }, - { - "name": "strsim", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.10", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "docopt", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bin" - ], - "crate_types": [ - "bin" - ], - "name": "docopt-wordlist", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/src/wordlist.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "cargo", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/cargo.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "cp", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/cp.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "decode", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/decode.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "hashmap", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/hashmap.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "optional_command", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/optional_command.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "verbose_multiple", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/verbose_multiple.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "command-line-interface" - ], - "keywords": [ - "docopt", - "argument", - "command", - "argv" - ], - "readme": "README.md", - "repository": "https://github.com/docopt/docopt.rs", - "homepage": "https://github.com/docopt/docopt.rs", - "documentation": "http://burntsushi.net/rustdoc/docopt/", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "getrandom", - "version": "0.2.9", - "id": "getrandom 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A small cross-platform library for retrieving random data from system source", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "cfg-if", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "js-sys", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", - "registry": null - }, - { - "name": "wasm-bindgen", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.62", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", - "registry": null - }, - { - "name": "wasm-bindgen-test", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.18", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", - "registry": null - }, - { - "name": "wasi", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.11", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": "cfg(target_os = \"wasi\")", - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.139", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": "cfg(unix)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "getrandom", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "custom", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/tests/custom.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "normal", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/tests/normal.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "rdrand", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/tests/rdrand.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "buffer", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/benches/buffer.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "custom": [], - "js": [ - "wasm-bindgen", - "js-sys" - ], - "js-sys": [ - "dep:js-sys" - ], - "rdrand": [], - "rustc-dep-of-std": [ - "compiler_builtins", - "core", - "libc/rustc-dep-of-std", - "wasi/rustc-dep-of-std" - ], - "std": [], - "test-in-browser": [], - "wasm-bindgen": [ - "dep:wasm-bindgen" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "std", - "custom" - ], - "rustdoc-args": [ - "--cfg", - "docsrs" - ] - } - } - }, - "publish": null, - "authors": [ - "The Rand Project Developers" - ], - "categories": [ - "os", - "no-std" - ], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-random/getrandom", - "homepage": null, - "documentation": "https://docs.rs/getrandom", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "lazy_static", - "version": "1.4.0", - "id": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "A macro for declaring lazily evaluated statics in Rust.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "spin", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.5.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "doc-comment", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "lazy_static", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "no_std", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/tests/no_std.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/tests/test.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "spin": [ - "dep:spin" - ], - "spin_no_std": [ - "spin" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Marvin Löbel " - ], - "categories": [ - "no-std", - "rust-patterns", - "memory-management" - ], - "keywords": [ - "macro", - "lazy", - "static" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang-nursery/lazy-static.rs", - "homepage": null, - "documentation": "https://docs.rs/lazy_static", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "libc", - "version": "0.2.142", - "id": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Raw FFI bindings to platform libraries like libc.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "libc", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "const_fn", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/tests/const_fn.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "align": [], - "const-extern-fn": [], - "default": [ - "std" - ], - "extra_traits": [], - "rustc-dep-of-std": [ - "align", - "rustc-std-workspace-core" - ], - "rustc-std-workspace-core": [ - "dep:rustc-std-workspace-core" - ], - "std": [], - "use_std": [ - "std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "const-extern-fn", - "extra_traits" - ] - } - } - }, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "external-ffi-bindings", - "no-std", - "os" - ], - "keywords": [ - "libc", - "ffi", - "bindings", - "operating", - "system" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang/libc", - "homepage": "https://github.com/rust-lang/libc", - "documentation": "https://docs.rs/libc/", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "memchr", - "version": "2.5.0", - "id": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "Safe interface to memchr.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.18", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quickcheck", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "memchr", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "default": [ - "std" - ], - "libc": [ - "dep:libc" - ], - "rustc-dep-of-std": [ - "core", - "compiler_builtins" - ], - "std": [], - "use_std": [ - "std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant ", - "bluss" - ], - "categories": [], - "keywords": [ - "memchr", - "char", - "scan", - "strchr", - "string" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/memchr", - "homepage": "https://github.com/BurntSushi/memchr", - "documentation": "https://docs.rs/memchr/", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "memmap", - "version": "0.6.2", - "id": "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Cross-platform Rust API for memory-mapped file IO", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "tempdir", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(unix)", - "registry": null - }, - { - "name": "winapi", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "basetsd", - "handleapi", - "memoryapi", - "minwindef", - "std", - "sysinfoapi" - ], - "target": "cfg(windows)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "memmap", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap-0.6.2/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "cat", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap-0.6.2/examples/cat.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap-0.6.2/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Dan Burkert " - ], - "categories": [], - "keywords": [ - "mmap", - "memory-map", - "io", - "file" - ], - "readme": "README.md", - "repository": "https://github.com/danburkert/memmap-rs", - "homepage": null, - "documentation": "https://docs.rs/memmap", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "pkg-config", - "version": "0.3.26", - "id": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A library to run the pkg-config system tool at build time in order to be used in\nCargo build scripts.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "pkg-config", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/tests/test.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [], - "keywords": [ - "build-dependencies" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang/pkg-config-rs", - "homepage": null, - "documentation": "https://docs.rs/pkg-config", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "proc-macro2", - "version": "1.0.56", - "id": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "unicode-ident", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quote", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "proc-macro2", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "comments", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/comments.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "features", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/features.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "marker", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/marker.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_fmt", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test_fmt.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_size", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test_size.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "proc-macro" - ], - "nightly": [], - "proc-macro": [], - "span-locations": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "rustc-args": [ - "--cfg", - "procmacro2_semver_exempt" - ], - "rustdoc-args": [ - "--cfg", - "procmacro2_semver_exempt", - "--cfg", - "doc_cfg" - ], - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - }, - "playground": { - "features": [ - "span-locations" - ] - } - }, - "publish": null, - "authors": [ - "David Tolnay ", - "Alex Crichton " - ], - "categories": [ - "development-tools::procedural-macro-helpers" - ], - "keywords": [ - "macros", - "syn" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/proc-macro2", - "homepage": null, - "documentation": "https://docs.rs/proc-macro2", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.31" - }, - { - "name": "quickcheck", - "version": "1.0.3", - "id": "quickcheck 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "Automatic property based testing with shrinking.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "env_logger", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "getrandom", - "small_rng" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "quickcheck", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "btree_set_range", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/btree_set_range.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "out_of_bounds", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/out_of_bounds.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "reverse", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/reverse.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "reverse_single", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/reverse_single.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "sieve", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/sieve.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "sort", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/sort.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "regex", - "use_logging" - ], - "env_logger": [ - "dep:env_logger" - ], - "log": [ - "dep:log" - ], - "regex": [ - "env_logger/regex" - ], - "use_logging": [ - "log", - "env_logger" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "development-tools::testing" - ], - "keywords": [ - "testing", - "quickcheck", - "property", - "shrinking", - "fuzz" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/quickcheck", - "homepage": "https://github.com/BurntSushi/quickcheck", - "documentation": "https://docs.rs/quickcheck", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "quote", - "version": "1.0.26", - "id": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Quasi-quoting macro quote!(...)", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "proc-macro2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.52", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "trybuild", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.66", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "diff" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "quote", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "compiletest", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/tests/compiletest.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/tests/test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "proc-macro" - ], - "proc-macro": [ - "proc-macro2/proc-macro" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - } - }, - "publish": null, - "authors": [ - "David Tolnay " - ], - "categories": [ - "development-tools::procedural-macro-helpers" - ], - "keywords": [ - "macros", - "syn" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/quote", - "homepage": null, - "documentation": "https://docs.rs/quote/", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.31" - }, - { - "name": "rand", - "version": "0.8.5", - "id": "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Random number generators and other randomness functionality.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.4", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "packed_simd_2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.7", - "kind": null, - "rename": "packed_simd", - "optional": true, - "uses_default_features": true, - "features": [ - "into_bits" - ], - "target": null, - "registry": null - }, - { - "name": "rand_chacha", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand_core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.6.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.103", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - }, - { - "name": "bincode", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.2.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand_pcg", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.22", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": "cfg(unix)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "rand", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand-0.8.5/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "alloc": [ - "rand_core/alloc" - ], - "default": [ - "std", - "std_rng" - ], - "getrandom": [ - "rand_core/getrandom" - ], - "libc": [ - "dep:libc" - ], - "log": [ - "dep:log" - ], - "min_const_gen": [], - "nightly": [], - "packed_simd": [ - "dep:packed_simd" - ], - "rand_chacha": [ - "dep:rand_chacha" - ], - "serde": [ - "dep:serde" - ], - "serde1": [ - "serde", - "rand_core/serde1" - ], - "simd_support": [ - "packed_simd" - ], - "small_rng": [], - "std": [ - "rand_core/std", - "rand_chacha/std", - "alloc", - "getrandom", - "libc" - ], - "std_rng": [ - "rand_chacha" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand-0.8.5/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true, - "rustdoc-args": [ - "--cfg", - "doc_cfg" - ] - } - }, - "playground": { - "features": [ - "small_rng", - "serde1" - ] - } - }, - "publish": null, - "authors": [ - "The Rand Project Developers", - "The Rust Project Developers" - ], - "categories": [ - "algorithms", - "no-std" - ], - "keywords": [ - "random", - "rng" - ], - "readme": "README.md", - "repository": "https://github.com/rust-random/rand", - "homepage": "https://rust-random.github.io/book", - "documentation": "https://docs.rs/rand", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "rand_core", - "version": "0.6.4", - "id": "rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Core random number generator traits and tools for implementation.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "getrandom", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "rand_core", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand_core-0.6.4/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "alloc": [], - "getrandom": [ - "dep:getrandom" - ], - "serde": [ - "dep:serde" - ], - "serde1": [ - "serde" - ], - "std": [ - "alloc", - "getrandom", - "getrandom/std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand_core-0.6.4/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true, - "rustdoc-args": [ - "--cfg", - "doc_cfg" - ] - } - }, - "playground": { - "all-features": true - } - }, - "publish": null, - "authors": [ - "The Rand Project Developers", - "The Rust Project Developers" - ], - "categories": [ - "algorithms", - "no-std" - ], - "keywords": [ - "random", - "rng" - ], - "readme": "README.md", - "repository": "https://github.com/rust-random/rand", - "homepage": "https://rust-random.github.io/book", - "documentation": "https://docs.rs/rand_core", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "regex", - "version": "1.7.1", - "id": "regex 1.7.1 (path+file:///$ROOT$regex)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "An implementation of regular expressions for Rust. This implementation uses\nfinite automata and guarantees linear time matching on all inputs.\n", - "source": null, - "dependencies": [ - { - "name": "aho-corasick", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.7.18", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.4.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex-syntax", - "source": null, - "req": "^0.6.27", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$regex/regex-syntax" - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quickcheck", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "getrandom", - "small_rng" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "regex", - "src_path": "$ROOT$regex/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": false, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-bytes", - "src_path": "$ROOT$regex/examples/shootout-regex-dna-bytes.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-cheat", - "src_path": "$ROOT$regex/examples/shootout-regex-dna-cheat.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-replace", - "src_path": "$ROOT$regex/examples/shootout-regex-dna-replace.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-single-cheat", - "src_path": "$ROOT$regex/examples/shootout-regex-dna-single-cheat.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-single", - "src_path": "$ROOT$regex/examples/shootout-regex-dna-single.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna", - "src_path": "$ROOT$regex/examples/shootout-regex-dna.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "default", - "src_path": "$ROOT$regex/tests/test_default.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "default-bytes", - "src_path": "$ROOT$regex/tests/test_default_bytes.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa", - "src_path": "$ROOT$regex/tests/test_nfa.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa-utf8bytes", - "src_path": "$ROOT$regex/tests/test_nfa_utf8bytes.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa-bytes", - "src_path": "$ROOT$regex/tests/test_nfa_bytes.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack", - "src_path": "$ROOT$regex/tests/test_backtrack.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack-utf8bytes", - "src_path": "$ROOT$regex/tests/test_backtrack_utf8bytes.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack-bytes", - "src_path": "$ROOT$regex/tests/test_backtrack_bytes.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "crates-regex", - "src_path": "$ROOT$regex/tests/test_crates_regex.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "aho-corasick": [ - "dep:aho-corasick" - ], - "default": [ - "std", - "perf", - "unicode", - "regex-syntax/default" - ], - "memchr": [ - "dep:memchr" - ], - "pattern": [], - "perf": [ - "perf-cache", - "perf-dfa", - "perf-inline", - "perf-literal" - ], - "perf-cache": [], - "perf-dfa": [], - "perf-inline": [], - "perf-literal": [ - "aho-corasick", - "memchr" - ], - "std": [], - "unicode": [ - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment", - "regex-syntax/unicode" - ], - "unicode-age": [ - "regex-syntax/unicode-age" - ], - "unicode-bool": [ - "regex-syntax/unicode-bool" - ], - "unicode-case": [ - "regex-syntax/unicode-case" - ], - "unicode-gencat": [ - "regex-syntax/unicode-gencat" - ], - "unicode-perl": [ - "regex-syntax/unicode-perl" - ], - "unicode-script": [ - "regex-syntax/unicode-script" - ], - "unicode-segment": [ - "regex-syntax/unicode-segment" - ], - "unstable": [ - "pattern" - ], - "use_std": [ - "std" - ] - }, - "manifest_path": "$ROOT$regex/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "text-processing" - ], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "regex", - "version": "1.8.1", - "id": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "An implementation of regular expressions for Rust. This implementation uses\nfinite automata and guarantees linear time matching on all inputs.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "aho-corasick", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.5.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex-syntax", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.7.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quickcheck", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "getrandom", - "small_rng" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "regex", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": false, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-cheat", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-cheat.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-replace", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-replace.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-single-cheat", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-single-cheat.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-single", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-single.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "default", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_default.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "default-bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_default_bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa-utf8bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa_utf8bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa-bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa_bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack-utf8bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack_utf8bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack-bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack_bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "crates-regex", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_crates_regex.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "aho-corasick": [ - "dep:aho-corasick" - ], - "default": [ - "std", - "perf", - "unicode", - "regex-syntax/default" - ], - "memchr": [ - "dep:memchr" - ], - "pattern": [], - "perf": [ - "perf-cache", - "perf-dfa", - "perf-inline", - "perf-literal" - ], - "perf-cache": [], - "perf-dfa": [], - "perf-inline": [], - "perf-literal": [ - "aho-corasick", - "memchr" - ], - "std": [], - "unicode": [ - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment", - "regex-syntax/unicode" - ], - "unicode-age": [ - "regex-syntax/unicode-age" - ], - "unicode-bool": [ - "regex-syntax/unicode-bool" - ], - "unicode-case": [ - "regex-syntax/unicode-case" - ], - "unicode-gencat": [ - "regex-syntax/unicode-gencat" - ], - "unicode-perl": [ - "regex-syntax/unicode-perl" - ], - "unicode-script": [ - "regex-syntax/unicode-script" - ], - "unicode-segment": [ - "regex-syntax/unicode-segment" - ], - "unstable": [ - "pattern" - ], - "use_std": [ - "std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "text-processing" - ], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.60.0" - }, - { - "name": "regex-benchmark", - "version": "0.1.0", - "id": "regex-benchmark 0.1.0 (path+file:///$ROOT$regex/bench)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Regex benchmarks for Rust's and other engines.", - "source": null, - "dependencies": [ - { - "name": "cfg-if", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "docopt", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libpcre-sys", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "memmap", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.6.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "onig", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^3", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": null, - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$regex" - }, - { - "name": "regex-syntax", - "source": null, - "req": "^0.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$regex/regex-syntax" - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - }, - { - "name": "cc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "build", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "pkg-config", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.9", - "kind": "build", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "bin" - ], - "crate_types": [ - "bin" - ], - "name": "regex-run-one", - "src_path": "$ROOT$regex/bench/src/main.rs", - "edition": "2018", - "doc": true, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$regex/bench/src/bench.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$regex/bench/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "libpcre-sys": [ - "dep:libpcre-sys" - ], - "onig": [ - "dep:onig" - ], - "re-onig": [ - "onig" - ], - "re-pcre1": [ - "libpcre-sys" - ], - "re-pcre2": [], - "re-re2": [], - "re-rust": [], - "re-rust-bytes": [], - "re-tcl": [] - }, - "manifest_path": "$ROOT$regex/bench/Cargo.toml", - "metadata": null, - "publish": [], - "authors": [ - "The Rust Project Developers" - ], - "categories": [], - "keywords": [], - "readme": null, - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "regex-debug", - "version": "0.1.0", - "id": "regex-debug 0.1.0 (path+file:///$ROOT$regex/regex-debug)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A tool useful for debugging regular expressions.", - "source": null, - "dependencies": [ - { - "name": "docopt", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": null, - "req": "^1.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$regex" - }, - { - "name": "regex-syntax", - "source": null, - "req": "^0.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$regex/regex-syntax" - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "bin" - ], - "crate_types": [ - "bin" - ], - "name": "regex-debug", - "src_path": "$ROOT$regex/regex-debug/src/main.rs", - "edition": "2018", - "doc": true, - "doctest": false, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$regex/regex-debug/Cargo.toml", - "metadata": null, - "publish": [], - "authors": [ - "The Rust Project Developers" - ], - "categories": [], - "keywords": [], - "readme": null, - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "regex-syntax", - "version": "0.6.28", - "id": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A regular expression parser.", - "source": null, - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "regex-syntax", - "src_path": "$ROOT$regex/regex-syntax/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$regex/regex-syntax/benches/bench.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "unicode" - ], - "unicode": [ - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ], - "unicode-age": [], - "unicode-bool": [], - "unicode-case": [], - "unicode-gencat": [], - "unicode-perl": [], - "unicode-script": [], - "unicode-segment": [] - }, - "manifest_path": "$ROOT$regex/regex-syntax/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex-syntax", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "regex-syntax", - "version": "0.7.1", - "id": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A regular expression parser.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "regex-syntax", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/benches/bench.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "std", - "unicode" - ], - "std": [], - "unicode": [ - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ], - "unicode-age": [], - "unicode-bool": [], - "unicode-case": [], - "unicode-gencat": [], - "unicode-perl": [], - "unicode-script": [], - "unicode-segment": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true, - "rustdoc-args": [ - "--cfg", - "docsrs" - ] - } - } - }, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex-syntax", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.60.0" - }, - { - "name": "rure", - "version": "0.2.2", - "id": "rure 0.2.2 (path+file:///$ROOT$regex/regex-capi)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A C API for Rust's regular expression library.\n", - "source": null, - "dependencies": [ - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": null, - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$regex" - } - ], - "targets": [ - { - "kind": [ - "staticlib", - "cdylib", - "rlib" - ], - "crate_types": [ - "staticlib", - "cdylib", - "rlib" - ], - "name": "rure", - "src_path": "$ROOT$regex/regex-capi/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$regex/regex-capi/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://github.com/rust-lang/regex/tree/master/regex-capi", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "serde", - "version": "1.0.160", - "id": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A generic serialization/deserialization framework", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "=1.0.160", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "serde", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "alloc": [], - "default": [ - "std" - ], - "derive": [ - "serde_derive" - ], - "rc": [], - "serde_derive": [ - "dep:serde_derive" - ], - "std": [], - "unstable": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "derive" - ], - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - }, - "playground": { - "features": [ - "derive", - "rc" - ] - } - }, - "publish": null, - "authors": [ - "Erick Tryzelaar ", - "David Tolnay " - ], - "categories": [ - "encoding", - "no-std" - ], - "keywords": [ - "serde", - "serialization", - "no_std" - ], - "readme": "crates-io.md", - "repository": "https://github.com/serde-rs/serde", - "homepage": "https://serde.rs", - "documentation": "https://docs.rs/serde", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": "1.19" - }, - { - "name": "serde_derive", - "version": "1.0.160", - "id": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "proc-macro2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quote", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "syn", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.0.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "proc-macro" - ], - "crate_types": [ - "proc-macro" - ], - "name": "serde_derive", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [], - "deserialize_in_place": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - } - }, - "publish": null, - "authors": [ - "Erick Tryzelaar ", - "David Tolnay " - ], - "categories": [ - "no-std" - ], - "keywords": [ - "serde", - "serialization", - "no_std", - "derive" - ], - "readme": "crates-io.md", - "repository": "https://github.com/serde-rs/serde", - "homepage": "https://serde.rs", - "documentation": "https://serde.rs/derive.html", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": "1.56" - }, - { - "name": "strsim", - "version": "0.10.0", - "id": "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT", - "license_file": null, - "description": "Implementations of string similarity metrics. Includes Hamming, Levenshtein,\nOSA, Damerau-Levenshtein, Jaro, Jaro-Winkler, and Sørensen-Dice.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "strsim", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "lib", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/tests/lib.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "benches", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/benches/benches.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Danny Guo " - ], - "categories": [], - "keywords": [ - "string", - "similarity", - "Hamming", - "Levenshtein", - "Jaro" - ], - "readme": "README.md", - "repository": "https://github.com/dguo/strsim-rs", - "homepage": "https://github.com/dguo/strsim-rs", - "documentation": "https://docs.rs/strsim/", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "syn", - "version": "2.0.15", - "id": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Parser for Rust source code", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "proc-macro2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.55", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quote", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.25", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "unicode-ident", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "anyhow", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "automod", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "flate2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "insta", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rayon", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "ref-cast", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "reqwest", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.11", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "blocking" - ], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "syn-test-suite", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tar", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.16", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "termcolor", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "walkdir", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.3.2", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "syn", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "regression", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/regression.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_asyncness", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_asyncness.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_attribute", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_attribute.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_derive_input", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_derive_input.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_expr", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_expr.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_generics", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_generics.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_grouping", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_grouping.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_ident", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_ident.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_item", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_item.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_iterators", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_iterators.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_lit", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_lit.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_meta", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_meta.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_parse_buffer", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_parse_buffer.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_parse_stream", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_parse_stream.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_pat", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_pat.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_path", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_path.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_precedence", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_precedence.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_receiver", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_receiver.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_round_trip", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_round_trip.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_shebang", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_shebang.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_should_parse", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_should_parse.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_size", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_size.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_stmt", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_stmt.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_token_trees", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_token_trees.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_ty", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_ty.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_visibility", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_visibility.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "zzz_stable", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/zzz_stable.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "rust", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/benches/rust.rs", - "edition": "2021", - "required-features": [ - "full", - "parsing" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "file", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/benches/file.rs", - "edition": "2021", - "required-features": [ - "full", - "parsing" - ], - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "clone-impls": [], - "default": [ - "derive", - "parsing", - "printing", - "clone-impls", - "proc-macro" - ], - "derive": [], - "extra-traits": [], - "fold": [], - "full": [], - "parsing": [], - "printing": [ - "quote" - ], - "proc-macro": [ - "proc-macro2/proc-macro", - "quote/proc-macro" - ], - "quote": [ - "dep:quote" - ], - "test": [ - "syn-test-suite/all-features" - ], - "visit": [], - "visit-mut": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true, - "rustdoc-args": [ - "--cfg", - "doc_cfg" - ], - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - }, - "playground": { - "features": [ - "full", - "visit", - "visit-mut", - "fold", - "extra-traits" - ] - } - }, - "publish": null, - "authors": [ - "David Tolnay " - ], - "categories": [ - "development-tools::procedural-macro-helpers", - "parser-implementations" - ], - "keywords": [ - "macros", - "syn" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/syn", - "homepage": null, - "documentation": "https://docs.rs/syn", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.56" - }, - { - "name": "unicode-ident", - "version": "1.0.8", - "id": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "(MIT OR Apache-2.0) AND Unicode-DFS-2016", - "license_file": null, - "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "criterion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "fst", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "small_rng" - ], - "target": null, - "registry": null - }, - { - "name": "roaring", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.10", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "ucd-trie", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "unicode-xid", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.4", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "unicode-ident", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "compare", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/tests/compare.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "static_size", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/tests/static_size.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "xid", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/benches/xid.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - } - }, - "publish": null, - "authors": [ - "David Tolnay " - ], - "categories": [ - "development-tools::procedural-macro-helpers", - "no-std" - ], - "keywords": [ - "unicode", - "xid" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/unicode-ident", - "homepage": null, - "documentation": "https://docs.rs/unicode-ident", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.31" - }, - { - "name": "wasi", - "version": "0.11.0+wasi-snapshot-preview1", - "id": "wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", - "license_file": null, - "description": "Experimental WASI API bindings for Rust", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-alloc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "wasi", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasi-0.11.0+wasi-snapshot-preview1/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "default": [ - "std" - ], - "rustc-dep-of-std": [ - "compiler_builtins", - "core", - "rustc-std-workspace-alloc" - ], - "rustc-std-workspace-alloc": [ - "dep:rustc-std-workspace-alloc" - ], - "std": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasi-0.11.0+wasi-snapshot-preview1/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Cranelift Project Developers" - ], - "categories": [ - "no-std", - "wasm" - ], - "keywords": [ - "webassembly", - "wasm" - ], - "readme": "README.md", - "repository": "https://github.com/bytecodealliance/wasi", - "homepage": null, - "documentation": "https://docs.rs/wasi", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "winapi", - "version": "0.3.9", - "id": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Raw FFI bindings for all of Windows API.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "winapi-i686-pc-windows-gnu", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "i686-pc-windows-gnu", - "registry": null - }, - { - "name": "winapi-x86_64-pc-windows-gnu", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "x86_64-pc-windows-gnu", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "winapi", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "accctrl": [], - "aclapi": [], - "activation": [], - "adhoc": [], - "appmgmt": [], - "audioclient": [], - "audiosessiontypes": [], - "avrt": [], - "basetsd": [], - "bcrypt": [], - "bits": [], - "bits10_1": [], - "bits1_5": [], - "bits2_0": [], - "bits2_5": [], - "bits3_0": [], - "bits4_0": [], - "bits5_0": [], - "bitscfg": [], - "bitsmsg": [], - "bluetoothapis": [], - "bluetoothleapis": [], - "bthdef": [], - "bthioctl": [], - "bthledef": [], - "bthsdpdef": [], - "bugcodes": [], - "cderr": [], - "cfg": [], - "cfgmgr32": [], - "cguid": [], - "combaseapi": [], - "coml2api": [], - "commapi": [], - "commctrl": [], - "commdlg": [], - "commoncontrols": [], - "consoleapi": [], - "corecrt": [], - "corsym": [], - "d2d1": [], - "d2d1_1": [], - "d2d1_2": [], - "d2d1_3": [], - "d2d1effectauthor": [], - "d2d1effects": [], - "d2d1effects_1": [], - "d2d1effects_2": [], - "d2d1svg": [], - "d2dbasetypes": [], - "d3d": [], - "d3d10": [], - "d3d10_1": [], - "d3d10_1shader": [], - "d3d10effect": [], - "d3d10misc": [], - "d3d10sdklayers": [], - "d3d10shader": [], - "d3d11": [], - "d3d11_1": [], - "d3d11_2": [], - "d3d11_3": [], - "d3d11_4": [], - "d3d11on12": [], - "d3d11sdklayers": [], - "d3d11shader": [], - "d3d11tokenizedprogramformat": [], - "d3d12": [], - "d3d12sdklayers": [], - "d3d12shader": [], - "d3d9": [], - "d3d9caps": [], - "d3d9types": [], - "d3dcommon": [], - "d3dcompiler": [], - "d3dcsx": [], - "d3dkmdt": [], - "d3dkmthk": [], - "d3dukmdt": [], - "d3dx10core": [], - "d3dx10math": [], - "d3dx10mesh": [], - "datetimeapi": [], - "davclnt": [], - "dbghelp": [], - "dbt": [], - "dcommon": [], - "dcomp": [], - "dcompanimation": [], - "dcomptypes": [], - "dde": [], - "ddraw": [], - "ddrawi": [], - "ddrawint": [], - "debug": [ - "impl-debug" - ], - "debugapi": [], - "devguid": [], - "devicetopology": [], - "devpkey": [], - "devpropdef": [], - "dinput": [], - "dinputd": [], - "dispex": [], - "dmksctl": [], - "dmusicc": [], - "docobj": [], - "documenttarget": [], - "dot1x": [], - "dpa_dsa": [], - "dpapi": [], - "dsgetdc": [], - "dsound": [], - "dsrole": [], - "dvp": [], - "dwmapi": [], - "dwrite": [], - "dwrite_1": [], - "dwrite_2": [], - "dwrite_3": [], - "dxdiag": [], - "dxfile": [], - "dxgi": [], - "dxgi1_2": [], - "dxgi1_3": [], - "dxgi1_4": [], - "dxgi1_5": [], - "dxgi1_6": [], - "dxgidebug": [], - "dxgiformat": [], - "dxgitype": [], - "dxva2api": [], - "dxvahd": [], - "eaptypes": [], - "enclaveapi": [], - "endpointvolume": [], - "errhandlingapi": [], - "everything": [], - "evntcons": [], - "evntprov": [], - "evntrace": [], - "excpt": [], - "exdisp": [], - "fibersapi": [], - "fileapi": [], - "functiondiscoverykeys_devpkey": [], - "gl-gl": [], - "guiddef": [], - "handleapi": [], - "heapapi": [], - "hidclass": [], - "hidpi": [], - "hidsdi": [], - "hidusage": [], - "highlevelmonitorconfigurationapi": [], - "hstring": [], - "http": [], - "ifdef": [], - "ifmib": [], - "imm": [], - "impl-debug": [], - "impl-default": [], - "in6addr": [], - "inaddr": [], - "inspectable": [], - "interlockedapi": [], - "intsafe": [], - "ioapiset": [], - "ipexport": [], - "iphlpapi": [], - "ipifcons": [], - "ipmib": [], - "iprtrmib": [], - "iptypes": [], - "jobapi": [], - "jobapi2": [], - "knownfolders": [], - "ks": [], - "ksmedia": [], - "ktmtypes": [], - "ktmw32": [], - "l2cmn": [], - "libloaderapi": [], - "limits": [], - "lmaccess": [], - "lmalert": [], - "lmapibuf": [], - "lmat": [], - "lmcons": [], - "lmdfs": [], - "lmerrlog": [], - "lmjoin": [], - "lmmsg": [], - "lmremutl": [], - "lmrepl": [], - "lmserver": [], - "lmshare": [], - "lmstats": [], - "lmsvc": [], - "lmuse": [], - "lmwksta": [], - "lowlevelmonitorconfigurationapi": [], - "lsalookup": [], - "memoryapi": [], - "minschannel": [], - "minwinbase": [], - "minwindef": [], - "mmdeviceapi": [], - "mmeapi": [], - "mmreg": [], - "mmsystem": [], - "mprapidef": [], - "msaatext": [], - "mscat": [], - "mschapp": [], - "mssip": [], - "mstcpip": [], - "mswsock": [], - "mswsockdef": [], - "namedpipeapi": [], - "namespaceapi": [], - "nb30": [], - "ncrypt": [], - "netioapi": [], - "nldef": [], - "ntddndis": [], - "ntddscsi": [], - "ntddser": [], - "ntdef": [], - "ntlsa": [], - "ntsecapi": [], - "ntstatus": [], - "oaidl": [], - "objbase": [], - "objidl": [], - "objidlbase": [], - "ocidl": [], - "ole2": [], - "oleauto": [], - "olectl": [], - "oleidl": [], - "opmapi": [], - "pdh": [], - "perflib": [], - "physicalmonitorenumerationapi": [], - "playsoundapi": [], - "portabledevice": [], - "portabledeviceapi": [], - "portabledevicetypes": [], - "powerbase": [], - "powersetting": [], - "powrprof": [], - "processenv": [], - "processsnapshot": [], - "processthreadsapi": [], - "processtopologyapi": [], - "profileapi": [], - "propidl": [], - "propkey": [], - "propkeydef": [], - "propsys": [], - "prsht": [], - "psapi": [], - "qos": [], - "realtimeapiset": [], - "reason": [], - "restartmanager": [], - "restrictederrorinfo": [], - "rmxfguid": [], - "roapi": [], - "robuffer": [], - "roerrorapi": [], - "rpc": [], - "rpcdce": [], - "rpcndr": [], - "rtinfo": [], - "sapi": [], - "sapi51": [], - "sapi53": [], - "sapiddk": [], - "sapiddk51": [], - "schannel": [], - "sddl": [], - "securityappcontainer": [], - "securitybaseapi": [], - "servprov": [], - "setupapi": [], - "shellapi": [], - "shellscalingapi": [], - "shlobj": [], - "shobjidl": [], - "shobjidl_core": [], - "shtypes": [], - "softpub": [], - "spapidef": [], - "spellcheck": [], - "sporder": [], - "sql": [], - "sqlext": [], - "sqltypes": [], - "sqlucode": [], - "sspi": [], - "std": [], - "stralign": [], - "stringapiset": [], - "strmif": [], - "subauth": [], - "synchapi": [], - "sysinfoapi": [], - "systemtopologyapi": [], - "taskschd": [], - "tcpestats": [], - "tcpmib": [], - "textstor": [], - "threadpoolapiset": [], - "threadpoollegacyapiset": [], - "timeapi": [], - "timezoneapi": [], - "tlhelp32": [], - "transportsettingcommon": [], - "tvout": [], - "udpmib": [], - "unknwnbase": [], - "urlhist": [], - "urlmon": [], - "usb": [], - "usbioctl": [], - "usbiodef": [], - "usbscan": [], - "usbspec": [], - "userenv": [], - "usp10": [], - "utilapiset": [], - "uxtheme": [], - "vadefs": [], - "vcruntime": [], - "vsbackup": [], - "vss": [], - "vsserror": [], - "vswriter": [], - "wbemads": [], - "wbemcli": [], - "wbemdisp": [], - "wbemprov": [], - "wbemtran": [], - "wct": [], - "werapi": [], - "winbase": [], - "wincodec": [], - "wincodecsdk": [], - "wincon": [], - "wincontypes": [], - "wincred": [], - "wincrypt": [], - "windef": [], - "windot11": [], - "windowsceip": [], - "windowsx": [], - "winefs": [], - "winerror": [], - "winevt": [], - "wingdi": [], - "winhttp": [], - "wininet": [], - "winineti": [], - "winioctl": [], - "winnetwk": [], - "winnls": [], - "winnt": [], - "winreg": [], - "winsafer": [], - "winscard": [], - "winsmcrd": [], - "winsock2": [], - "winspool": [], - "winstring": [], - "winsvc": [], - "wintrust": [], - "winusb": [], - "winusbio": [], - "winuser": [], - "winver": [], - "wlanapi": [], - "wlanihv": [], - "wlanihvtypes": [], - "wlantypes": [], - "wlclient": [], - "wmistr": [], - "wnnc": [], - "wow64apiset": [], - "wpdmtpextensions": [], - "ws2bth": [], - "ws2def": [], - "ws2ipdef": [], - "ws2spi": [], - "ws2tcpip": [], - "wtsapi32": [], - "wtypes": [], - "wtypesbase": [], - "xinput": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "default-target": "x86_64-pc-windows-msvc", - "features": [ - "everything", - "impl-debug", - "impl-default" - ], - "targets": [ - "aarch64-pc-windows-msvc", - "i686-pc-windows-msvc", - "x86_64-pc-windows-msvc" - ] - } - } - }, - "publish": null, - "authors": [ - "Peter Atashian " - ], - "categories": [ - "external-ffi-bindings", - "no-std", - "os::windows-apis" - ], - "keywords": [ - "windows", - "ffi", - "win32", - "com", - "directx" - ], - "readme": "README.md", - "repository": "https://github.com/retep998/winapi-rs", - "homepage": null, - "documentation": "https://docs.rs/winapi/", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "winapi-i686-pc-windows-gnu", - "version": "0.4.0", - "id": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Import libraries for the i686-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "winapi-i686-pc-windows-gnu", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Peter Atashian " - ], - "categories": [], - "keywords": [ - "windows" - ], - "readme": null, - "repository": "https://github.com/retep998/winapi-rs", - "homepage": null, - "documentation": null, - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "winapi-x86_64-pc-windows-gnu", - "version": "0.4.0", - "id": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Import libraries for the x86_64-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "winapi-x86_64-pc-windows-gnu", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Peter Atashian " - ], - "categories": [], - "keywords": [ - "windows" - ], - "readme": null, - "repository": "https://github.com/retep998/winapi-rs", - "homepage": null, - "documentation": null, - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - } - ], - "workspace_members": [ - "regex-benchmark 0.1.0 (path+file:///$ROOT$regex/bench)", - "regex 1.7.1 (path+file:///$ROOT$regex)", - "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", - "rure 0.2.2 (path+file:///$ROOT$regex/regex-capi)", - "regex-debug 0.1.0 (path+file:///$ROOT$regex/regex-debug)" - ], - "resolve": { - "nodes": [ - { - "id": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "memchr", - "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "std" - ] - }, - { - "id": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "lazy_static", - "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde", - "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "strsim", - "pkg": "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "getrandom 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cfg_if", - "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(unix)" - } - ] - }, - { - "name": "wasi", - "pkg": "wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(target_os = \"wasi\")" - } - ] - } - ], - "features": [] - }, - { - "id": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "std" - ] - }, - { - "id": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "std" - ] - }, - { - "id": "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(unix)" - } - ] - }, - { - "name": "winapi", - "pkg": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(windows)" - } - ] - } - ], - "features": [] - }, - { - "id": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "unicode_ident", - "pkg": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "proc-macro" - ] - }, - { - "id": "quickcheck 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "rand", - "pkg": "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "proc_macro2", - "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "proc-macro" - ] - }, - { - "id": "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "rand_core", - "pkg": "rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "getrandom", - "small_rng" - ] - }, - { - "id": "rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "getrandom 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "getrandom", - "pkg": "getrandom 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "getrandom" - ] - }, - { - "id": "regex 1.7.1 (path+file:///$ROOT$regex)", - "dependencies": [ - "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)" - ], - "deps": [ - { - "name": "aho_corasick", - "pkg": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "lazy_static", - "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "memchr", - "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "quickcheck", - "pkg": "quickcheck 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "rand", - "pkg": "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "regex_syntax", - "pkg": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "aho-corasick", - "default", - "memchr", - "perf", - "perf-cache", - "perf-dfa", - "perf-inline", - "perf-literal", - "std", - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ] - }, - { - "id": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "regex_syntax", - "pkg": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "std", - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ] - }, - { - "id": "regex-benchmark 0.1.0 (path+file:///$ROOT$regex/bench)", - "dependencies": [ - "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.7.1 (path+file:///$ROOT$regex)", - "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", - "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cc", - "pkg": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "build", - "target": null - } - ] - }, - { - "name": "cfg_if", - "pkg": "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "docopt", - "pkg": "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "lazy_static", - "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "memmap", - "pkg": "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "pkg_config", - "pkg": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "build", - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.7.1 (path+file:///$ROOT$regex)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex_syntax", - "pkg": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde", - "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "regex-debug 0.1.0 (path+file:///$ROOT$regex/regex-debug)", - "dependencies": [ - "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.7.1 (path+file:///$ROOT$regex)", - "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", - "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "docopt", - "pkg": "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.7.1 (path+file:///$ROOT$regex)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex_syntax", - "pkg": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde", - "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ] - }, - { - "id": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ] - }, - { - "id": "rure 0.2.2 (path+file:///$ROOT$regex/regex-capi)", - "dependencies": [ - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.7.1 (path+file:///$ROOT$regex)" - ], - "deps": [ - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.7.1 (path+file:///$ROOT$regex)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "serde_derive", - "pkg": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "derive", - "serde_derive", - "std" - ] - }, - { - "id": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "proc_macro2", - "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "quote", - "pkg": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "syn", - "pkg": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default" - ] - }, - { - "id": "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "proc_macro2", - "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "quote", - "pkg": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "unicode_ident", - "pkg": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "clone-impls", - "default", - "derive", - "parsing", - "printing", - "proc-macro", - "quote" - ] - }, - { - "id": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "winapi_i686_pc_windows_gnu", - "pkg": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "i686-pc-windows-gnu" - } - ] - }, - { - "name": "winapi_x86_64_pc_windows_gnu", - "pkg": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "x86_64-pc-windows-gnu" - } - ] - } - ], - "features": [ - "basetsd", - "handleapi", - "memoryapi", - "minwindef", - "std", - "sysinfoapi" - ] - }, - { - "id": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - } - ], - "root": "regex 1.7.1 (path+file:///$ROOT$regex)" - }, - "target_directory": "$ROOT$regex/target", - "version": 1, - "workspace_root": "$ROOT$regex", - "metadata": null -} diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/ripgrep-metadata.json b/src/tools/rust-analyzer/crates/project-model/test_data/ripgrep-metadata.json deleted file mode 100644 index 131ff5dd71571..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/test_data/ripgrep-metadata.json +++ /dev/null @@ -1,12816 +0,0 @@ -{ - "packages": [ - { - "name": "aho-corasick", - "version": "0.7.20", - "id": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Fast multiple substring searching.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.4.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "aho_corasick", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-0.7.20/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "default": [ - "std" - ], - "std": [ - "memchr/std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-0.7.20/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "text-processing" - ], - "keywords": [ - "string", - "search", - "text", - "aho", - "multi" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/aho-corasick", - "homepage": "https://github.com/BurntSushi/aho-corasick", - "documentation": null, - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "aho-corasick", - "version": "1.0.1", - "id": "aho-corasick 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Fast multiple substring searching.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.17", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.4.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "doc-comment", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "aho_corasick", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-1.0.1/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "default": [ - "std", - "perf-literal" - ], - "logging": [ - "dep:log" - ], - "perf-literal": [ - "dep:memchr" - ], - "std": [ - "memchr?/std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-1.0.1/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true, - "rustdoc-args": [ - "--cfg", - "docsrs" - ] - } - } - }, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "text-processing" - ], - "keywords": [ - "string", - "search", - "text", - "pattern", - "multi" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/aho-corasick", - "homepage": "https://github.com/BurntSushi/aho-corasick", - "documentation": null, - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.60.0" - }, - { - "name": "atty", - "version": "0.2.14", - "id": "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT", - "license_file": null, - "description": "A simple interface for querying atty", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "hermit-abi", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(target_os = \"hermit\")", - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": "cfg(unix)", - "registry": null - }, - { - "name": "winapi", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "consoleapi", - "processenv", - "minwinbase", - "minwindef", - "winbase" - ], - "target": "cfg(windows)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "atty", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/atty-0.2.14/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "atty", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/atty-0.2.14/examples/atty.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/atty-0.2.14/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "softprops " - ], - "categories": [], - "keywords": [ - "terminal", - "tty", - "isatty" - ], - "readme": "README.md", - "repository": "https://github.com/softprops/atty", - "homepage": "https://github.com/softprops/atty", - "documentation": "http://softprops.github.io/atty", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "base64", - "version": "0.20.0", - "id": "base64 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "encodes and decodes base64 as bytes or utf8", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "criterion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8.5", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "small_rng" - ], - "target": null, - "registry": null - }, - { - "name": "rstest", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.12.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rstest_reuse", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "structopt", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.26", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "base64", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "base64", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/examples/base64.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "encode", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/tests/encode.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "tests", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/tests/tests.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "benchmarks", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/benches/benchmarks.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "alloc": [], - "default": [ - "std" - ], - "std": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alice Maz ", - "Marshall Pierce " - ], - "categories": [ - "encoding" - ], - "keywords": [ - "base64", - "utf8", - "encode", - "decode", - "no_std" - ], - "readme": "README.md", - "repository": "https://github.com/marshallpierce/rust-base64", - "homepage": null, - "documentation": "https://docs.rs/base64", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.57.0" - }, - { - "name": "bitflags", - "version": "1.3.2", - "id": "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "A macro to generate structures which behave like bitflags.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_json", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "trybuild", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "walkdir", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "bitflags", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bitflags-1.3.2/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "basic", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bitflags-1.3.2/tests/basic.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "compile", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bitflags-1.3.2/tests/compile.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "default": [], - "example_generated": [], - "rustc-dep-of-std": [ - "core", - "compiler_builtins" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bitflags-1.3.2/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "example_generated" - ] - } - } - }, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "no-std" - ], - "keywords": [ - "bit", - "bitmask", - "bitflags", - "flags" - ], - "readme": "README.md", - "repository": "https://github.com/bitflags/bitflags", - "homepage": "https://github.com/bitflags/bitflags", - "documentation": "https://docs.rs/bitflags", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "bstr", - "version": "1.4.0", - "id": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A string type that is not required to be valid UTF-8.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.4.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "once_cell", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.14.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex-automata", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.5", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.85", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quickcheck", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "ucd-parse", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "unicode-segmentation", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.2.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "bstr", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "graphemes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/graphemes.rs", - "edition": "2021", - "required-features": [ - "std", - "unicode" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "lines", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/lines.rs", - "edition": "2021", - "required-features": [ - "std" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "uppercase", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/uppercase.rs", - "edition": "2021", - "required-features": [ - "std", - "unicode" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "words", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/words.rs", - "edition": "2021", - "required-features": [ - "std", - "unicode" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "graphemes-std", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/graphemes-std.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "lines-std", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/lines-std.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "uppercase-std", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/uppercase-std.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "words-std", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/words-std.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "alloc": [ - "serde?/alloc" - ], - "default": [ - "std", - "unicode" - ], - "serde": [ - "dep:serde" - ], - "std": [ - "alloc", - "memchr/std", - "serde?/std" - ], - "unicode": [ - "dep:once_cell", - "dep:regex-automata" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true, - "rustdoc-args": [ - "--cfg", - "docsrs" - ] - } - } - }, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "text-processing", - "encoding" - ], - "keywords": [ - "string", - "str", - "byte", - "bytes", - "text" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/bstr", - "homepage": "https://github.com/BurntSushi/bstr", - "documentation": "https://docs.rs/bstr", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.60" - }, - { - "name": "bytecount", - "version": "0.6.3", - "id": "bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Apache-2.0/MIT", - "license_file": null, - "description": "count occurrences of a given byte, or the number of UTF-8 code points, in a byte slice, fast", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "packed_simd_2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.8", - "kind": null, - "rename": "packed_simd", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "criterion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quickcheck", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "bytecount", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytecount-0.6.3/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "check", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytecount-0.6.3/tests/check.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytecount-0.6.3/benches/bench.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "generic-simd": [ - "packed_simd" - ], - "html_report": [], - "packed_simd": [ - "dep:packed_simd" - ], - "runtime-dispatch-simd": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytecount-0.6.3/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andre Bogus ", - "Joshua Landau " - ], - "categories": [ - "algorithms", - "no-std" - ], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/llogiq/bytecount", - "homepage": null, - "documentation": null, - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "cc", - "version": "1.0.79", - "id": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "jobserver", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.16", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tempfile", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "cc", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bin" - ], - "crate_types": [ - "bin" - ], - "name": "gcc-shim", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/src/bin/gcc-shim.rs", - "edition": "2018", - "doc": true, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "cc_env", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cc_env.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "cflags", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cflags.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "cxxflags", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cxxflags.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "jobserver": [ - "dep:jobserver" - ], - "parallel": [ - "jobserver" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [ - "development-tools::build-utils" - ], - "keywords": [ - "build-dependencies" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang/cc-rs", - "homepage": "https://github.com/rust-lang/cc-rs", - "documentation": "https://docs.rs/cc", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "cfg-if", - "version": "1.0.0", - "id": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "cfg-if", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "xcrate", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/tests/xcrate.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "rustc-dep-of-std": [ - "core", - "compiler_builtins" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/alexcrichton/cfg-if", - "homepage": "https://github.com/alexcrichton/cfg-if", - "documentation": "https://docs.rs/cfg-if", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "clap", - "version": "2.34.0", - "id": "clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT", - "license_file": null, - "description": "A simple to use, efficient, and full-featured Command Line Argument Parser\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "atty", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "bitflags", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "clippy", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "~0.0.166", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "strsim", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "term_size", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "textwrap", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.11.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "unicode-width", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "vec_map", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "yaml-rust", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.5", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "version-sync", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "ansi_term", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.12", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": "cfg(not(windows))", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "clap", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/clap-2.34.0/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "ansi_term": [ - "dep:ansi_term" - ], - "atty": [ - "dep:atty" - ], - "clippy": [ - "dep:clippy" - ], - "color": [ - "ansi_term", - "atty" - ], - "debug": [], - "default": [ - "suggestions", - "color", - "vec_map" - ], - "doc": [ - "yaml" - ], - "nightly": [], - "no_cargo": [], - "strsim": [ - "dep:strsim" - ], - "suggestions": [ - "strsim" - ], - "term_size": [ - "dep:term_size" - ], - "unstable": [], - "vec_map": [ - "dep:vec_map" - ], - "wrap_help": [ - "term_size", - "textwrap/term_size" - ], - "yaml": [ - "yaml-rust" - ], - "yaml-rust": [ - "dep:yaml-rust" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/clap-2.34.0/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "doc" - ] - } - } - }, - "publish": null, - "authors": [ - "Kevin K. " - ], - "categories": [ - "command-line-interface" - ], - "keywords": [ - "argument", - "cli", - "arg", - "parser", - "parse" - ], - "readme": "README.md", - "repository": "https://github.com/clap-rs/clap", - "homepage": "https://clap.rs/", - "documentation": "https://docs.rs/clap/", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "crossbeam-channel", - "version": "0.5.8", - "id": "crossbeam-channel 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Multi-producer multi-consumer channels for message passing", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "cfg-if", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "crossbeam-utils", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "num_cpus", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.13.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "signal-hook", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "crossbeam-channel", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "fibonacci", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/examples/fibonacci.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "matching", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/examples/matching.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "stopwatch", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/examples/stopwatch.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "after", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/after.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "array", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/array.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "golang", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/golang.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "iter", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/iter.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "list", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/list.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "mpsc", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/mpsc.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "never", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/never.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "ready", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/ready.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "same_channel", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/same_channel.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "select", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/select.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "select_macro", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/select_macro.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "thread_locals", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/thread_locals.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "tick", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/tick.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "zero", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/zero.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "crossbeam", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/benches/crossbeam.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "crossbeam-utils": [ - "dep:crossbeam-utils" - ], - "default": [ - "std" - ], - "std": [ - "crossbeam-utils/std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [], - "categories": [ - "algorithms", - "concurrency", - "data-structures" - ], - "keywords": [ - "channel", - "mpmc", - "select", - "golang", - "message" - ], - "readme": "README.md", - "repository": "https://github.com/crossbeam-rs/crossbeam", - "homepage": "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel", - "documentation": null, - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.38" - }, - { - "name": "crossbeam-utils", - "version": "0.8.15", - "id": "crossbeam-utils 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Utilities for concurrent programming", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "cfg-if", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "loom", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.5", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": "cfg(crossbeam_loom)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "crossbeam-utils", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "atomic_cell", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/atomic_cell.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "cache_padded", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/cache_padded.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "parker", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/parker.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "sharded_lock", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/sharded_lock.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "thread", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/thread.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "wait_group", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/wait_group.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "atomic_cell", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/benches/atomic_cell.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "std" - ], - "loom": [ - "dep:loom" - ], - "nightly": [], - "std": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [], - "categories": [ - "algorithms", - "concurrency", - "data-structures", - "no-std" - ], - "keywords": [ - "scoped", - "thread", - "atomic", - "cache" - ], - "readme": "README.md", - "repository": "https://github.com/crossbeam-rs/crossbeam", - "homepage": "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils", - "documentation": null, - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.38" - }, - { - "name": "encoding_rs", - "version": "0.8.32", - "id": "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "(Apache-2.0 OR MIT) AND BSD-3-Clause", - "license_file": null, - "description": "A Gecko-oriented implementation of the Encoding Standard", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "cfg-if", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "packed_simd_2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.4", - "kind": null, - "rename": "packed_simd", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "bincode", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_json", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "encoding_rs", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/encoding_rs-0.8.32/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "alloc": [], - "default": [ - "alloc" - ], - "fast-big5-hanzi-encode": [], - "fast-gb-hanzi-encode": [], - "fast-hangul-encode": [], - "fast-hanja-encode": [], - "fast-kanji-encode": [], - "fast-legacy-encode": [ - "fast-hangul-encode", - "fast-hanja-encode", - "fast-kanji-encode", - "fast-gb-hanzi-encode", - "fast-big5-hanzi-encode" - ], - "less-slow-big5-hanzi-encode": [], - "less-slow-gb-hanzi-encode": [], - "less-slow-kanji-encode": [], - "packed_simd": [ - "dep:packed_simd" - ], - "serde": [ - "dep:serde" - ], - "simd-accel": [ - "packed_simd", - "packed_simd/into_bits" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/encoding_rs-0.8.32/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Henri Sivonen " - ], - "categories": [ - "text-processing", - "encoding", - "web-programming", - "internationalization" - ], - "keywords": [ - "encoding", - "web", - "unicode", - "charset" - ], - "readme": "README.md", - "repository": "https://github.com/hsivonen/encoding_rs", - "homepage": "https://docs.rs/encoding_rs/", - "documentation": "https://docs.rs/encoding_rs/", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "encoding_rs_io", - "version": "0.1.7", - "id": "encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Streaming transcoding for encoding_rs", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "encoding_rs", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "encoding_rs_io", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/encoding_rs_io-0.1.7/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/encoding_rs_io-0.1.7/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "text-processing", - "encoding", - "web-programming", - "email" - ], - "keywords": [ - "encoding", - "transcoding", - "stream", - "io", - "read" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/encoding_rs_io", - "homepage": null, - "documentation": "https://docs.rs/encoding_rs_io", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "fnv", - "version": "1.0.7", - "id": "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Apache-2.0 / MIT", - "license_file": null, - "description": "Fowler–Noll–Vo hash function", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "fnv", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/fnv-1.0.7/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "default": [ - "std" - ], - "std": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/fnv-1.0.7/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/servo/rust-fnv", - "homepage": null, - "documentation": "https://doc.servo.org/fnv/", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "glob", - "version": "0.3.1", - "id": "glob 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Support for matching file paths against Unix shell style patterns.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "doc-comment", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tempdir", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "glob", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/glob-0.3.1/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "glob-std", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/glob-0.3.1/tests/glob-std.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/glob-0.3.1/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "filesystem" - ], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/glob", - "homepage": "https://github.com/rust-lang/glob", - "documentation": "https://docs.rs/glob/0.3.1", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "globset", - "version": "0.4.10", - "id": "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Cross platform single glob and glob set matching. Glob set matching is the\nprocess of matching one or more glob patterns against a single candidate path\nsimultaneously, and returning all of the globs that matched.\n", - "source": null, - "dependencies": [ - { - "name": "aho-corasick", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.7.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "bstr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "std" - ], - "target": null, - "registry": null - }, - { - "name": "fnv", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.5", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "perf", - "std" - ], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.104", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "glob", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_json", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.45", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "globset", - "src_path": "$ROOT$ripgrep/crates/globset/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$ripgrep/crates/globset/benches/bench.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "log" - ], - "log": [ - "dep:log" - ], - "serde": [ - "dep:serde" - ], - "serde1": [ - "serde" - ], - "simd-accel": [] - }, - "manifest_path": "$ROOT$ripgrep/crates/globset/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "regex", - "glob", - "multiple", - "set", - "pattern" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/globset", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/globset", - "documentation": "https://docs.rs/globset", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "grep", - "version": "0.2.11", - "id": "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Fast line oriented regex searching as a library.\n", - "source": null, - "dependencies": [ - { - "name": "grep-cli", - "source": null, - "req": "^0.1.7", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/cli" - }, - { - "name": "grep-matcher", - "source": null, - "req": "^0.1.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/matcher" - }, - { - "name": "grep-pcre2", - "source": null, - "req": "^0.1.6", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/pcre2" - }, - { - "name": "grep-printer", - "source": null, - "req": "^0.1.7", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/printer" - }, - { - "name": "grep-regex", - "source": null, - "req": "^0.1.11", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/regex" - }, - { - "name": "grep-searcher", - "source": null, - "req": "^0.1.11", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/searcher" - }, - { - "name": "termcolor", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.4", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "walkdir", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.2.7", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "grep", - "src_path": "$ROOT$ripgrep/crates/grep/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "simplegrep", - "src_path": "$ROOT$ripgrep/crates/grep/examples/simplegrep.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "avx-accel": [], - "grep-pcre2": [ - "dep:grep-pcre2" - ], - "pcre2": [ - "grep-pcre2" - ], - "simd-accel": [ - "grep-searcher/simd-accel" - ] - }, - "manifest_path": "$ROOT$ripgrep/crates/grep/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "regex", - "grep", - "egrep", - "search", - "pattern" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/grep", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/grep", - "documentation": "https://docs.rs/grep", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "grep-cli", - "version": "0.1.7", - "id": "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Utilities for search oriented command line applications.\n", - "source": null, - "dependencies": [ - { - "name": "atty", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.11", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "bstr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "globset", - "source": null, - "req": "^0.4.10", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/globset" - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "same-file", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "termcolor", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "winapi-util", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(windows)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "grep-cli", - "src_path": "$ROOT$ripgrep/crates/cli/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$ripgrep/crates/cli/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "regex", - "grep", - "cli", - "utility", - "util" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli", - "documentation": "https://docs.rs/grep-cli", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "grep-matcher", - "version": "0.1.6", - "id": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "A trait for regular expressions, with a focus on line oriented search.\n", - "source": null, - "dependencies": [ - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "grep-matcher", - "src_path": "$ROOT$ripgrep/crates/matcher/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "integration", - "src_path": "$ROOT$ripgrep/crates/matcher/tests/tests.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$ripgrep/crates/matcher/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "regex", - "pattern", - "trait" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/matcher", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/matcher", - "documentation": "https://docs.rs/grep-matcher", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "grep-pcre2", - "version": "0.1.6", - "id": "grep-pcre2 0.1.6 (path+file:///$ROOT$ripgrep/crates/pcre2)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Use PCRE2 with the 'grep' crate.\n", - "source": null, - "dependencies": [ - { - "name": "grep-matcher", - "source": null, - "req": "^0.1.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/matcher" - }, - { - "name": "pcre2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "grep-pcre2", - "src_path": "$ROOT$ripgrep/crates/pcre2/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$ripgrep/crates/pcre2/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "regex", - "grep", - "pcre", - "backreference", - "look" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/pcre2", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/pcre2", - "documentation": "https://docs.rs/grep-pcre2", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "grep-printer", - "version": "0.1.7", - "id": "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "An implementation of the grep crate's Sink trait that provides standard\nprinting of search results, similar to grep itself.\n", - "source": null, - "dependencies": [ - { - "name": "base64", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.20.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "bstr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "grep-matcher", - "source": null, - "req": "^0.1.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/matcher" - }, - { - "name": "grep-searcher", - "source": null, - "req": "^0.1.11", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/searcher" - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.77", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - }, - { - "name": "serde_json", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.27", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "termcolor", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "grep-regex", - "source": null, - "req": "^0.1.11", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/regex" - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "grep-printer", - "src_path": "$ROOT$ripgrep/crates/printer/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "base64": [ - "dep:base64" - ], - "default": [ - "serde1" - ], - "serde": [ - "dep:serde" - ], - "serde1": [ - "base64", - "serde", - "serde_json" - ], - "serde_json": [ - "dep:serde_json" - ] - }, - "manifest_path": "$ROOT$ripgrep/crates/printer/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "grep", - "pattern", - "print", - "printer", - "sink" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/printer", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/printer", - "documentation": "https://docs.rs/grep-printer", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "grep-regex", - "version": "0.1.11", - "id": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Use Rust's regex library with the 'grep' crate.\n", - "source": null, - "dependencies": [ - { - "name": "aho-corasick", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.7.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "bstr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "grep-matcher", - "source": null, - "req": "^0.1.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/matcher" - }, - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex-syntax", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.6.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "thread_local", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "grep-regex", - "src_path": "$ROOT$ripgrep/crates/regex/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$ripgrep/crates/regex/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "regex", - "grep", - "search", - "pattern", - "line" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/regex", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/regex", - "documentation": "https://docs.rs/grep-regex", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "grep-searcher", - "version": "0.1.11", - "id": "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "Fast line oriented regex searching as a library.\n", - "source": null, - "dependencies": [ - { - "name": "bstr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "std" - ], - "target": null, - "registry": null - }, - { - "name": "bytecount", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "encoding_rs", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8.14", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "encoding_rs_io", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "grep-matcher", - "source": null, - "req": "^0.1.6", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/matcher" - }, - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "memmap2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.5.3", - "kind": null, - "rename": "memmap", - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "grep-regex", - "source": null, - "req": "^0.1.11", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/regex" - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "grep-searcher", - "src_path": "$ROOT$ripgrep/crates/searcher/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "search-stdin", - "src_path": "$ROOT$ripgrep/crates/searcher/examples/search-stdin.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "avx-accel": [], - "default": [ - "bytecount/runtime-dispatch-simd" - ], - "simd-accel": [ - "encoding_rs/simd-accel" - ] - }, - "manifest_path": "$ROOT$ripgrep/crates/searcher/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "regex", - "grep", - "egrep", - "search", - "pattern" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/searcher", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/searcher", - "documentation": "https://docs.rs/grep-searcher", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "hermit-abi", - "version": "0.1.19", - "id": "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "hermit-abi is small interface to call functions from the unikernel RustyHermit.\nIt is used to build the target `x86_64-unknown-hermit`.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.51", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "hermit-abi", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/hermit-abi-0.1.19/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "default": [], - "docs": [], - "rustc-dep-of-std": [ - "core", - "compiler_builtins/rustc-dep-of-std", - "libc/rustc-dep-of-std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/hermit-abi-0.1.19/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "default-target": "x86_64-unknown-hermit", - "features": [ - "docs" - ] - } - } - }, - "publish": null, - "authors": [ - "Stefan Lankes" - ], - "categories": [ - "os" - ], - "keywords": [ - "unikernel", - "libos" - ], - "readme": "README.md", - "repository": "https://github.com/hermitcore/libhermit-rs", - "homepage": null, - "documentation": "https://hermitcore.github.io/rusty-hermit/hermit_abi", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "ignore", - "version": "0.4.20", - "id": "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "A fast library for efficiently matching ignore files such as `.gitignore`\nagainst file paths.\n", - "source": null, - "dependencies": [ - { - "name": "globset", - "source": null, - "req": "^0.4.10", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/globset" - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "same-file", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "thread_local", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "walkdir", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.2.7", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "crossbeam-channel", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.5.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "winapi-util", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(windows)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "ignore", - "src_path": "$ROOT$ripgrep/crates/ignore/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "walk", - "src_path": "$ROOT$ripgrep/crates/ignore/examples/walk.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "gitignore_matched_path_or_any_parents_tests", - "src_path": "$ROOT$ripgrep/crates/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "simd-accel": [ - "globset/simd-accel" - ] - }, - "manifest_path": "$ROOT$ripgrep/crates/ignore/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "glob", - "ignore", - "gitignore", - "pattern", - "file" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore", - "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore", - "documentation": "https://docs.rs/ignore", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "itoa", - "version": "1.0.6", - "id": "itoa 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Fast integer primitive to string conversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "no-panic", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "itoa", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/itoa-1.0.6/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/itoa-1.0.6/tests/test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/itoa-1.0.6/benches/bench.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "no-panic": [ - "dep:no-panic" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/itoa-1.0.6/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - } - }, - "publish": null, - "authors": [ - "David Tolnay " - ], - "categories": [ - "value-formatting", - "no-std" - ], - "keywords": [ - "integer" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/itoa", - "homepage": null, - "documentation": "https://docs.rs/itoa", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.36" - }, - { - "name": "jemalloc-sys", - "version": "0.5.3+5.3.0-patched", - "id": "jemalloc-sys 0.5.3+5.3.0-patched (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Rust FFI bindings to jemalloc\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.8", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "cc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.13", - "kind": "build", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "jemalloc-sys", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "malloc_conf_empty", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/tests/malloc_conf_empty.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "malloc_conf_set", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/tests/malloc_conf_set.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "unprefixed_malloc", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/tests/unprefixed_malloc.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "background_threads": [ - "background_threads_runtime_support" - ], - "background_threads_runtime_support": [], - "debug": [], - "default": [ - "background_threads_runtime_support" - ], - "disable_initial_exec_tls": [], - "profiling": [], - "stats": [], - "unprefixed_malloc_on_supported_platforms": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "rustdoc-args": [ - "--cfg", - "jemallocator_docs" - ] - } - } - }, - "publish": null, - "authors": [ - "Alex Crichton ", - "Gonzalo Brito Gadeschi ", - "The TiKV Project Developers" - ], - "categories": [], - "keywords": [ - "allocator", - "jemalloc" - ], - "readme": "README.md", - "repository": "https://github.com/tikv/jemallocator", - "homepage": "https://github.com/tikv/jemallocator", - "documentation": "https://docs.rs/jemallocator-sys", - "edition": "2018", - "links": "jemalloc", - "default_run": null, - "rust_version": null - }, - { - "name": "jemallocator", - "version": "0.5.0", - "id": "jemallocator 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "A Rust allocator backed by jemalloc\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "jemalloc-sys", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.5.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.8", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "paste", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "jemallocator", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "background_thread_defaults", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/background_thread_defaults.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "background_thread_enabled", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/background_thread_enabled.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "ffi", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/ffi.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "grow_in_place", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/grow_in_place.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "malloctl", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/malloctl.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "shrink_in_place", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/shrink_in_place.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "smoke", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/smoke.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "smoke_ffi", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/smoke_ffi.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "usable_size", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/usable_size.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "roundtrip", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/benches/roundtrip.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "alloc_trait": [], - "background_threads": [ - "jemalloc-sys/background_threads" - ], - "background_threads_runtime_support": [ - "jemalloc-sys/background_threads_runtime_support" - ], - "debug": [ - "jemalloc-sys/debug" - ], - "default": [ - "background_threads_runtime_support" - ], - "disable_initial_exec_tls": [ - "jemalloc-sys/disable_initial_exec_tls" - ], - "profiling": [ - "jemalloc-sys/profiling" - ], - "stats": [ - "jemalloc-sys/stats" - ], - "unprefixed_malloc_on_supported_platforms": [ - "jemalloc-sys/unprefixed_malloc_on_supported_platforms" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [], - "rustdoc-args": [ - "--cfg", - "jemallocator_docs" - ] - } - } - }, - "publish": null, - "authors": [ - "Alex Crichton ", - "Gonzalo Brito Gadeschi ", - "Simon Sapin ", - "Steven Fackler ", - "The TiKV Project Developers" - ], - "categories": [ - "memory-management", - "api-bindings" - ], - "keywords": [ - "allocator", - "jemalloc" - ], - "readme": "README.md", - "repository": "https://github.com/tikv/jemallocator", - "homepage": "https://github.com/tikv/jemallocator", - "documentation": "https://docs.rs/jemallocator", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "jobserver", - "version": "0.1.26", - "id": "jobserver 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "An implementation of the GNU make jobserver for Rust\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "futures", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "num_cpus", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tempfile", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tokio-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tokio-process", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.50", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(unix)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "jobserver", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "client", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/client.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "server", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/server.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "client-of-myself", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/client-of-myself.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "make-as-a-client", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/make-as-a-client.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "helper", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/helper.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/alexcrichton/jobserver-rs", - "homepage": "https://github.com/alexcrichton/jobserver-rs", - "documentation": "https://docs.rs/jobserver", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "lazy_static", - "version": "1.4.0", - "id": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "A macro for declaring lazily evaluated statics in Rust.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "spin", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.5.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "doc-comment", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "lazy_static", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "no_std", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/tests/no_std.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/tests/test.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "spin": [ - "dep:spin" - ], - "spin_no_std": [ - "spin" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Marvin Löbel " - ], - "categories": [ - "no-std", - "rust-patterns", - "memory-management" - ], - "keywords": [ - "macro", - "lazy", - "static" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang-nursery/lazy-static.rs", - "homepage": null, - "documentation": "https://docs.rs/lazy_static", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "libc", - "version": "0.2.142", - "id": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Raw FFI bindings to platform libraries like libc.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "libc", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "const_fn", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/tests/const_fn.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "align": [], - "const-extern-fn": [], - "default": [ - "std" - ], - "extra_traits": [], - "rustc-dep-of-std": [ - "align", - "rustc-std-workspace-core" - ], - "rustc-std-workspace-core": [ - "dep:rustc-std-workspace-core" - ], - "std": [], - "use_std": [ - "std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "const-extern-fn", - "extra_traits" - ] - } - } - }, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "external-ffi-bindings", - "no-std", - "os" - ], - "keywords": [ - "libc", - "ffi", - "bindings", - "operating", - "system" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang/libc", - "homepage": "https://github.com/rust-lang/libc", - "documentation": "https://docs.rs/libc/", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "log", - "version": "0.4.17", - "id": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A lightweight logging facade for Rust\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "cfg-if", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "sval", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "=1.0.0-alpha.5", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "value-bag", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "=1.0.0-alpha.9", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - }, - { - "name": "serde_test", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "sval", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "=1.0.0-alpha.5", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - }, - { - "name": "value-bag", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "=1.0.0-alpha.9", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "test" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "log", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "filters", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/tests/filters.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "macros", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/tests/macros.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "value", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/benches/value.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "kv_unstable": [ - "value-bag" - ], - "kv_unstable_serde": [ - "kv_unstable_std", - "value-bag/serde", - "serde" - ], - "kv_unstable_std": [ - "std", - "kv_unstable", - "value-bag/error" - ], - "kv_unstable_sval": [ - "kv_unstable", - "value-bag/sval", - "sval" - ], - "max_level_debug": [], - "max_level_error": [], - "max_level_info": [], - "max_level_off": [], - "max_level_trace": [], - "max_level_warn": [], - "release_max_level_debug": [], - "release_max_level_error": [], - "release_max_level_info": [], - "release_max_level_off": [], - "release_max_level_trace": [], - "release_max_level_warn": [], - "serde": [ - "dep:serde" - ], - "std": [], - "sval": [ - "dep:sval" - ], - "value-bag": [ - "dep:value-bag" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "std", - "serde", - "kv_unstable_std", - "kv_unstable_sval", - "kv_unstable_serde" - ] - } - } - }, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "development-tools::debugging" - ], - "keywords": [ - "logging" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang/log", - "homepage": null, - "documentation": "https://docs.rs/log", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "memchr", - "version": "2.5.0", - "id": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "Safe interface to memchr.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.18", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quickcheck", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "memchr", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "default": [ - "std" - ], - "libc": [ - "dep:libc" - ], - "rustc-dep-of-std": [ - "core", - "compiler_builtins" - ], - "std": [], - "use_std": [ - "std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant ", - "bluss" - ], - "categories": [], - "keywords": [ - "memchr", - "char", - "scan", - "strchr", - "string" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/memchr", - "homepage": "https://github.com/BurntSushi/memchr", - "documentation": "https://docs.rs/memchr/", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "memmap2", - "version": "0.5.10", - "id": "memmap2 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Cross-platform Rust API for memory-mapped file IO", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "stable_deref_trait", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "owning_ref", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tempfile", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(unix)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "memmap2", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap2-0.5.10/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "cat", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap2-0.5.10/examples/cat.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "stable_deref_trait": [ - "dep:stable_deref_trait" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap2-0.5.10/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Dan Burkert ", - "Yevhenii Reizner " - ], - "categories": [], - "keywords": [ - "mmap", - "memory-map", - "io", - "file" - ], - "readme": "README.md", - "repository": "https://github.com/RazrFalcon/memmap2-rs", - "homepage": null, - "documentation": "https://docs.rs/memmap2", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "once_cell", - "version": "1.17.1", - "id": "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Single assignment cells and lazy values.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "atomic-polyfill", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": "atomic_polyfill", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "critical-section", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": "critical_section", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "parking_lot_core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.9.3", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "critical-section", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.1", - "kind": "dev", - "rename": "critical_section", - "optional": false, - "uses_default_features": true, - "features": [ - "std" - ], - "target": null, - "registry": null - }, - { - "name": "crossbeam-utils", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8.7", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.2.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "once_cell", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/bench.rs", - "edition": "2021", - "required-features": [ - "std" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "bench_acquire", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/bench_acquire.rs", - "edition": "2021", - "required-features": [ - "std" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "bench_vs_lazy_static", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/bench_vs_lazy_static.rs", - "edition": "2021", - "required-features": [ - "std" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "lazy_static", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/lazy_static.rs", - "edition": "2021", - "required-features": [ - "std" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "reentrant_init_deadlocks", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/reentrant_init_deadlocks.rs", - "edition": "2021", - "required-features": [ - "std" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "regex", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/regex.rs", - "edition": "2021", - "required-features": [ - "std" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "test_synchronization", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/test_synchronization.rs", - "edition": "2021", - "required-features": [ - "std" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "it", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/tests/it.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "alloc": [ - "race" - ], - "atomic-polyfill": [ - "critical-section" - ], - "atomic_polyfill": [ - "dep:atomic_polyfill" - ], - "critical-section": [ - "critical_section", - "atomic_polyfill" - ], - "critical_section": [ - "dep:critical_section" - ], - "default": [ - "std" - ], - "parking_lot": [ - "parking_lot_core" - ], - "parking_lot_core": [ - "dep:parking_lot_core" - ], - "race": [], - "std": [ - "alloc" - ], - "unstable": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true - } - } - }, - "publish": null, - "authors": [ - "Aleksey Kladov " - ], - "categories": [ - "rust-patterns", - "memory-management" - ], - "keywords": [ - "lazy", - "static" - ], - "readme": "README.md", - "repository": "https://github.com/matklad/once_cell", - "homepage": null, - "documentation": "https://docs.rs/once_cell", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.56" - }, - { - "name": "pcre2", - "version": "0.2.3", - "id": "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "High level wrapper library for PCRE2.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.46", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "pcre2-sys", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "thread_local", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "pcre2", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-0.2.3/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-0.2.3/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "text-processing" - ], - "keywords": [ - "pcre", - "pcre2", - "regex", - "jit", - "perl" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/rust-pcre2", - "homepage": "https://github.com/BurntSushi/rust-pcre2", - "documentation": "https://docs.rs/pcre2", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "pcre2-sys", - "version": "0.2.5", - "id": "pcre2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "Low level bindings to PCRE2.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "cc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "build", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "parallel" - ], - "target": null, - "registry": null - }, - { - "name": "pkg-config", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.13", - "kind": "build", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "pcre2-sys", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-sys-0.2.5/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-sys-0.2.5/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-sys-0.2.5/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "external-ffi-bindings" - ], - "keywords": [ - "pcre", - "pcre2", - "regex", - "jit" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/rust-pcre2", - "homepage": "https://github.com/BurntSushi/rust-pcre2", - "documentation": "https://docs.rs/pcre2-sys", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "pkg-config", - "version": "0.3.26", - "id": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A library to run the pkg-config system tool at build time in order to be used in\nCargo build scripts.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "pkg-config", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/tests/test.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Alex Crichton " - ], - "categories": [], - "keywords": [ - "build-dependencies" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang/pkg-config-rs", - "homepage": null, - "documentation": "https://docs.rs/pkg-config", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "proc-macro2", - "version": "1.0.56", - "id": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "unicode-ident", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quote", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "proc-macro2", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "comments", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/comments.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "features", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/features.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "marker", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/marker.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_fmt", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test_fmt.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_size", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test_size.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "proc-macro" - ], - "nightly": [], - "proc-macro": [], - "span-locations": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "rustc-args": [ - "--cfg", - "procmacro2_semver_exempt" - ], - "rustdoc-args": [ - "--cfg", - "procmacro2_semver_exempt", - "--cfg", - "doc_cfg" - ], - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - }, - "playground": { - "features": [ - "span-locations" - ] - } - }, - "publish": null, - "authors": [ - "David Tolnay ", - "Alex Crichton " - ], - "categories": [ - "development-tools::procedural-macro-helpers" - ], - "keywords": [ - "macros", - "syn" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/proc-macro2", - "homepage": null, - "documentation": "https://docs.rs/proc-macro2", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.31" - }, - { - "name": "quote", - "version": "1.0.26", - "id": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Quasi-quoting macro quote!(...)", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "proc-macro2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.52", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "trybuild", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.66", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "diff" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "quote", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "compiletest", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/tests/compiletest.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/tests/test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "proc-macro" - ], - "proc-macro": [ - "proc-macro2/proc-macro" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - } - }, - "publish": null, - "authors": [ - "David Tolnay " - ], - "categories": [ - "development-tools::procedural-macro-helpers" - ], - "keywords": [ - "macros", - "syn" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/quote", - "homepage": null, - "documentation": "https://docs.rs/quote/", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.31" - }, - { - "name": "regex", - "version": "1.8.1", - "id": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "An implementation of regular expressions for Rust. This implementation uses\nfinite automata and guarantees linear time matching on all inputs.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "aho-corasick", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "memchr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.5.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex-syntax", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.7.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quickcheck", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "getrandom", - "small_rng" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "regex", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": false, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-cheat", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-cheat.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-replace", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-replace.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-single-cheat", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-single-cheat.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna-single", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-single.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "shootout-regex-dna", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "default", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_default.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "default-bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_default_bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa-utf8bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa_utf8bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "nfa-bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa_bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack-utf8bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack_utf8bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "backtrack-bytes", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack_bytes.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "crates-regex", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_crates_regex.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "aho-corasick": [ - "dep:aho-corasick" - ], - "default": [ - "std", - "perf", - "unicode", - "regex-syntax/default" - ], - "memchr": [ - "dep:memchr" - ], - "pattern": [], - "perf": [ - "perf-cache", - "perf-dfa", - "perf-inline", - "perf-literal" - ], - "perf-cache": [], - "perf-dfa": [], - "perf-inline": [], - "perf-literal": [ - "aho-corasick", - "memchr" - ], - "std": [], - "unicode": [ - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment", - "regex-syntax/unicode" - ], - "unicode-age": [ - "regex-syntax/unicode-age" - ], - "unicode-bool": [ - "regex-syntax/unicode-bool" - ], - "unicode-case": [ - "regex-syntax/unicode-case" - ], - "unicode-gencat": [ - "regex-syntax/unicode-gencat" - ], - "unicode-perl": [ - "regex-syntax/unicode-perl" - ], - "unicode-script": [ - "regex-syntax/unicode-script" - ], - "unicode-segment": [ - "regex-syntax/unicode-segment" - ], - "unstable": [ - "pattern" - ], - "use_std": [ - "std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "text-processing" - ], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.60.0" - }, - { - "name": "regex-automata", - "version": "0.1.10", - "id": "regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "Automata construction and matching using regular expressions.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "fst", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex-syntax", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.6.16", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "bstr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "std" - ], - "target": null, - "registry": null - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.2.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.82", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_bytes", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.11", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.82", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "toml", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.10", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "regex-automata", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-automata-0.1.10/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "default", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-automata-0.1.10/tests/tests.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": { - "default": [ - "std" - ], - "fst": [ - "dep:fst" - ], - "regex-syntax": [ - "dep:regex-syntax" - ], - "std": [ - "regex-syntax" - ], - "transducer": [ - "std", - "fst" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-automata-0.1.10/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "text-processing" - ], - "keywords": [ - "regex", - "dfa", - "automata", - "automaton", - "nfa" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/regex-automata", - "homepage": "https://github.com/BurntSushi/regex-automata", - "documentation": "https://docs.rs/regex-automata", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "regex-syntax", - "version": "0.6.29", - "id": "regex-syntax 0.6.29 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A regular expression parser.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "regex-syntax", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.6.29/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.6.29/benches/bench.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "unicode" - ], - "unicode": [ - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ], - "unicode-age": [], - "unicode-bool": [], - "unicode-case": [], - "unicode-gencat": [], - "unicode-perl": [], - "unicode-script": [], - "unicode-segment": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.6.29/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex-syntax", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "regex-syntax", - "version": "0.7.1", - "id": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A regular expression parser.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "regex-syntax", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/benches/bench.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [ - "std", - "unicode" - ], - "std": [], - "unicode": [ - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ], - "unicode-age": [], - "unicode-bool": [], - "unicode-case": [], - "unicode-gencat": [], - "unicode-perl": [], - "unicode-script": [], - "unicode-segment": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true, - "rustdoc-args": [ - "--cfg", - "docsrs" - ] - } - } - }, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [], - "keywords": [], - "readme": "README.md", - "repository": "https://github.com/rust-lang/regex", - "homepage": "https://github.com/rust-lang/regex", - "documentation": "https://docs.rs/regex-syntax", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.60.0" - }, - { - "name": "ripgrep", - "version": "13.0.0", - "id": "ripgrep 13.0.0 (path+file:///$ROOT$ripgrep)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "ripgrep is a line-oriented search tool that recursively searches the current\ndirectory for a regex pattern while respecting gitignore rules. ripgrep has\nfirst class support on Windows, macOS and Linux.\n", - "source": null, - "dependencies": [ - { - "name": "bstr", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "clap", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.33.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "suggestions" - ], - "target": null, - "registry": null - }, - { - "name": "grep", - "source": null, - "req": "^0.2.11", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/grep" - }, - { - "name": "ignore", - "source": null, - "req": "^0.4.19", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$ripgrep/crates/ignore" - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "log", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.3.5", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_json", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.23", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "termcolor", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.77", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.77", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "walkdir", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "clap", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.33.0", - "kind": "build", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [ - "suggestions" - ], - "target": null, - "registry": null - }, - { - "name": "lazy_static", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.1.0", - "kind": "build", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "jemallocator", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.5.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(all(target_env = \"musl\", target_pointer_width = \"64\"))", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "bin" - ], - "crate_types": [ - "bin" - ], - "name": "rg", - "src_path": "$ROOT$ripgrep/crates/core/main.rs", - "edition": "2018", - "doc": true, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "integration", - "src_path": "$ROOT$ripgrep/tests/tests.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$ripgrep/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "pcre2": [ - "grep/pcre2" - ], - "simd-accel": [ - "grep/simd-accel" - ] - }, - "manifest_path": "$ROOT$ripgrep/Cargo.toml", - "metadata": { - "deb": { - "assets": [ - [ - "target/release/rg", - "usr/bin/", - "755" - ], - [ - "COPYING", - "usr/share/doc/ripgrep/", - "644" - ], - [ - "LICENSE-MIT", - "usr/share/doc/ripgrep/", - "644" - ], - [ - "UNLICENSE", - "usr/share/doc/ripgrep/", - "644" - ], - [ - "CHANGELOG.md", - "usr/share/doc/ripgrep/CHANGELOG", - "644" - ], - [ - "README.md", - "usr/share/doc/ripgrep/README", - "644" - ], - [ - "FAQ.md", - "usr/share/doc/ripgrep/FAQ", - "644" - ], - [ - "deployment/deb/rg.1", - "usr/share/man/man1/rg.1", - "644" - ], - [ - "deployment/deb/rg.bash", - "usr/share/bash-completion/completions/rg", - "644" - ], - [ - "deployment/deb/rg.fish", - "usr/share/fish/vendor_completions.d/rg.fish", - "644" - ], - [ - "deployment/deb/_rg", - "usr/share/zsh/vendor-completions/", - "644" - ] - ], - "extended-description": "ripgrep (rg) recursively searches your current directory for a regex pattern.\nBy default, ripgrep will respect your .gitignore and automatically skip hidden\nfiles/directories and binary files.\n", - "features": [ - "pcre2" - ], - "section": "utils" - } - }, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "command-line-utilities", - "text-processing" - ], - "keywords": [ - "regex", - "grep", - "egrep", - "search", - "pattern" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/ripgrep", - "homepage": "https://github.com/BurntSushi/ripgrep", - "documentation": "https://github.com/BurntSushi/ripgrep", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.65" - }, - { - "name": "ryu", - "version": "1.0.13", - "id": "ryu 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Apache-2.0 OR BSL-1.0", - "license_file": null, - "description": "Fast floating point to string conversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "no-panic", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "num_cpus", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.8", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand_xorshift", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "ryu", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "upstream_benchmark", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/examples/upstream_benchmark.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "common_test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/common_test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "d2s_table_test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/d2s_table_test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "d2s_test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/d2s_test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "exhaustive", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/exhaustive.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "f2s_test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/f2s_test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "s2d_test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/s2d_test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "s2f_test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/s2f_test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "bench", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/benches/bench.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "no-panic": [ - "dep:no-panic" - ], - "small": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - } - }, - "publish": null, - "authors": [ - "David Tolnay " - ], - "categories": [ - "value-formatting", - "no-std" - ], - "keywords": [ - "float" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/ryu", - "homepage": null, - "documentation": "https://docs.rs/ryu", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.36" - }, - { - "name": "same-file", - "version": "1.0.6", - "id": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "A simple crate for determining whether two file paths point to the same file.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "doc-comment", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "winapi-util", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(windows)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "same-file", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/same-file-1.0.6/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "is_same_file", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/same-file-1.0.6/examples/is_same_file.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "is_stderr", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/same-file-1.0.6/examples/is_stderr.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/same-file-1.0.6/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "same", - "file", - "equal", - "inode" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/same-file", - "homepage": "https://github.com/BurntSushi/same-file", - "documentation": "https://docs.rs/same-file", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "serde", - "version": "1.0.160", - "id": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A generic serialization/deserialization framework", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "=1.0.160", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "serde", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "alloc": [], - "default": [ - "std" - ], - "derive": [ - "serde_derive" - ], - "rc": [], - "serde_derive": [ - "dep:serde_derive" - ], - "std": [], - "unstable": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "derive" - ], - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - }, - "playground": { - "features": [ - "derive", - "rc" - ] - } - }, - "publish": null, - "authors": [ - "Erick Tryzelaar ", - "David Tolnay " - ], - "categories": [ - "encoding", - "no-std" - ], - "keywords": [ - "serde", - "serialization", - "no_std" - ], - "readme": "crates-io.md", - "repository": "https://github.com/serde-rs/serde", - "homepage": "https://serde.rs", - "documentation": "https://docs.rs/serde", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": "1.19" - }, - { - "name": "serde_derive", - "version": "1.0.160", - "id": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "proc-macro2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quote", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "syn", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.0.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "proc-macro" - ], - "crate_types": [ - "proc-macro" - ], - "name": "serde_derive", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "default": [], - "deserialize_in_place": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - } - }, - "publish": null, - "authors": [ - "Erick Tryzelaar ", - "David Tolnay " - ], - "categories": [ - "no-std" - ], - "keywords": [ - "serde", - "serialization", - "no_std", - "derive" - ], - "readme": "crates-io.md", - "repository": "https://github.com/serde-rs/serde", - "homepage": "https://serde.rs", - "documentation": "https://serde.rs/derive.html", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": "1.56" - }, - { - "name": "serde_json", - "version": "1.0.96", - "id": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "A JSON serialization file format", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "indexmap", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.5.2", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [ - "std" - ], - "target": null, - "registry": null - }, - { - "name": "itoa", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "ryu", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.100", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "automod", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "indoc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "ref-cast", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.100", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "derive" - ], - "target": null, - "registry": null - }, - { - "name": "serde_bytes", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.11", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_derive", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "serde_stacker", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "trybuild", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.49", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "diff" - ], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "serde_json", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "compiletest", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/compiletest.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "debug", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/debug.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "lexical", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/lexical.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "map", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/map.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "regression", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/regression.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "stream", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/stream.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/test.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/build.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "alloc": [ - "serde/alloc" - ], - "arbitrary_precision": [], - "default": [ - "std" - ], - "float_roundtrip": [], - "indexmap": [ - "dep:indexmap" - ], - "preserve_order": [ - "indexmap", - "std" - ], - "raw_value": [], - "std": [ - "serde/std" - ], - "unbounded_depth": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "features": [ - "raw_value", - "unbounded_depth" - ], - "rustdoc-args": [ - "--cfg", - "docsrs" - ], - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - }, - "playground": { - "features": [ - "raw_value" - ] - } - }, - "publish": null, - "authors": [ - "Erick Tryzelaar ", - "David Tolnay " - ], - "categories": [ - "encoding", - "parser-implementations", - "no-std" - ], - "keywords": [ - "json", - "serde", - "serialization" - ], - "readme": "README.md", - "repository": "https://github.com/serde-rs/json", - "homepage": null, - "documentation": "https://docs.rs/serde_json", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.36" - }, - { - "name": "strsim", - "version": "0.8.0", - "id": "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT", - "license_file": null, - "description": "Implementations of string similarity metrics.\nIncludes Hamming, Levenshtein, OSA, Damerau-Levenshtein, Jaro, and Jaro-Winkler.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "strsim", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.8.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "lib", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.8.0/tests/lib.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "benches", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.8.0/benches/benches.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.8.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Danny Guo " - ], - "categories": [], - "keywords": [ - "string", - "similarity", - "Hamming", - "Levenshtein", - "Jaro" - ], - "readme": "README.md", - "repository": "https://github.com/dguo/strsim-rs", - "homepage": "https://github.com/dguo/strsim-rs", - "documentation": "https://docs.rs/strsim/", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "syn", - "version": "2.0.15", - "id": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Parser for Rust source code", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "proc-macro2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.55", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "quote", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.25", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "unicode-ident", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "anyhow", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "automod", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "flate2", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "insta", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rayon", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "ref-cast", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "regex", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "reqwest", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.11", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "blocking" - ], - "target": null, - "registry": null - }, - { - "name": "rustversion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "syn-test-suite", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "tar", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.16", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "termcolor", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "walkdir", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^2.3.2", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "syn", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "regression", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/regression.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_asyncness", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_asyncness.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_attribute", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_attribute.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_derive_input", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_derive_input.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_expr", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_expr.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_generics", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_generics.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_grouping", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_grouping.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_ident", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_ident.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_item", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_item.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_iterators", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_iterators.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_lit", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_lit.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_meta", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_meta.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_parse_buffer", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_parse_buffer.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_parse_stream", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_parse_stream.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_pat", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_pat.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_path", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_path.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_precedence", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_precedence.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_receiver", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_receiver.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_round_trip", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_round_trip.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_shebang", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_shebang.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_should_parse", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_should_parse.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_size", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_size.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_stmt", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_stmt.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_token_trees", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_token_trees.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_ty", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_ty.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "test_visibility", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_visibility.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "zzz_stable", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/zzz_stable.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "rust", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/benches/rust.rs", - "edition": "2021", - "required-features": [ - "full", - "parsing" - ], - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "file", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/benches/file.rs", - "edition": "2021", - "required-features": [ - "full", - "parsing" - ], - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "clone-impls": [], - "default": [ - "derive", - "parsing", - "printing", - "clone-impls", - "proc-macro" - ], - "derive": [], - "extra-traits": [], - "fold": [], - "full": [], - "parsing": [], - "printing": [ - "quote" - ], - "proc-macro": [ - "proc-macro2/proc-macro", - "quote/proc-macro" - ], - "quote": [ - "dep:quote" - ], - "test": [ - "syn-test-suite/all-features" - ], - "visit": [], - "visit-mut": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true, - "rustdoc-args": [ - "--cfg", - "doc_cfg" - ], - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - }, - "playground": { - "features": [ - "full", - "visit", - "visit-mut", - "fold", - "extra-traits" - ] - } - }, - "publish": null, - "authors": [ - "David Tolnay " - ], - "categories": [ - "development-tools::procedural-macro-helpers", - "parser-implementations" - ], - "keywords": [ - "macros", - "syn" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/syn", - "homepage": null, - "documentation": "https://docs.rs/syn", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": "1.56" - }, - { - "name": "termcolor", - "version": "1.2.0", - "id": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense OR MIT", - "license_file": null, - "description": "A simple cross platform library for writing colored text to a terminal.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "winapi-util", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(windows)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "termcolor", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/termcolor-1.2.0/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/termcolor-1.2.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [], - "keywords": [ - "windows", - "win", - "color", - "ansi", - "console" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/termcolor", - "homepage": "https://github.com/BurntSushi/termcolor", - "documentation": "https://docs.rs/termcolor", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "textwrap", - "version": "0.11.0", - "id": "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT", - "license_file": null, - "description": "Textwrap is a small library for word wrapping, indenting, and\ndedenting strings.\n\nYou can use it to format strings (such as help and error messages) for\ndisplay in commandline applications. It is designed to be efficient\nand handle Unicode characters correctly.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "hyphenation", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.7.1", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [ - "embed_all" - ], - "target": null, - "registry": null - }, - { - "name": "term_size", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "unicode-width", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "lipsum", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.6", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.6", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand_xorshift", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "version-sync", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.6", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "textwrap", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "layout", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/examples/layout.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "termwidth", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/examples/termwidth.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "version-numbers", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/tests/version-numbers.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "linear", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/benches/linear.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "hyphenation": [ - "dep:hyphenation" - ], - "term_size": [ - "dep:term_size" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "all-features": true - } - } - }, - "publish": null, - "authors": [ - "Martin Geisler " - ], - "categories": [ - "text-processing", - "command-line-interface" - ], - "keywords": [ - "text", - "formatting", - "wrap", - "typesetting", - "hyphenation" - ], - "readme": "README.md", - "repository": "https://github.com/mgeisler/textwrap", - "homepage": null, - "documentation": "https://docs.rs/textwrap/", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "thread_local", - "version": "1.1.7", - "id": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Per-object thread-local storage", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "cfg-if", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "once_cell", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.5.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "criterion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4.0", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "thread_local", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/thread_local-1.1.7/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "thread_local", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/thread_local-1.1.7/benches/thread_local.rs", - "edition": "2021", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "nightly": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/thread_local-1.1.7/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Amanieu d'Antras " - ], - "categories": [], - "keywords": [ - "thread_local", - "concurrent", - "thread" - ], - "readme": "README.md", - "repository": "https://github.com/Amanieu/thread_local-rs", - "homepage": null, - "documentation": "https://docs.rs/thread_local/", - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "unicode-ident", - "version": "1.0.8", - "id": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "(MIT OR Apache-2.0) AND Unicode-DFS-2016", - "license_file": null, - "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "criterion", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "fst", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rand", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.8", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "small_rng" - ], - "target": null, - "registry": null - }, - { - "name": "roaring", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.10", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "ucd-trie", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": false, - "features": [], - "target": null, - "registry": null - }, - { - "name": "unicode-xid", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2.4", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "unicode-ident", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "compare", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/tests/compare.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "static_size", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/tests/static_size.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "bench" - ], - "crate_types": [ - "bin" - ], - "name": "xid", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/benches/xid.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-unknown-linux-gnu" - ] - } - } - }, - "publish": null, - "authors": [ - "David Tolnay " - ], - "categories": [ - "development-tools::procedural-macro-helpers", - "no-std" - ], - "keywords": [ - "unicode", - "xid" - ], - "readme": "README.md", - "repository": "https://github.com/dtolnay/unicode-ident", - "homepage": null, - "documentation": "https://docs.rs/unicode-ident", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": "1.31" - }, - { - "name": "unicode-width", - "version": "0.1.10", - "id": "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Determine displayed width of `char` and `str` types\naccording to Unicode Standard Annex #11 rules.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "compiler_builtins", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": "core", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "rustc-std-workspace-std", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0", - "kind": null, - "rename": "std", - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "unicode-width", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-width-0.1.10/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": { - "bench": [], - "compiler_builtins": [ - "dep:compiler_builtins" - ], - "core": [ - "dep:core" - ], - "default": [], - "no_std": [], - "rustc-dep-of-std": [ - "std", - "core", - "compiler_builtins" - ], - "std": [ - "dep:std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-width-0.1.10/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "kwantam ", - "Manish Goregaokar " - ], - "categories": [], - "keywords": [ - "text", - "width", - "unicode" - ], - "readme": "README.md", - "repository": "https://github.com/unicode-rs/unicode-width", - "homepage": "https://github.com/unicode-rs/unicode-width", - "documentation": "https://unicode-rs.github.io/unicode-width", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "walkdir", - "version": "2.3.3", - "id": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "Recursively walk a directory.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "same-file", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "doc-comment", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - }, - { - "name": "winapi-util", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.1.1", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "cfg(windows)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "walkdir", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/walkdir-2.3.3/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/walkdir-2.3.3/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "filesystem" - ], - "keywords": [ - "directory", - "recursive", - "walk", - "iterator" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/walkdir", - "homepage": "https://github.com/BurntSushi/walkdir", - "documentation": "https://docs.rs/walkdir/", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "winapi", - "version": "0.3.9", - "id": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Raw FFI bindings for all of Windows API.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "winapi-i686-pc-windows-gnu", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "i686-pc-windows-gnu", - "registry": null - }, - { - "name": "winapi-x86_64-pc-windows-gnu", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.4", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": "x86_64-pc-windows-gnu", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "winapi", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "accctrl": [], - "aclapi": [], - "activation": [], - "adhoc": [], - "appmgmt": [], - "audioclient": [], - "audiosessiontypes": [], - "avrt": [], - "basetsd": [], - "bcrypt": [], - "bits": [], - "bits10_1": [], - "bits1_5": [], - "bits2_0": [], - "bits2_5": [], - "bits3_0": [], - "bits4_0": [], - "bits5_0": [], - "bitscfg": [], - "bitsmsg": [], - "bluetoothapis": [], - "bluetoothleapis": [], - "bthdef": [], - "bthioctl": [], - "bthledef": [], - "bthsdpdef": [], - "bugcodes": [], - "cderr": [], - "cfg": [], - "cfgmgr32": [], - "cguid": [], - "combaseapi": [], - "coml2api": [], - "commapi": [], - "commctrl": [], - "commdlg": [], - "commoncontrols": [], - "consoleapi": [], - "corecrt": [], - "corsym": [], - "d2d1": [], - "d2d1_1": [], - "d2d1_2": [], - "d2d1_3": [], - "d2d1effectauthor": [], - "d2d1effects": [], - "d2d1effects_1": [], - "d2d1effects_2": [], - "d2d1svg": [], - "d2dbasetypes": [], - "d3d": [], - "d3d10": [], - "d3d10_1": [], - "d3d10_1shader": [], - "d3d10effect": [], - "d3d10misc": [], - "d3d10sdklayers": [], - "d3d10shader": [], - "d3d11": [], - "d3d11_1": [], - "d3d11_2": [], - "d3d11_3": [], - "d3d11_4": [], - "d3d11on12": [], - "d3d11sdklayers": [], - "d3d11shader": [], - "d3d11tokenizedprogramformat": [], - "d3d12": [], - "d3d12sdklayers": [], - "d3d12shader": [], - "d3d9": [], - "d3d9caps": [], - "d3d9types": [], - "d3dcommon": [], - "d3dcompiler": [], - "d3dcsx": [], - "d3dkmdt": [], - "d3dkmthk": [], - "d3dukmdt": [], - "d3dx10core": [], - "d3dx10math": [], - "d3dx10mesh": [], - "datetimeapi": [], - "davclnt": [], - "dbghelp": [], - "dbt": [], - "dcommon": [], - "dcomp": [], - "dcompanimation": [], - "dcomptypes": [], - "dde": [], - "ddraw": [], - "ddrawi": [], - "ddrawint": [], - "debug": [ - "impl-debug" - ], - "debugapi": [], - "devguid": [], - "devicetopology": [], - "devpkey": [], - "devpropdef": [], - "dinput": [], - "dinputd": [], - "dispex": [], - "dmksctl": [], - "dmusicc": [], - "docobj": [], - "documenttarget": [], - "dot1x": [], - "dpa_dsa": [], - "dpapi": [], - "dsgetdc": [], - "dsound": [], - "dsrole": [], - "dvp": [], - "dwmapi": [], - "dwrite": [], - "dwrite_1": [], - "dwrite_2": [], - "dwrite_3": [], - "dxdiag": [], - "dxfile": [], - "dxgi": [], - "dxgi1_2": [], - "dxgi1_3": [], - "dxgi1_4": [], - "dxgi1_5": [], - "dxgi1_6": [], - "dxgidebug": [], - "dxgiformat": [], - "dxgitype": [], - "dxva2api": [], - "dxvahd": [], - "eaptypes": [], - "enclaveapi": [], - "endpointvolume": [], - "errhandlingapi": [], - "everything": [], - "evntcons": [], - "evntprov": [], - "evntrace": [], - "excpt": [], - "exdisp": [], - "fibersapi": [], - "fileapi": [], - "functiondiscoverykeys_devpkey": [], - "gl-gl": [], - "guiddef": [], - "handleapi": [], - "heapapi": [], - "hidclass": [], - "hidpi": [], - "hidsdi": [], - "hidusage": [], - "highlevelmonitorconfigurationapi": [], - "hstring": [], - "http": [], - "ifdef": [], - "ifmib": [], - "imm": [], - "impl-debug": [], - "impl-default": [], - "in6addr": [], - "inaddr": [], - "inspectable": [], - "interlockedapi": [], - "intsafe": [], - "ioapiset": [], - "ipexport": [], - "iphlpapi": [], - "ipifcons": [], - "ipmib": [], - "iprtrmib": [], - "iptypes": [], - "jobapi": [], - "jobapi2": [], - "knownfolders": [], - "ks": [], - "ksmedia": [], - "ktmtypes": [], - "ktmw32": [], - "l2cmn": [], - "libloaderapi": [], - "limits": [], - "lmaccess": [], - "lmalert": [], - "lmapibuf": [], - "lmat": [], - "lmcons": [], - "lmdfs": [], - "lmerrlog": [], - "lmjoin": [], - "lmmsg": [], - "lmremutl": [], - "lmrepl": [], - "lmserver": [], - "lmshare": [], - "lmstats": [], - "lmsvc": [], - "lmuse": [], - "lmwksta": [], - "lowlevelmonitorconfigurationapi": [], - "lsalookup": [], - "memoryapi": [], - "minschannel": [], - "minwinbase": [], - "minwindef": [], - "mmdeviceapi": [], - "mmeapi": [], - "mmreg": [], - "mmsystem": [], - "mprapidef": [], - "msaatext": [], - "mscat": [], - "mschapp": [], - "mssip": [], - "mstcpip": [], - "mswsock": [], - "mswsockdef": [], - "namedpipeapi": [], - "namespaceapi": [], - "nb30": [], - "ncrypt": [], - "netioapi": [], - "nldef": [], - "ntddndis": [], - "ntddscsi": [], - "ntddser": [], - "ntdef": [], - "ntlsa": [], - "ntsecapi": [], - "ntstatus": [], - "oaidl": [], - "objbase": [], - "objidl": [], - "objidlbase": [], - "ocidl": [], - "ole2": [], - "oleauto": [], - "olectl": [], - "oleidl": [], - "opmapi": [], - "pdh": [], - "perflib": [], - "physicalmonitorenumerationapi": [], - "playsoundapi": [], - "portabledevice": [], - "portabledeviceapi": [], - "portabledevicetypes": [], - "powerbase": [], - "powersetting": [], - "powrprof": [], - "processenv": [], - "processsnapshot": [], - "processthreadsapi": [], - "processtopologyapi": [], - "profileapi": [], - "propidl": [], - "propkey": [], - "propkeydef": [], - "propsys": [], - "prsht": [], - "psapi": [], - "qos": [], - "realtimeapiset": [], - "reason": [], - "restartmanager": [], - "restrictederrorinfo": [], - "rmxfguid": [], - "roapi": [], - "robuffer": [], - "roerrorapi": [], - "rpc": [], - "rpcdce": [], - "rpcndr": [], - "rtinfo": [], - "sapi": [], - "sapi51": [], - "sapi53": [], - "sapiddk": [], - "sapiddk51": [], - "schannel": [], - "sddl": [], - "securityappcontainer": [], - "securitybaseapi": [], - "servprov": [], - "setupapi": [], - "shellapi": [], - "shellscalingapi": [], - "shlobj": [], - "shobjidl": [], - "shobjidl_core": [], - "shtypes": [], - "softpub": [], - "spapidef": [], - "spellcheck": [], - "sporder": [], - "sql": [], - "sqlext": [], - "sqltypes": [], - "sqlucode": [], - "sspi": [], - "std": [], - "stralign": [], - "stringapiset": [], - "strmif": [], - "subauth": [], - "synchapi": [], - "sysinfoapi": [], - "systemtopologyapi": [], - "taskschd": [], - "tcpestats": [], - "tcpmib": [], - "textstor": [], - "threadpoolapiset": [], - "threadpoollegacyapiset": [], - "timeapi": [], - "timezoneapi": [], - "tlhelp32": [], - "transportsettingcommon": [], - "tvout": [], - "udpmib": [], - "unknwnbase": [], - "urlhist": [], - "urlmon": [], - "usb": [], - "usbioctl": [], - "usbiodef": [], - "usbscan": [], - "usbspec": [], - "userenv": [], - "usp10": [], - "utilapiset": [], - "uxtheme": [], - "vadefs": [], - "vcruntime": [], - "vsbackup": [], - "vss": [], - "vsserror": [], - "vswriter": [], - "wbemads": [], - "wbemcli": [], - "wbemdisp": [], - "wbemprov": [], - "wbemtran": [], - "wct": [], - "werapi": [], - "winbase": [], - "wincodec": [], - "wincodecsdk": [], - "wincon": [], - "wincontypes": [], - "wincred": [], - "wincrypt": [], - "windef": [], - "windot11": [], - "windowsceip": [], - "windowsx": [], - "winefs": [], - "winerror": [], - "winevt": [], - "wingdi": [], - "winhttp": [], - "wininet": [], - "winineti": [], - "winioctl": [], - "winnetwk": [], - "winnls": [], - "winnt": [], - "winreg": [], - "winsafer": [], - "winscard": [], - "winsmcrd": [], - "winsock2": [], - "winspool": [], - "winstring": [], - "winsvc": [], - "wintrust": [], - "winusb": [], - "winusbio": [], - "winuser": [], - "winver": [], - "wlanapi": [], - "wlanihv": [], - "wlanihvtypes": [], - "wlantypes": [], - "wlclient": [], - "wmistr": [], - "wnnc": [], - "wow64apiset": [], - "wpdmtpextensions": [], - "ws2bth": [], - "ws2def": [], - "ws2ipdef": [], - "ws2spi": [], - "ws2tcpip": [], - "wtsapi32": [], - "wtypes": [], - "wtypesbase": [], - "xinput": [] - }, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "default-target": "x86_64-pc-windows-msvc", - "features": [ - "everything", - "impl-debug", - "impl-default" - ], - "targets": [ - "aarch64-pc-windows-msvc", - "i686-pc-windows-msvc", - "x86_64-pc-windows-msvc" - ] - } - } - }, - "publish": null, - "authors": [ - "Peter Atashian " - ], - "categories": [ - "external-ffi-bindings", - "no-std", - "os::windows-apis" - ], - "keywords": [ - "windows", - "ffi", - "win32", - "com", - "directx" - ], - "readme": "README.md", - "repository": "https://github.com/retep998/winapi-rs", - "homepage": null, - "documentation": "https://docs.rs/winapi/", - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "winapi-i686-pc-windows-gnu", - "version": "0.4.0", - "id": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Import libraries for the i686-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "winapi-i686-pc-windows-gnu", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Peter Atashian " - ], - "categories": [], - "keywords": [ - "windows" - ], - "readme": null, - "repository": "https://github.com/retep998/winapi-rs", - "homepage": null, - "documentation": null, - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "winapi-util", - "version": "0.1.5", - "id": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "Unlicense/MIT", - "license_file": null, - "description": "A dumping ground for high level safe wrappers over winapi.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "winapi", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.3", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [ - "std", - "consoleapi", - "errhandlingapi", - "fileapi", - "minwindef", - "processenv", - "winbase", - "wincon", - "winerror", - "winnt" - ], - "target": "cfg(windows)", - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "winapi-util", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-util-0.1.5/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-util-0.1.5/Cargo.toml", - "metadata": { - "docs": { - "rs": { - "targets": [ - "x86_64-pc-windows-msvc" - ] - } - } - }, - "publish": null, - "authors": [ - "Andrew Gallant " - ], - "categories": [ - "os::windows-apis", - "external-ffi-bindings" - ], - "keywords": [ - "windows", - "winapi", - "util", - "win" - ], - "readme": "README.md", - "repository": "https://github.com/BurntSushi/winapi-util", - "homepage": "https://github.com/BurntSushi/winapi-util", - "documentation": "https://docs.rs/winapi-util", - "edition": "2018", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "winapi-x86_64-pc-windows-gnu", - "version": "0.4.0", - "id": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT/Apache-2.0", - "license_file": null, - "description": "Import libraries for the x86_64-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "winapi-x86_64-pc-windows-gnu", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": {}, - "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "Peter Atashian " - ], - "categories": [], - "keywords": [ - "windows" - ], - "readme": null, - "repository": "https://github.com/retep998/winapi-rs", - "homepage": null, - "documentation": null, - "edition": "2015", - "links": null, - "default_run": null, - "rust_version": null - } - ], - "workspace_members": [ - "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", - "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", - "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", - "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "grep-pcre2 0.1.6 (path+file:///$ROOT$ripgrep/crates/pcre2)", - "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", - "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", - "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", - "ripgrep 13.0.0 (path+file:///$ROOT$ripgrep)" - ], - "resolve": { - "nodes": [ - { - "id": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "memchr", - "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "std" - ] - }, - { - "id": "aho-corasick 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "memchr", - "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "perf-literal", - "std" - ] - }, - { - "id": "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "hermit_abi", - "pkg": "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(target_os = \"hermit\")" - } - ] - }, - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(unix)" - } - ] - }, - { - "name": "winapi", - "pkg": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(windows)" - } - ] - } - ], - "features": [] - }, - { - "id": "base64 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "std" - ] - }, - { - "id": "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default" - ] - }, - { - "id": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "memchr", - "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "once_cell", - "pkg": "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex_automata", - "pkg": "regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde", - "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "alloc", - "default", - "std", - "unicode" - ] - }, - { - "id": "bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "runtime-dispatch-simd" - ] - }, - { - "id": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "jobserver 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "jobserver", - "pkg": "jobserver 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "jobserver", - "parallel" - ] - }, - { - "id": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "bitflags", - "pkg": "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "strsim", - "pkg": "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "textwrap", - "pkg": "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "unicode_width", - "pkg": "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "strsim", - "suggestions" - ] - }, - { - "id": "crossbeam-channel 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cfg_if", - "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "crossbeam_utils", - "pkg": "crossbeam-utils 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "crossbeam-utils", - "default", - "std" - ] - }, - { - "id": "crossbeam-utils 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cfg_if", - "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "std" - ] - }, - { - "id": "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cfg_if", - "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "alloc", - "default" - ] - }, - { - "id": "encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "encoding_rs", - "pkg": "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "std" - ] - }, - { - "id": "glob 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", - "dependencies": [ - "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "aho_corasick", - "pkg": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "bstr", - "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "fnv", - "pkg": "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "glob", - "pkg": "glob 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "lazy_static", - "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "log", - "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde_json", - "pkg": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - } - ], - "features": [ - "default", - "log" - ] - }, - { - "id": "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", - "dependencies": [ - "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", - "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", - "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", - "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "grep_cli", - "pkg": "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_matcher", - "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_printer", - "pkg": "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_regex", - "pkg": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_searcher", - "pkg": "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "termcolor", - "pkg": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "walkdir", - "pkg": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", - "dependencies": [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "atty", - "pkg": "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "bstr", - "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "globset", - "pkg": "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "lazy_static", - "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "log", - "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "same_file", - "pkg": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "termcolor", - "pkg": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "winapi_util", - "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(windows)" - } - ] - } - ], - "features": [] - }, - { - "id": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "dependencies": [ - "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "memchr", - "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "grep-pcre2 0.1.6 (path+file:///$ROOT$ripgrep/crates/pcre2)", - "dependencies": [ - "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "grep_matcher", - "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "pcre2", - "pkg": "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", - "dependencies": [ - "base64 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", - "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "base64", - "pkg": "base64 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "bstr", - "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_matcher", - "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_regex", - "pkg": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "grep_searcher", - "pkg": "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde", - "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde_json", - "pkg": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "termcolor", - "pkg": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "base64", - "default", - "serde", - "serde1", - "serde_json" - ] - }, - { - "id": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "dependencies": [ - "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.29 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "aho_corasick", - "pkg": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "bstr", - "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_matcher", - "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "log", - "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex_syntax", - "pkg": "regex-syntax 0.6.29 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "thread_local", - "pkg": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", - "dependencies": [ - "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap2 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "bstr", - "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "bytecount", - "pkg": "bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "encoding_rs", - "pkg": "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "encoding_rs_io", - "pkg": "encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_matcher", - "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "grep_regex", - "pkg": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "log", - "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "memmap", - "pkg": "memmap2 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - } - ], - "features": [ - "default" - ] - }, - { - "id": "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default" - ] - }, - { - "id": "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", - "dependencies": [ - "crossbeam-channel 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "crossbeam_channel", - "pkg": "crossbeam-channel 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "globset", - "pkg": "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "lazy_static", - "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "log", - "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "memchr", - "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "same_file", - "pkg": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "thread_local", - "pkg": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "walkdir", - "pkg": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "winapi_util", - "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(windows)" - } - ] - } - ], - "features": [] - }, - { - "id": "itoa 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "jemalloc-sys 0.5.3+5.3.0-patched (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cc", - "pkg": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "build", - "target": null - } - ] - }, - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "background_threads_runtime_support" - ] - }, - { - "id": "jemallocator 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "jemalloc-sys 0.5.3+5.3.0-patched (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "jemalloc_sys", - "pkg": "jemalloc-sys 0.5.3+5.3.0-patched (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "background_threads_runtime_support", - "default" - ] - }, - { - "id": "jobserver 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(unix)" - } - ] - } - ], - "features": [] - }, - { - "id": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "std" - ] - }, - { - "id": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cfg_if", - "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "std" - ] - }, - { - "id": "memmap2 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(unix)" - } - ] - } - ], - "features": [] - }, - { - "id": "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "alloc", - "default", - "race", - "std" - ] - }, - { - "id": "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "pcre2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "log", - "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "pcre2_sys", - "pkg": "pcre2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "thread_local", - "pkg": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "pcre2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cc", - "pkg": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "build", - "target": null - } - ] - }, - { - "name": "libc", - "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "pkg_config", - "pkg": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "build", - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "unicode_ident", - "pkg": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "proc-macro" - ] - }, - { - "id": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "proc_macro2", - "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "proc-macro" - ] - }, - { - "id": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "aho-corasick 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "aho_corasick", - "pkg": "aho-corasick 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "memchr", - "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex_syntax", - "pkg": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "aho-corasick", - "default", - "memchr", - "perf", - "perf-cache", - "perf-dfa", - "perf-inline", - "perf-literal", - "std", - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ] - }, - { - "id": "regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "regex-syntax 0.6.29 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ] - }, - { - "id": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "std", - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" - ] - }, - { - "id": "ripgrep 13.0.0 (path+file:///$ROOT$ripgrep)", - "dependencies": [ - "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)", - "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", - "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", - "jemallocator 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "bstr", - "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "clap", - "pkg": "clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - }, - { - "kind": "build", - "target": null - } - ] - }, - { - "name": "grep", - "pkg": "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "ignore", - "pkg": "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "jemallocator", - "pkg": "jemallocator 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(all(target_env = \"musl\", target_pointer_width = \"64\"))" - } - ] - }, - { - "name": "lazy_static", - "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - }, - { - "kind": "build", - "target": null - } - ] - }, - { - "name": "log", - "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "regex", - "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde", - "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "serde_derive", - "pkg": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - }, - { - "name": "serde_json", - "pkg": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "termcolor", - "pkg": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "walkdir", - "pkg": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": "dev", - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "ryu 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "winapi_util", - "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(windows)" - } - ] - } - ], - "features": [] - }, - { - "id": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "serde_derive", - "pkg": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "alloc", - "default", - "derive", - "serde_derive", - "std" - ] - }, - { - "id": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "proc_macro2", - "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "quote", - "pkg": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "syn", - "pkg": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default" - ] - }, - { - "id": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "itoa 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "itoa", - "pkg": "itoa 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "ryu", - "pkg": "ryu 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "serde", - "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "default", - "std" - ] - }, - { - "id": "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "proc_macro2", - "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "quote", - "pkg": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "unicode_ident", - "pkg": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [ - "clone-impls", - "default", - "derive", - "parsing", - "printing", - "proc-macro", - "quote" - ] - }, - { - "id": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "winapi_util", - "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(windows)" - } - ] - } - ], - "features": [] - }, - { - "id": "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "unicode_width", - "pkg": "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "cfg_if", - "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "once_cell", - "pkg": "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default" - ] - }, - { - "id": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "same_file", - "pkg": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - }, - { - "name": "winapi_util", - "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(windows)" - } - ] - } - ], - "features": [] - }, - { - "id": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "winapi_i686_pc_windows_gnu", - "pkg": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "i686-pc-windows-gnu" - } - ] - }, - { - "name": "winapi_x86_64_pc_windows_gnu", - "pkg": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "x86_64-pc-windows-gnu" - } - ] - } - ], - "features": [ - "consoleapi", - "errhandlingapi", - "fileapi", - "minwinbase", - "minwindef", - "processenv", - "std", - "winbase", - "wincon", - "winerror", - "winnt" - ] - }, - { - "id": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - }, - { - "id": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "winapi", - "pkg": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": "cfg(windows)" - } - ] - } - ], - "features": [] - }, - { - "id": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [] - } - ], - "root": "ripgrep 13.0.0 (path+file:///$ROOT$ripgrep)" - }, - "target_directory": "$ROOT$ripgrep/target", - "version": 1, - "workspace_root": "$ROOT$ripgrep", - "metadata": null -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index 21b481c1fa29e..41b42573f0821 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -82,6 +82,7 @@ fn actual_main() -> anyhow::Result { flags::RustAnalyzerCmd::Highlight(cmd) => cmd.run()?, flags::RustAnalyzerCmd::AnalysisStats(cmd) => cmd.run(verbosity)?, flags::RustAnalyzerCmd::Diagnostics(cmd) => cmd.run()?, + flags::RustAnalyzerCmd::UnresolvedReferences(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs index 5eb6ff664f665..a7ec5af89fcbf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs @@ -13,6 +13,7 @@ mod rustc_tests; mod scip; mod ssr; mod symbols; +mod unresolved_references; mod progress_report; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 44e56645ba3c3..e899e0e8eea5f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -64,6 +64,7 @@ impl flags::AnalysisStats { true => None, false => Some(RustLibSource::Discover), }, + all_targets: true, ..Default::default() }; let no_progress = &|_| (); @@ -77,7 +78,11 @@ impl flags::AnalysisStats { let metadata_time = db_load_sw.elapsed(); let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: !self.disable_build_scripts, - with_proc_macro_server: ProcMacroServerChoice::Sysroot, + with_proc_macro_server: if self.disable_proc_macros { + ProcMacroServerChoice::None + } else { + ProcMacroServerChoice::Sysroot + }, prefill_caches: false, }; @@ -339,6 +344,7 @@ impl flags::AnalysisStats { true => None, false => Some(RustLibSource::Discover), }, + all_targets: true, ..Default::default() }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index cdac0e5ef5cca..28f25975d64aa 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -24,8 +24,11 @@ impl flags::Diagnostics { handle.join() } fn run_(self) -> anyhow::Result<()> { - let cargo_config = - CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; + let cargo_config = CargoConfig { + sysroot: Some(RustLibSource::Discover), + all_targets: true, + ..Default::default() + }; let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv { let path = vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(p)); ProcMacroServerChoice::Explicit(path) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index 16d90de661ad1..73e71658d17c5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -124,6 +124,19 @@ xflags::xflags! { optional --proc-macro-srv path: PathBuf } + /// Report unresolved references + cmd unresolved-references { + /// Directory with Cargo.toml. + required path: PathBuf + + /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis. + optional --disable-build-scripts + /// Don't use expand proc macros. + optional --disable-proc-macros + /// Run a custom proc-macro-srv binary. + optional --proc-macro-srv path: PathBuf + } + cmd ssr { /// A structured search replace rule (`$a.foo($b) ==>> bar($a, $b)`) repeated rule: SsrRule @@ -181,6 +194,7 @@ pub enum RustAnalyzerCmd { RunTests(RunTests), RustcTests(RustcTests), Diagnostics(Diagnostics), + UnresolvedReferences(UnresolvedReferences), Ssr(Ssr), Search(Search), Lsif(Lsif), @@ -250,6 +264,15 @@ pub struct Diagnostics { pub proc_macro_srv: Option, } +#[derive(Debug)] +pub struct UnresolvedReferences { + pub path: PathBuf, + + pub disable_build_scripts: bool, + pub disable_proc_macros: bool, + pub proc_macro_srv: Option, +} + #[derive(Debug)] pub struct Ssr { pub rule: Vec, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs index 89fe712ced020..e4263a3f667c3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs @@ -273,10 +273,12 @@ impl LsifManager<'_> { impl flags::Lsif { pub fn run(self) -> anyhow::Result<()> { - eprintln!("Generating LSIF started..."); let now = Instant::now(); - let cargo_config = - &CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; + let cargo_config = &CargoConfig { + sysroot: Some(RustLibSource::Discover), + all_targets: true, + ..Default::default() + }; let no_progress = &|_| (); let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, @@ -285,6 +287,7 @@ impl flags::Lsif { }; let path = AbsPathBuf::assert_utf8(env::current_dir()?.join(self.path)); let root = ProjectManifest::discover_single(&path)?; + eprintln!("Generating LSIF for project at {root}"); let mut workspace = ProjectWorkspace::load(root, cargo_config, no_progress)?; let build_scripts = workspace.run_build_scripts(cargo_config, no_progress)?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs index 157ef43dd0a27..f90ebcfdb2e3e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs @@ -13,8 +13,11 @@ use crate::cli::{flags, full_name_of_item, Result}; impl flags::RunTests { pub fn run(self) -> Result<()> { - let cargo_config = - CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; + let cargo_config = CargoConfig { + sysroot: Some(RustLibSource::Discover), + all_targets: true, + ..Default::default() + }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 75efdfd7dd8fe..730f3c08abb5e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -67,8 +67,11 @@ impl Tester { path.push("ra-rustc-test.rs"); let tmp_file = AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).unwrap()).unwrap(); std::fs::write(&tmp_file, "")?; - let cargo_config = - CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; + let cargo_config = CargoConfig { + sysroot: Some(RustLibSource::Discover), + all_targets: true, + ..Default::default() + }; let sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env); let data_layout = target_data_layout::get( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index ceb8534fdf553..e9198977dea50 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -51,7 +51,7 @@ impl flags::Scip { // FIXME @alibektas : What happens to errors without logging? error!(?error_sink, "Config Error(s)"); } - let cargo_config = config.cargo(); + let cargo_config = config.cargo(None); let (db, vfs, _) = load_workspace_at( root.as_path().as_ref(), &cargo_config, @@ -142,7 +142,7 @@ impl flags::Scip { let mut symbol_roles = Default::default(); if let Some(def) = token.definition { - // if the the range of the def and the range of the token are the same, this must be the definition. + // if the range of the def and the range of the token are the same, this must be the definition. // they also must be in the same file. See https://github.com/rust-lang/rust-analyzer/pull/17988 if def.file_id == file_id && def.range == text_range { symbol_roles |= scip_types::SymbolRole::Definition as i32; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs index 3caa487988744..bdca800a0d68a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs @@ -10,8 +10,11 @@ use crate::cli::flags; impl flags::Ssr { pub fn run(self) -> anyhow::Result<()> { - let cargo_config = - CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; + let cargo_config = CargoConfig { + sysroot: Some(RustLibSource::Discover), + all_targets: true, + ..Default::default() + }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs new file mode 100644 index 0000000000000..986bd018b424d --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs @@ -0,0 +1,175 @@ +//! Reports references in code that the IDE layer cannot resolve. +use hir::{db::HirDatabase, AnyDiagnostic, Crate, HirFileIdExt as _, Module, Semantics}; +use ide::{AnalysisHost, RootDatabase, TextRange}; +use ide_db::{ + base_db::{SourceDatabase, SourceRootDatabase}, + defs::NameRefClass, + EditionedFileId, FxHashSet, LineIndexDatabase as _, +}; +use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; +use parser::SyntaxKind; +use syntax::{ast, AstNode, WalkEvent}; +use vfs::FileId; + +use crate::cli::flags; + +impl flags::UnresolvedReferences { + pub fn run(self) -> anyhow::Result<()> { + const STACK_SIZE: usize = 1024 * 1024 * 8; + + let handle = stdx::thread::Builder::new(stdx::thread::ThreadIntent::LatencySensitive) + .name("BIG_STACK_THREAD".into()) + .stack_size(STACK_SIZE) + .spawn(|| self.run_()) + .unwrap(); + + handle.join() + } + + fn run_(self) -> anyhow::Result<()> { + let root = + vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(&self.path)).normalize(); + let config = crate::config::Config::new( + root.clone(), + lsp_types::ClientCapabilities::default(), + vec![], + None, + ); + let cargo_config = config.cargo(None); + let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv { + let path = vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(p)); + ProcMacroServerChoice::Explicit(path) + } else { + ProcMacroServerChoice::Sysroot + }; + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: !self.disable_build_scripts, + with_proc_macro_server, + prefill_caches: false, + }; + let (db, vfs, _proc_macro) = + load_workspace_at(&self.path, &cargo_config, &load_cargo_config, &|_| {})?; + let host = AnalysisHost::with_database(db); + let db = host.raw_database(); + let sema = Semantics::new(db); + + let mut visited_files = FxHashSet::default(); + + let work = all_modules(db).into_iter().filter(|module| { + let file_id = module.definition_source_file_id(db).original_file(db); + let source_root = db.file_source_root(file_id.into()); + let source_root = db.source_root(source_root); + !source_root.is_library + }); + + for module in work { + let file_id = module.definition_source_file_id(db).original_file(db); + if !visited_files.contains(&file_id) { + let crate_name = + module.krate().display_name(db).as_deref().unwrap_or("unknown").to_owned(); + let file_path = vfs.file_path(file_id.into()); + eprintln!("processing crate: {crate_name}, module: {file_path}",); + + let line_index = db.line_index(file_id.into()); + let file_text = db.file_text(file_id.into()); + + for range in find_unresolved_references(db, &sema, file_id.into(), &module) { + let line_col = line_index.line_col(range.start()); + let line = line_col.line + 1; + let col = line_col.col + 1; + let text = &file_text[range]; + println!("{file_path}:{line}:{col}: {text}"); + } + + visited_files.insert(file_id); + } + } + + eprintln!(); + eprintln!("scan complete"); + + Ok(()) + } +} + +fn all_modules(db: &dyn HirDatabase) -> Vec { + let mut worklist: Vec<_> = + Crate::all(db).into_iter().map(|krate| krate.root_module()).collect(); + let mut modules = Vec::new(); + + while let Some(module) = worklist.pop() { + modules.push(module); + worklist.extend(module.children(db)); + } + + modules +} + +fn find_unresolved_references( + db: &RootDatabase, + sema: &Semantics<'_, RootDatabase>, + file_id: FileId, + module: &Module, +) -> Vec { + let mut unresolved_references = all_unresolved_references(sema, file_id); + + // remove unresolved references which are within inactive code + let mut diagnostics = Vec::new(); + module.diagnostics(db, &mut diagnostics, false); + for diagnostic in diagnostics { + let AnyDiagnostic::InactiveCode(inactive_code) = diagnostic else { + continue; + }; + + let node = inactive_code.node; + let range = node.map(|it| it.text_range()).original_node_file_range_rooted(db); + + if range.file_id != file_id { + continue; + } + + unresolved_references.retain(|r| !range.range.contains_range(*r)); + } + + unresolved_references +} + +fn all_unresolved_references( + sema: &Semantics<'_, RootDatabase>, + file_id: FileId, +) -> Vec { + let file_id = sema + .attach_first_edition(file_id) + .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); + let file = sema.parse(file_id); + let root = file.syntax(); + + let mut unresolved_references = Vec::new(); + for event in root.preorder() { + let WalkEvent::Enter(syntax) = event else { + continue; + }; + let Some(name_ref) = ast::NameRef::cast(syntax) else { + continue; + }; + let Some(descended_name_ref) = name_ref.syntax().first_token().and_then(|tok| { + sema.descend_into_macros_single_exact(tok).parent().and_then(ast::NameRef::cast) + }) else { + continue; + }; + + // if we can classify the name_ref, it's not unresolved + if NameRefClass::classify(sema, &descended_name_ref).is_some() { + continue; + } + + // if we couldn't classify it, but it's in an attr, ignore it. See #10935 + if descended_name_ref.syntax().ancestors().any(|it| it.kind() == SyntaxKind::ATTR) { + continue; + } + + // otherwise, it's unresolved + unresolved_references.push(name_ref.syntax().text_range()); + } + unresolved_references +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 2889af844b14e..4cc60695fe668 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -24,7 +24,8 @@ use ide_db::{ use itertools::Itertools; use paths::{Utf8Path, Utf8PathBuf}; use project_model::{ - CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource, + CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectJsonFromCommand, + ProjectManifest, RustLibSource, }; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; @@ -59,15 +60,13 @@ mod patch_old_style; // However, editor specific config, which the server doesn't know about, should // be specified directly in `package.json`. // -// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep +// To deprecate an option by replacing it with another name use `new_name` | `old_name` so that we keep // parsing the old name. config_data! { - /// Configs that apply on a workspace-wide scope. There are 3 levels on which a global configuration can be configured - // FIXME: 1. and 3. should be split, some configs do not make sense per project + /// Configs that apply on a workspace-wide scope. There are 2 levels on which a global configuration can be configured /// - /// 1. `rust-analyzer.toml` file under user's config directory (e.g ~/.config/rust-analyzer.toml) + /// 1. `rust-analyzer.toml` file under user's config directory (e.g ~/.config/rust-analyzer/rust-analyzer.toml) /// 2. Client's own configurations (e.g `settings.json` on VS Code) - /// 3. `rust-analyzer.toml` file located at the workspace root /// /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen by the nearest first principle. global: struct GlobalDefaultConfigData <- GlobalConfigInput -> { @@ -76,178 +75,9 @@ config_data! { /// How many worker threads to handle priming caches. The default `0` means to pick automatically. cachePriming_numThreads: NumThreads = NumThreads::Physical, - /// Pass `--all-targets` to cargo invocation. - cargo_allTargets: bool = true, - /// Automatically refresh project info via `cargo metadata` on - /// `Cargo.toml` or `.cargo/config.toml` changes. - pub(crate) cargo_autoreload: bool = true, - /// Run build scripts (`build.rs`) for more precise code analysis. - cargo_buildScripts_enable: bool = true, - /// Specifies the invocation strategy to use when running the build scripts command. - /// If `per_workspace` is set, the command will be executed for each Rust workspace with the - /// workspace as the working directory. - /// If `once` is set, the command will be executed once with the opened project as the - /// working directory. - /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` - /// is set. - cargo_buildScripts_invocationStrategy: InvocationStrategy = InvocationStrategy::PerWorkspace, - /// Override the command rust-analyzer uses to run build scripts and - /// build procedural macros. The command is required to output json - /// and should therefore include `--message-format=json` or a similar - /// option. - /// - /// If there are multiple linked projects/workspaces, this command is invoked for - /// each of them, with the working directory being the workspace root - /// (i.e., the folder containing the `Cargo.toml`). This can be overwritten - /// by changing `#rust-analyzer.cargo.buildScripts.invocationStrategy#`. - /// - /// By default, a cargo invocation will be constructed for the configured - /// targets and features, with the following base command line: - /// - /// ```bash - /// cargo check --quiet --workspace --message-format=json --all-targets --keep-going - /// ``` - /// . - cargo_buildScripts_overrideCommand: Option> = None, - /// Rerun proc-macros building/build-scripts running when proc-macro - /// or build-script sources change and are saved. - cargo_buildScripts_rebuildOnSave: bool = true, - /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to - /// avoid checking unnecessary things. - cargo_buildScripts_useRustcWrapper: bool = true, - /// List of cfg options to enable with the given values. - cargo_cfgs: FxHashMap> = { - let mut m = FxHashMap::default(); - m.insert("debug_assertions".to_owned(), None); - m.insert("miri".to_owned(), None); - m - }, - /// Extra arguments that are passed to every cargo invocation. - cargo_extraArgs: Vec = vec![], - /// Extra environment variables that will be set when running cargo, rustc - /// or other commands within the workspace. Useful for setting RUSTFLAGS. - cargo_extraEnv: FxHashMap = FxHashMap::default(), - /// List of features to activate. - /// - /// Set this to `"all"` to pass `--all-features` to cargo. - cargo_features: CargoFeaturesDef = CargoFeaturesDef::Selected(vec![]), - /// Whether to pass `--no-default-features` to cargo. - cargo_noDefaultFeatures: bool = false, - /// Relative path to the sysroot, or "discover" to try to automatically find it via - /// "rustc --print sysroot". - /// - /// Unsetting this disables sysroot loading. - /// - /// This option does not take effect until rust-analyzer is restarted. - cargo_sysroot: Option = Some("discover".to_owned()), - /// Relative path to the sysroot library sources. If left unset, this will default to - /// `{cargo.sysroot}/lib/rustlib/src/rust/library`. - /// - /// This option does not take effect until rust-analyzer is restarted. - cargo_sysrootSrc: Option = None, - /// Compilation target override (target triple). - // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work - // than `checkOnSave_target` - cargo_target: Option = None, - /// Optional path to a rust-analyzer specific target directory. - /// This prevents rust-analyzer's `cargo check` and initial build-script and proc-macro - /// building from locking the `Cargo.lock` at the expense of duplicating build artifacts. - /// - /// Set to `true` to use a subdirectory of the existing target directory or - /// set to a path relative to the workspace to use that path. - cargo_targetDir | rust_analyzerTargetDir: Option = None, - - /// Run the check command for diagnostics on save. - checkOnSave | checkOnSave_enable: bool = true, - - /// Check all targets and tests (`--all-targets`). Defaults to - /// `#rust-analyzer.cargo.allTargets#`. - check_allTargets | checkOnSave_allTargets: Option = None, - /// Cargo command to use for `cargo check`. - check_command | checkOnSave_command: String = "check".to_owned(), - /// Extra arguments for `cargo check`. - check_extraArgs | checkOnSave_extraArgs: Vec = vec![], - /// Extra environment variables that will be set when running `cargo check`. - /// Extends `#rust-analyzer.cargo.extraEnv#`. - check_extraEnv | checkOnSave_extraEnv: FxHashMap = FxHashMap::default(), - /// List of features to activate. Defaults to - /// `#rust-analyzer.cargo.features#`. - /// - /// Set to `"all"` to pass `--all-features` to Cargo. - check_features | checkOnSave_features: Option = None, - /// List of `cargo check` (or other command specified in `check.command`) diagnostics to ignore. - /// - /// For example for `cargo check`: `dead_code`, `unused_imports`, `unused_variables`,... - check_ignore: FxHashSet = FxHashSet::default(), - /// Specifies the invocation strategy to use when running the check command. - /// If `per_workspace` is set, the command will be executed for each workspace. - /// If `once` is set, the command will be executed once. - /// This config only has an effect when `#rust-analyzer.check.overrideCommand#` - /// is set. - check_invocationStrategy | checkOnSave_invocationStrategy: InvocationStrategy = InvocationStrategy::PerWorkspace, - /// Whether to pass `--no-default-features` to Cargo. Defaults to - /// `#rust-analyzer.cargo.noDefaultFeatures#`. - check_noDefaultFeatures | checkOnSave_noDefaultFeatures: Option = None, - /// Override the command rust-analyzer uses instead of `cargo check` for - /// diagnostics on save. The command is required to output json and - /// should therefore include `--message-format=json` or a similar option - /// (if your client supports the `colorDiagnosticOutput` experimental - /// capability, you can use `--message-format=json-diagnostic-rendered-ansi`). - /// - /// If you're changing this because you're using some tool wrapping - /// Cargo, you might also want to change - /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`. - /// - /// If there are multiple linked projects/workspaces, this command is invoked for - /// each of them, with the working directory being the workspace root - /// (i.e., the folder containing the `Cargo.toml`). This can be overwritten - /// by changing `#rust-analyzer.check.invocationStrategy#`. - /// - /// If `$saved_file` is part of the command, rust-analyzer will pass - /// the absolute path of the saved file to the provided command. This is - /// intended to be used with non-Cargo build systems. - /// Note that `$saved_file` is experimental and may be removed in the future. - /// - /// An example command would be: - /// - /// ```bash - /// cargo check --workspace --message-format=json --all-targets - /// ``` - /// . - check_overrideCommand | checkOnSave_overrideCommand: Option> = None, - /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. - /// - /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. - /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. - /// - /// Aliased as `"checkOnSave.targets"`. - check_targets | checkOnSave_targets | checkOnSave_target: Option = None, - /// Whether `--workspace` should be passed to `cargo check`. - /// If false, `-p ` will be passed instead. - check_workspace: bool = true, + /// Custom completion snippets. + completion_snippets_custom: FxHashMap = Config::completion_snippets_default(), - /// List of rust-analyzer diagnostics to disable. - diagnostics_disabled: FxHashSet = FxHashSet::default(), - /// Whether to show native rust-analyzer diagnostics. - diagnostics_enable: bool = true, - /// Whether to show experimental rust-analyzer diagnostics that might - /// have more false positives than usual. - diagnostics_experimental_enable: bool = false, - /// Map of prefixes to be substituted when parsing diagnostic file paths. - /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. - diagnostics_remapPrefix: FxHashMap = FxHashMap::default(), - /// Whether to run additional style lints. - diagnostics_styleLints_enable: bool = false, - /// List of warnings that should be displayed with hint severity. - /// - /// The warnings will be indicated by faded text or three dots in code - /// and will not show up in the `Problems Panel`. - diagnostics_warningsAsHint: Vec = vec![], - /// List of warnings that should be displayed with info severity. - /// - /// The warnings will be indicated by a blue squiggly underline in code - /// and a blue icon in the `Problems Panel`. - diagnostics_warningsAsInfo: Vec = vec![], /// These directories will be ignored by rust-analyzer. They are /// relative to the workspace root, and globs are not supported. You may @@ -255,51 +85,234 @@ config_data! { files_excludeDirs: Vec = vec![], - /// Disable project auto-discovery in favor of explicitly specified set - /// of projects. - /// - /// Elements must be paths pointing to `Cargo.toml`, - /// `rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON - /// objects in `rust-project.json` format. - linkedProjects: Vec = vec![], - - /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. - lru_capacity: Option = None, - /// Sets the LRU capacity of the specified queries. - lru_query_capacities: FxHashMap, u16> = FxHashMap::default(), - - /// These proc-macros will be ignored when trying to expand them. - /// - /// This config takes a map of crate names with the exported proc-macro names to ignore as values. - procMacro_ignored: FxHashMap, Box<[Box]>> = FxHashMap::default(), - /// Command to be executed instead of 'cargo' for runnables. - runnables_command: Option = None, - /// Additional arguments to be passed to cargo for runnables such as - /// tests or binaries. For example, it may be `--release`. - runnables_extraArgs: Vec = vec![], - /// Additional arguments to be passed through Cargo to launched tests, benchmarks, or - /// doc-tests. - /// - /// Unless the launched target uses a - /// [custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field), - /// they will end up being interpreted as options to - /// [`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments). - runnables_extraTestBinaryArgs: Vec = vec!["--show-output".to_owned()], + /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. + highlightRelated_breakPoints_enable: bool = true, + /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure. + highlightRelated_closureCaptures_enable: bool = true, + /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). + highlightRelated_exitPoints_enable: bool = true, + /// Enables highlighting of related references while the cursor is on any identifier. + highlightRelated_references_enable: bool = true, + /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords. + highlightRelated_yieldPoints_enable: bool = true, - /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private - /// projects, or "discover" to try to automatically find it if the `rustc-dev` component - /// is installed. - /// - /// Any project which uses rust-analyzer with the rustcPrivate - /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it. - /// - /// This option does not take effect until rust-analyzer is restarted. - rustc_source: Option = None, + /// Whether to show `Debug` action. Only applies when + /// `#rust-analyzer.hover.actions.enable#` is set. + hover_actions_debug_enable: bool = true, + /// Whether to show HoverActions in Rust files. + hover_actions_enable: bool = true, + /// Whether to show `Go to Type Definition` action. Only applies when + /// `#rust-analyzer.hover.actions.enable#` is set. + hover_actions_gotoTypeDef_enable: bool = true, + /// Whether to show `Implementations` action. Only applies when + /// `#rust-analyzer.hover.actions.enable#` is set. + hover_actions_implementations_enable: bool = true, + /// Whether to show `References` action. Only applies when + /// `#rust-analyzer.hover.actions.enable#` is set. + hover_actions_references_enable: bool = false, + /// Whether to show `Run` action. Only applies when + /// `#rust-analyzer.hover.actions.enable#` is set. + hover_actions_run_enable: bool = true, + /// Whether to show documentation on hover. + hover_documentation_enable: bool = true, + /// Whether to show keyword hover popups. Only applies when + /// `#rust-analyzer.hover.documentation.enable#` is set. + hover_documentation_keywords_enable: bool = true, + /// Use markdown syntax for links on hover. + hover_links_enable: bool = true, + /// How to render the align information in a memory layout hover. + hover_memoryLayout_alignment: Option = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), + /// Whether to show memory layout data on hover. + hover_memoryLayout_enable: bool = true, + /// How to render the niche information in a memory layout hover. + hover_memoryLayout_niches: Option = Some(false), + /// How to render the offset information in a memory layout hover. + hover_memoryLayout_offset: Option = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), + /// How to render the size information in a memory layout hover. + hover_memoryLayout_size: Option = Some(MemoryLayoutHoverRenderKindDef::Both), - /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. - /// + /// How many variants of an enum to display when hovering on. Show none if empty. + hover_show_enumVariants: Option = Some(5), + /// How many fields of a struct, variant or union to display when hovering on. Show none if empty. + hover_show_fields: Option = Some(5), + /// How many associated items of a trait to display when hovering a trait. + hover_show_traitAssocItems: Option = None, + + /// Whether to show inlay type hints for binding modes. + inlayHints_bindingModeHints_enable: bool = false, + /// Whether to show inlay type hints for method chains. + inlayHints_chainingHints_enable: bool = true, + /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to. + inlayHints_closingBraceHints_enable: bool = true, + /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1 + /// to always show them). + inlayHints_closingBraceHints_minLines: usize = 25, + /// Whether to show inlay hints for closure captures. + inlayHints_closureCaptureHints_enable: bool = false, + /// Whether to show inlay type hints for return types of closures. + inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = ClosureReturnTypeHintsDef::Never, + /// Closure notation in type and chaining inlay hints. + inlayHints_closureStyle: ClosureStyle = ClosureStyle::ImplFn, + /// Whether to show enum variant discriminant hints. + inlayHints_discriminantHints_enable: DiscriminantHintsDef = DiscriminantHintsDef::Never, + /// Whether to show inlay hints for type adjustments. + inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = AdjustmentHintsDef::Never, + /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. + inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = false, + /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc). + inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = AdjustmentHintsModeDef::Prefix, + /// Whether to show const generic parameter name inlay hints. + inlayHints_genericParameterHints_const_enable: bool= true, + /// Whether to show generic lifetime parameter name inlay hints. + inlayHints_genericParameterHints_lifetime_enable: bool = false, + /// Whether to show generic type parameter name inlay hints. + inlayHints_genericParameterHints_type_enable: bool = false, + /// Whether to show implicit drop hints. + inlayHints_implicitDrops_enable: bool = false, + /// Whether to show inlay type hints for elided lifetimes in function signatures. + inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = LifetimeElisionDef::Never, + /// Whether to prefer using parameter names as the name for elided lifetime hints if possible. + inlayHints_lifetimeElisionHints_useParameterNames: bool = false, + /// Maximum length for inlay hints. Set to null to have an unlimited length. + inlayHints_maxLength: Option = Some(25), + /// Whether to show function parameter name inlay hints at the call + /// site. + inlayHints_parameterHints_enable: bool = true, + /// Whether to show exclusive range inlay hints. + inlayHints_rangeExclusiveHints_enable: bool = false, + /// Whether to show inlay hints for compiler inserted reborrows. + /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. + inlayHints_reborrowHints_enable: ReborrowHintsDef = ReborrowHintsDef::Never, + /// Whether to render leading colons for type hints, and trailing colons for parameter hints. + inlayHints_renderColons: bool = true, + /// Whether to show inlay type hints for variables. + inlayHints_typeHints_enable: bool = true, + /// Whether to hide inlay type hints for `let` statements that initialize to a closure. + /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. + inlayHints_typeHints_hideClosureInitialization: bool = false, + /// Whether to hide inlay type hints for constructors. + inlayHints_typeHints_hideNamedConstructor: bool = false, + + /// Enables the experimental support for interpreting tests. + interpret_tests: bool = false, + + /// Join lines merges consecutive declaration and initialization of an assignment. + joinLines_joinAssignments: bool = true, + /// Join lines inserts else between consecutive ifs. + joinLines_joinElseIf: bool = true, + /// Join lines removes trailing commas. + joinLines_removeTrailingComma: bool = true, + /// Join lines unwraps trivial blocks. + joinLines_unwrapTrivialBlock: bool = true, + + /// Whether to show `Debug` lens. Only applies when + /// `#rust-analyzer.lens.enable#` is set. + lens_debug_enable: bool = true, + /// Whether to show CodeLens in Rust files. + lens_enable: bool = true, + /// Whether to show `Implementations` lens. Only applies when + /// `#rust-analyzer.lens.enable#` is set. + lens_implementations_enable: bool = true, + /// Where to render annotations. + lens_location: AnnotationLocation = AnnotationLocation::AboveName, + /// Whether to show `References` lens for Struct, Enum, and Union. + /// Only applies when `#rust-analyzer.lens.enable#` is set. + lens_references_adt_enable: bool = false, + /// Whether to show `References` lens for Enum Variants. + /// Only applies when `#rust-analyzer.lens.enable#` is set. + lens_references_enumVariant_enable: bool = false, + /// Whether to show `Method References` lens. Only applies when + /// `#rust-analyzer.lens.enable#` is set. + lens_references_method_enable: bool = false, + /// Whether to show `References` lens for Trait. + /// Only applies when `#rust-analyzer.lens.enable#` is set. + lens_references_trait_enable: bool = false, + /// Whether to show `Run` lens. Only applies when + /// `#rust-analyzer.lens.enable#` is set. + lens_run_enable: bool = true, + + /// Disable project auto-discovery in favor of explicitly specified set + /// of projects. + /// + /// Elements must be paths pointing to `Cargo.toml`, + /// `rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON + /// objects in `rust-project.json` format. + linkedProjects: Vec = vec![], + + /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. + lru_capacity: Option = None, + /// Sets the LRU capacity of the specified queries. + lru_query_capacities: FxHashMap, u16> = FxHashMap::default(), + + /// Whether to show `can't find Cargo.toml` error message. + notifications_cargoTomlNotFound: bool = true, + + /// How many worker threads in the main loop. The default `null` means to pick automatically. + numThreads: Option = None, + + /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set. + procMacro_attributes_enable: bool = true, + /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`. + procMacro_enable: bool = true, + /// Internal config, path to proc-macro server executable. + procMacro_server: Option = None, + + /// Exclude imports from find-all-references. + references_excludeImports: bool = false, + + /// Exclude tests from find-all-references. + references_excludeTests: bool = false, + + /// Inject additional highlighting into doc comments. + /// + /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra + /// doc links. + semanticHighlighting_doc_comment_inject_enable: bool = true, + /// Whether the server is allowed to emit non-standard tokens and modifiers. + semanticHighlighting_nonStandardTokens: bool = true, + /// Use semantic tokens for operators. + /// + /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when + /// they are tagged with modifiers. + semanticHighlighting_operator_enable: bool = true, + /// Use specialized semantic tokens for operators. + /// + /// When enabled, rust-analyzer will emit special token types for operator tokens instead + /// of the generic `operator` token type. + semanticHighlighting_operator_specialization_enable: bool = false, + /// Use semantic tokens for punctuation. + /// + /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when + /// they are tagged with modifiers or have a special role. + semanticHighlighting_punctuation_enable: bool = false, + /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro + /// calls. + semanticHighlighting_punctuation_separate_macro_bang: bool = false, + /// Use specialized semantic tokens for punctuation. + /// + /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead + /// of the generic `punctuation` token type. + semanticHighlighting_punctuation_specialization_enable: bool = false, + /// Use semantic tokens for strings. + /// + /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars. + /// By disabling semantic tokens for strings, other grammars can be used to highlight + /// their contents. + semanticHighlighting_strings_enable: bool = true, + + /// Show full signature of the callable. Only shows parameters if disabled. + signatureInfo_detail: SignatureDetail = SignatureDetail::Full, + /// Show documentation. + signatureInfo_documentation_enable: bool = true, + + /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. + typing_autoClosingAngleBrackets_enable: bool = false, + + + /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. + /// /// [`DiscoverWorkspaceConfig`] also requires setting `progress_label` and `files_to_watch`. /// `progress_label` is used for the title in progress indicators, whereas `files_to_watch` /// is used to determine which build system-specific files should be watched in order to @@ -408,6 +421,57 @@ config_data! { /// Term search fuel in "units of work" for assists (Defaults to 1800). assist_termSearch_fuel: usize = 1800, + + /// Whether to automatically add a semicolon when completing unit-returning functions. + /// + /// In `match` arms it completes a comma instead. + completion_addSemicolonToUnit: bool = true, + /// Toggles the additional completions that automatically add imports when completed. + /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. + completion_autoimport_enable: bool = true, + /// Toggles the additional completions that automatically show method calls and field accesses + /// with `self` prefixed to them when inside a method. + completion_autoself_enable: bool = true, + /// Whether to add parenthesis and argument snippets when completing function. + completion_callable_snippets: CallableCompletionDef = CallableCompletionDef::FillArguments, + /// Whether to show full function/method signatures in completion docs. + completion_fullFunctionSignatures_enable: bool = false, + /// Whether to omit deprecated items from autocompletion. By default they are marked as deprecated but not hidden. + completion_hideDeprecated: bool = false, + /// Maximum number of completions to return. If `None`, the limit is infinite. + completion_limit: Option = None, + /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. + completion_postfix_enable: bool = true, + /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position. + completion_privateEditable_enable: bool = false, + /// Whether to enable term search based snippets like `Some(foo.bar().baz())`. + completion_termSearch_enable: bool = false, + /// Term search fuel in "units of work" for autocompletion (Defaults to 1000). + completion_termSearch_fuel: usize = 1000, + + /// List of rust-analyzer diagnostics to disable. + diagnostics_disabled: FxHashSet = FxHashSet::default(), + /// Whether to show native rust-analyzer diagnostics. + diagnostics_enable: bool = true, + /// Whether to show experimental rust-analyzer diagnostics that might + /// have more false positives than usual. + diagnostics_experimental_enable: bool = false, + /// Map of prefixes to be substituted when parsing diagnostic file paths. + /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. + diagnostics_remapPrefix: FxHashMap = FxHashMap::default(), + /// Whether to run additional style lints. + diagnostics_styleLints_enable: bool = false, + /// List of warnings that should be displayed with hint severity. + /// + /// The warnings will be indicated by faded text or three dots in code + /// and will not show up in the `Problems Panel`. + diagnostics_warningsAsHint: Vec = vec![], + /// List of warnings that should be displayed with info severity. + /// + /// The warnings will be indicated by a blue squiggly underline in code + /// and a blue icon in the `Problems Panel`. + diagnostics_warningsAsInfo: Vec = vec![], + /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file. imports_granularity_enforce: bool = false, /// How imports should be grouped into use statements. @@ -429,303 +493,199 @@ config_data! { config_data! { workspace: struct WorkspaceDefaultConfigData <- WorkspaceConfigInput -> { + /// Pass `--all-targets` to cargo invocation. + cargo_allTargets: bool = true, + /// Automatically refresh project info via `cargo metadata` on + /// `Cargo.toml` or `.cargo/config.toml` changes. + cargo_autoreload: bool = true, + /// Run build scripts (`build.rs`) for more precise code analysis. + cargo_buildScripts_enable: bool = true, + /// Specifies the invocation strategy to use when running the build scripts command. + /// If `per_workspace` is set, the command will be executed for each Rust workspace with the + /// workspace as the working directory. + /// If `once` is set, the command will be executed once with the opened project as the + /// working directory. + /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` + /// is set. + cargo_buildScripts_invocationStrategy: InvocationStrategy = InvocationStrategy::PerWorkspace, + /// Override the command rust-analyzer uses to run build scripts and + /// build procedural macros. The command is required to output json + /// and should therefore include `--message-format=json` or a similar + /// option. + /// + /// If there are multiple linked projects/workspaces, this command is invoked for + /// each of them, with the working directory being the workspace root + /// (i.e., the folder containing the `Cargo.toml`). This can be overwritten + /// by changing `#rust-analyzer.cargo.buildScripts.invocationStrategy#`. + /// + /// By default, a cargo invocation will be constructed for the configured + /// targets and features, with the following base command line: + /// + /// ```bash + /// cargo check --quiet --workspace --message-format=json --all-targets --keep-going + /// ``` + /// . + cargo_buildScripts_overrideCommand: Option> = None, + /// Rerun proc-macros building/build-scripts running when proc-macro + /// or build-script sources change and are saved. + cargo_buildScripts_rebuildOnSave: bool = true, + /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to + /// avoid checking unnecessary things. + cargo_buildScripts_useRustcWrapper: bool = true, + /// List of cfg options to enable with the given values. + cargo_cfgs: FxHashMap> = { + let mut m = FxHashMap::default(); + m.insert("debug_assertions".to_owned(), None); + m.insert("miri".to_owned(), None); + m + }, + /// Extra arguments that are passed to every cargo invocation. + cargo_extraArgs: Vec = vec![], + /// Extra environment variables that will be set when running cargo, rustc + /// or other commands within the workspace. Useful for setting RUSTFLAGS. + cargo_extraEnv: FxHashMap = FxHashMap::default(), + /// List of features to activate. + /// + /// Set this to `"all"` to pass `--all-features` to cargo. + cargo_features: CargoFeaturesDef = CargoFeaturesDef::Selected(vec![]), + /// Whether to pass `--no-default-features` to cargo. + cargo_noDefaultFeatures: bool = false, + /// Relative path to the sysroot, or "discover" to try to automatically find it via + /// "rustc --print sysroot". + /// + /// Unsetting this disables sysroot loading. + /// + /// This option does not take effect until rust-analyzer is restarted. + cargo_sysroot: Option = Some("discover".to_owned()), + /// Relative path to the sysroot library sources. If left unset, this will default to + /// `{cargo.sysroot}/lib/rustlib/src/rust/library`. + /// + /// This option does not take effect until rust-analyzer is restarted. + cargo_sysrootSrc: Option = None, + /// Compilation target override (target triple). + // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work + // than `checkOnSave_target` + cargo_target: Option = None, + /// Optional path to a rust-analyzer specific target directory. + /// This prevents rust-analyzer's `cargo check` and initial build-script and proc-macro + /// building from locking the `Cargo.lock` at the expense of duplicating build artifacts. + /// + /// Set to `true` to use a subdirectory of the existing target directory or + /// set to a path relative to the workspace to use that path. + cargo_targetDir | rust_analyzerTargetDir: Option = None, - /// Additional arguments to `rustfmt`. - rustfmt_extraArgs: Vec = vec![], - /// Advanced option, fully override the command rust-analyzer uses for - /// formatting. This should be the equivalent of `rustfmt` here, and - /// not that of `cargo fmt`. The file contents will be passed on the - /// standard input and the formatted result will be read from the - /// standard output. - rustfmt_overrideCommand: Option> = None, - /// Enables the use of rustfmt's unstable range formatting command for the - /// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only - /// available on a nightly build. - rustfmt_rangeFormatting_enable: bool = false, - - } -} - -config_data! { - /// Configs that only make sense when they are set by a client. As such they can only be defined - /// by setting them using client's settings (e.g `settings.json` on VS Code). - client: struct ClientDefaultConfigData <- ClientConfigInput -> { - /// Toggles the additional completions that automatically add imports when completed. - /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. - completion_autoimport_enable: bool = true, - /// Toggles the additional completions that automatically show method calls and field accesses - /// with `self` prefixed to them when inside a method. - completion_autoself_enable: bool = true, - /// Whether to add parenthesis and argument snippets when completing function. - completion_callable_snippets: CallableCompletionDef = CallableCompletionDef::FillArguments, - /// Whether to show full function/method signatures in completion docs. - completion_fullFunctionSignatures_enable: bool = false, - /// Maximum number of completions to return. If `None`, the limit is infinite. - completion_limit: Option = None, - /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. - completion_postfix_enable: bool = true, - /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position. - completion_privateEditable_enable: bool = false, - /// Custom completion snippets. - completion_snippets_custom: FxHashMap = serde_json::from_str(r#"{ - "Arc::new": { - "postfix": "arc", - "body": "Arc::new(${receiver})", - "requires": "std::sync::Arc", - "description": "Put the expression into an `Arc`", - "scope": "expr" - }, - "Rc::new": { - "postfix": "rc", - "body": "Rc::new(${receiver})", - "requires": "std::rc::Rc", - "description": "Put the expression into an `Rc`", - "scope": "expr" - }, - "Box::pin": { - "postfix": "pinbox", - "body": "Box::pin(${receiver})", - "requires": "std::boxed::Box", - "description": "Put the expression into a pinned `Box`", - "scope": "expr" - }, - "Ok": { - "postfix": "ok", - "body": "Ok(${receiver})", - "description": "Wrap the expression in a `Result::Ok`", - "scope": "expr" - }, - "Err": { - "postfix": "err", - "body": "Err(${receiver})", - "description": "Wrap the expression in a `Result::Err`", - "scope": "expr" - }, - "Some": { - "postfix": "some", - "body": "Some(${receiver})", - "description": "Wrap the expression in an `Option::Some`", - "scope": "expr" - } - }"#).unwrap(), - /// Whether to enable term search based snippets like `Some(foo.bar().baz())`. - completion_termSearch_enable: bool = false, - /// Term search fuel in "units of work" for autocompletion (Defaults to 1000). - completion_termSearch_fuel: usize = 1000, - - /// Controls file watching implementation. - files_watcher: FilesWatcherDef = FilesWatcherDef::Client, - - /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. - highlightRelated_breakPoints_enable: bool = true, - /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure. - highlightRelated_closureCaptures_enable: bool = true, - /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). - highlightRelated_exitPoints_enable: bool = true, - /// Enables highlighting of related references while the cursor is on any identifier. - highlightRelated_references_enable: bool = true, - /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords. - highlightRelated_yieldPoints_enable: bool = true, - - /// Whether to show `Debug` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_debug_enable: bool = true, - /// Whether to show HoverActions in Rust files. - hover_actions_enable: bool = true, - /// Whether to show `Go to Type Definition` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_gotoTypeDef_enable: bool = true, - /// Whether to show `Implementations` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_implementations_enable: bool = true, - /// Whether to show `References` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_references_enable: bool = false, - /// Whether to show `Run` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_run_enable: bool = true, - - /// Whether to show documentation on hover. - hover_documentation_enable: bool = true, - /// Whether to show keyword hover popups. Only applies when - /// `#rust-analyzer.hover.documentation.enable#` is set. - hover_documentation_keywords_enable: bool = true, - /// Use markdown syntax for links on hover. - hover_links_enable: bool = true, - /// How to render the align information in a memory layout hover. - hover_memoryLayout_alignment: Option = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), - /// Whether to show memory layout data on hover. - hover_memoryLayout_enable: bool = true, - /// How to render the niche information in a memory layout hover. - hover_memoryLayout_niches: Option = Some(false), - /// How to render the offset information in a memory layout hover. - hover_memoryLayout_offset: Option = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), - /// How to render the size information in a memory layout hover. - hover_memoryLayout_size: Option = Some(MemoryLayoutHoverRenderKindDef::Both), - - /// How many variants of an enum to display when hovering on. Show none if empty. - hover_show_enumVariants: Option = Some(5), - /// How many fields of a struct, variant or union to display when hovering on. Show none if empty. - hover_show_fields: Option = Some(5), - /// How many associated items of a trait to display when hovering a trait. - hover_show_traitAssocItems: Option = None, - - /// Whether to show inlay type hints for binding modes. - inlayHints_bindingModeHints_enable: bool = false, - /// Whether to show inlay type hints for method chains. - inlayHints_chainingHints_enable: bool = true, - /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to. - inlayHints_closingBraceHints_enable: bool = true, - /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1 - /// to always show them). - inlayHints_closingBraceHints_minLines: usize = 25, - /// Whether to show inlay hints for closure captures. - inlayHints_closureCaptureHints_enable: bool = false, - /// Whether to show inlay type hints for return types of closures. - inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = ClosureReturnTypeHintsDef::Never, - /// Closure notation in type and chaining inlay hints. - inlayHints_closureStyle: ClosureStyle = ClosureStyle::ImplFn, - /// Whether to show enum variant discriminant hints. - inlayHints_discriminantHints_enable: DiscriminantHintsDef = DiscriminantHintsDef::Never, - /// Whether to show inlay hints for type adjustments. - inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = AdjustmentHintsDef::Never, - /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. - inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = false, - /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc). - inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = AdjustmentHintsModeDef::Prefix, - /// Whether to show const generic parameter name inlay hints. - inlayHints_genericParameterHints_const_enable: bool= true, - /// Whether to show generic lifetime parameter name inlay hints. - inlayHints_genericParameterHints_lifetime_enable: bool = false, - /// Whether to show generic type parameter name inlay hints. - inlayHints_genericParameterHints_type_enable: bool = false, - /// Whether to show implicit drop hints. - inlayHints_implicitDrops_enable: bool = false, - /// Whether to show inlay type hints for elided lifetimes in function signatures. - inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = LifetimeElisionDef::Never, - /// Whether to prefer using parameter names as the name for elided lifetime hints if possible. - inlayHints_lifetimeElisionHints_useParameterNames: bool = false, - /// Maximum length for inlay hints. Set to null to have an unlimited length. - inlayHints_maxLength: Option = Some(25), - /// Whether to show function parameter name inlay hints at the call - /// site. - inlayHints_parameterHints_enable: bool = true, - /// Whether to show exclusive range inlay hints. - inlayHints_rangeExclusiveHints_enable: bool = false, - /// Whether to show inlay hints for compiler inserted reborrows. - /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. - inlayHints_reborrowHints_enable: ReborrowHintsDef = ReborrowHintsDef::Never, - /// Whether to render leading colons for type hints, and trailing colons for parameter hints. - inlayHints_renderColons: bool = true, - /// Whether to show inlay type hints for variables. - inlayHints_typeHints_enable: bool = true, - /// Whether to hide inlay type hints for `let` statements that initialize to a closure. - /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. - inlayHints_typeHints_hideClosureInitialization: bool = false, - /// Whether to hide inlay type hints for constructors. - inlayHints_typeHints_hideNamedConstructor: bool = false, - - /// Enables the experimental support for interpreting tests. - interpret_tests: bool = false, - - /// Join lines merges consecutive declaration and initialization of an assignment. - joinLines_joinAssignments: bool = true, - /// Join lines inserts else between consecutive ifs. - joinLines_joinElseIf: bool = true, - /// Join lines removes trailing commas. - joinLines_removeTrailingComma: bool = true, - /// Join lines unwraps trivial blocks. - joinLines_unwrapTrivialBlock: bool = true, - - /// Whether to show `Debug` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_debug_enable: bool = true, - /// Whether to show CodeLens in Rust files. - lens_enable: bool = true, - /// Whether to show `Implementations` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_implementations_enable: bool = true, - /// Where to render annotations. - lens_location: AnnotationLocation = AnnotationLocation::AboveName, - /// Whether to show `References` lens for Struct, Enum, and Union. - /// Only applies when `#rust-analyzer.lens.enable#` is set. - lens_references_adt_enable: bool = false, - /// Whether to show `References` lens for Enum Variants. - /// Only applies when `#rust-analyzer.lens.enable#` is set. - lens_references_enumVariant_enable: bool = false, - /// Whether to show `Method References` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_references_method_enable: bool = false, - /// Whether to show `References` lens for Trait. - /// Only applies when `#rust-analyzer.lens.enable#` is set. - lens_references_trait_enable: bool = false, - /// Whether to show `Run` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_run_enable: bool = true, - - /// Whether to show `can't find Cargo.toml` error message. - notifications_cargoTomlNotFound: bool = true, - - /// How many worker threads in the main loop. The default `null` means to pick automatically. - numThreads: Option = None, - - /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set. - procMacro_attributes_enable: bool = true, - /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`. - procMacro_enable: bool = true, - /// Internal config, path to proc-macro server executable. - procMacro_server: Option = None, - - /// Exclude imports from find-all-references. - references_excludeImports: bool = false, + /// Run the check command for diagnostics on save. + checkOnSave | checkOnSave_enable: bool = true, - /// Exclude tests from find-all-references. - references_excludeTests: bool = false, - /// Inject additional highlighting into doc comments. + /// Check all targets and tests (`--all-targets`). Defaults to + /// `#rust-analyzer.cargo.allTargets#`. + check_allTargets | checkOnSave_allTargets: Option = None, + /// Cargo command to use for `cargo check`. + check_command | checkOnSave_command: String = "check".to_owned(), + /// Extra arguments for `cargo check`. + check_extraArgs | checkOnSave_extraArgs: Vec = vec![], + /// Extra environment variables that will be set when running `cargo check`. + /// Extends `#rust-analyzer.cargo.extraEnv#`. + check_extraEnv | checkOnSave_extraEnv: FxHashMap = FxHashMap::default(), + /// List of features to activate. Defaults to + /// `#rust-analyzer.cargo.features#`. /// - /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra - /// doc links. - semanticHighlighting_doc_comment_inject_enable: bool = true, - /// Whether the server is allowed to emit non-standard tokens and modifiers. - semanticHighlighting_nonStandardTokens: bool = true, - /// Use semantic tokens for operators. + /// Set to `"all"` to pass `--all-features` to Cargo. + check_features | checkOnSave_features: Option = None, + /// List of `cargo check` (or other command specified in `check.command`) diagnostics to ignore. /// - /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when - /// they are tagged with modifiers. - semanticHighlighting_operator_enable: bool = true, - /// Use specialized semantic tokens for operators. + /// For example for `cargo check`: `dead_code`, `unused_imports`, `unused_variables`,... + check_ignore: FxHashSet = FxHashSet::default(), + /// Specifies the invocation strategy to use when running the check command. + /// If `per_workspace` is set, the command will be executed for each workspace. + /// If `once` is set, the command will be executed once. + /// This config only has an effect when `#rust-analyzer.check.overrideCommand#` + /// is set. + check_invocationStrategy | checkOnSave_invocationStrategy: InvocationStrategy = InvocationStrategy::PerWorkspace, + /// Whether to pass `--no-default-features` to Cargo. Defaults to + /// `#rust-analyzer.cargo.noDefaultFeatures#`. + check_noDefaultFeatures | checkOnSave_noDefaultFeatures: Option = None, + /// Override the command rust-analyzer uses instead of `cargo check` for + /// diagnostics on save. The command is required to output json and + /// should therefore include `--message-format=json` or a similar option + /// (if your client supports the `colorDiagnosticOutput` experimental + /// capability, you can use `--message-format=json-diagnostic-rendered-ansi`). /// - /// When enabled, rust-analyzer will emit special token types for operator tokens instead - /// of the generic `operator` token type. - semanticHighlighting_operator_specialization_enable: bool = false, - /// Use semantic tokens for punctuation. + /// If you're changing this because you're using some tool wrapping + /// Cargo, you might also want to change + /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`. /// - /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when - /// they are tagged with modifiers or have a special role. - semanticHighlighting_punctuation_enable: bool = false, - /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro - /// calls. - semanticHighlighting_punctuation_separate_macro_bang: bool = false, - /// Use specialized semantic tokens for punctuation. + /// If there are multiple linked projects/workspaces, this command is invoked for + /// each of them, with the working directory being the workspace root + /// (i.e., the folder containing the `Cargo.toml`). This can be overwritten + /// by changing `#rust-analyzer.check.invocationStrategy#`. /// - /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead - /// of the generic `punctuation` token type. - semanticHighlighting_punctuation_specialization_enable: bool = false, - /// Use semantic tokens for strings. + /// If `$saved_file` is part of the command, rust-analyzer will pass + /// the absolute path of the saved file to the provided command. This is + /// intended to be used with non-Cargo build systems. + /// Note that `$saved_file` is experimental and may be removed in the future. /// - /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars. - /// By disabling semantic tokens for strings, other grammars can be used to highlight - /// their contents. - semanticHighlighting_strings_enable: bool = true, + /// An example command would be: + /// + /// ```bash + /// cargo check --workspace --message-format=json --all-targets + /// ``` + /// . + check_overrideCommand | checkOnSave_overrideCommand: Option> = None, + /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + /// + /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. + /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + /// + /// Aliased as `"checkOnSave.targets"`. + check_targets | checkOnSave_targets | checkOnSave_target: Option = None, + /// Whether `--workspace` should be passed to `cargo check`. + /// If false, `-p ` will be passed instead. + check_workspace: bool = true, - /// Show full signature of the callable. Only shows parameters if disabled. - signatureInfo_detail: SignatureDetail = SignatureDetail::Full, - /// Show documentation. - signatureInfo_documentation_enable: bool = true, + /// These proc-macros will be ignored when trying to expand them. + /// + /// This config takes a map of crate names with the exported proc-macro names to ignore as values. + procMacro_ignored: FxHashMap, Box<[Box]>> = FxHashMap::default(), + + /// Command to be executed instead of 'cargo' for runnables. + runnables_command: Option = None, + /// Additional arguments to be passed to cargo for runnables such as + /// tests or binaries. For example, it may be `--release`. + runnables_extraArgs: Vec = vec![], + /// Additional arguments to be passed through Cargo to launched tests, benchmarks, or + /// doc-tests. + /// + /// Unless the launched target uses a + /// [custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field), + /// they will end up being interpreted as options to + /// [`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments). + runnables_extraTestBinaryArgs: Vec = vec!["--show-output".to_owned()], + + /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private + /// projects, or "discover" to try to automatically find it if the `rustc-dev` component + /// is installed. + /// + /// Any project which uses rust-analyzer with the rustcPrivate + /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it. + /// + /// This option does not take effect until rust-analyzer is restarted. + rustc_source: Option = None, + + /// Additional arguments to `rustfmt`. + rustfmt_extraArgs: Vec = vec![], + /// Advanced option, fully override the command rust-analyzer uses for + /// formatting. This should be the equivalent of `rustfmt` here, and + /// not that of `cargo fmt`. The file contents will be passed on the + /// standard input and the formatted result will be read from the + /// standard output. + rustfmt_overrideCommand: Option> = None, + /// Enables the use of rustfmt's unstable range formatting command for the + /// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only + /// available on a nightly build. + rustfmt_rangeFormatting_enable: bool = false, - /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. - typing_autoClosingAngleBrackets_enable: bool = false, /// Workspace symbol search kind. workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes, @@ -735,6 +695,19 @@ config_data! { workspace_symbol_search_limit: usize = 128, /// Workspace symbol search scope. workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = WorkspaceSymbolSearchScopeDef::Workspace, + + } +} + +config_data! { + /// Configs that only make sense when they are set by a client. As such they can only be defined + /// by setting them using client's settings (e.g `settings.json` on VS Code). + client: struct ClientDefaultConfigData <- ClientConfigInput -> { + + /// Controls file watching implementation. + files_watcher: FilesWatcherDef = FilesWatcherDef::Client, + + } } @@ -753,7 +726,13 @@ enum RatomlFile { #[derive(Debug, Clone)] pub struct Config { - discovered_projects: Vec, + /// Projects that have a Cargo.toml or a rust-project.json in a + /// parent directory, so we can discover them by walking the + /// file system. + discovered_projects_from_filesystem: Vec, + /// Projects whose configuration was generated by a command + /// configured in discoverConfig. + discovered_projects_from_command: Vec, /// The workspace roots as registered by the LSP client workspace_roots: Vec, caps: ClientCapabilities, @@ -1016,7 +995,7 @@ impl Config { config.source_root_parent_map = source_root_map; } - if config.check_command().is_empty() { + if config.check_command(None).is_empty() { config.validation_errors.0.push(Arc::new(ConfigErrorInner::Json { config_key: "/check/command".to_owned(), error: serde_json::Error::custom("expected a non-empty string"), @@ -1046,19 +1025,19 @@ impl Config { (config, e, should_update) } - pub fn add_linked_projects(&mut self, data: ProjectJsonData, buildfile: AbsPathBuf) { - let linked_projects = &mut self.client_config.0.global.linkedProjects; - - let new_project = ManifestOrProjectJson::DiscoveredProjectJson { data, buildfile }; - match linked_projects { - Some(projects) => { - match projects.iter_mut().find(|p| p.manifest() == new_project.manifest()) { - Some(p) => *p = new_project, - None => projects.push(new_project), - } + pub fn add_discovered_project_from_command( + &mut self, + data: ProjectJsonData, + buildfile: AbsPathBuf, + ) { + for proj in self.discovered_projects_from_command.iter_mut() { + if proj.buildfile == buildfile { + proj.data = data; + return; } - None => *linked_projects = Some(vec![new_project]), } + + self.discovered_projects_from_command.push(ProjectJsonFromCommand { data, buildfile }); } } @@ -1251,7 +1230,7 @@ pub struct NotificationsConfig { pub cargo_toml_not_found: bool, } -#[derive(Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone)] pub enum RustfmtConfig { Rustfmt { extra_args: Vec, enable_range_formatting: bool }, CustomCommand { command: String, args: Vec }, @@ -1336,7 +1315,8 @@ impl Config { Config { caps: ClientCapabilities::new(caps), - discovered_projects: Vec::new(), + discovered_projects_from_filesystem: Vec::new(), + discovered_projects_from_command: Vec::new(), root_path, snippets: Default::default(), workspace_roots, @@ -1357,7 +1337,7 @@ impl Config { if discovered.is_empty() { tracing::error!("failed to find any projects in {:?}", &self.workspace_roots); } - self.discovered_projects = discovered; + self.discovered_projects_from_filesystem = discovered; } pub fn remove_workspace(&mut self, path: &AbsPath) { @@ -1412,29 +1392,36 @@ impl Config { pub fn completion(&self, source_root: Option) -> CompletionConfig { CompletionConfig { - enable_postfix_completions: self.completion_postfix_enable().to_owned(), - enable_imports_on_the_fly: self.completion_autoimport_enable().to_owned() + enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(), + enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned() && self.caps.completion_item_edit_resolve(), - enable_self_on_the_fly: self.completion_autoself_enable().to_owned(), - enable_private_editable: self.completion_privateEditable_enable().to_owned(), - full_function_signatures: self.completion_fullFunctionSignatures_enable().to_owned(), - callable: match self.completion_callable_snippets() { + enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(), + enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(), + full_function_signatures: self + .completion_fullFunctionSignatures_enable(source_root) + .to_owned(), + callable: match self.completion_callable_snippets(source_root) { CallableCompletionDef::FillArguments => Some(CallableSnippets::FillArguments), CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses), CallableCompletionDef::None => None, }, + add_semicolon_to_unit: *self.completion_addSemicolonToUnit(source_root), snippet_cap: SnippetCap::new(self.completion_snippet()), insert_use: self.insert_use_config(source_root), prefer_no_std: self.imports_preferNoStd(source_root).to_owned(), prefer_prelude: self.imports_preferPrelude(source_root).to_owned(), prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(), snippets: self.snippets.clone().to_vec(), - limit: self.completion_limit().to_owned(), - enable_term_search: self.completion_termSearch_enable().to_owned(), - term_search_fuel: self.completion_termSearch_fuel().to_owned() as u64, + limit: self.completion_limit(source_root).to_owned(), + enable_term_search: self.completion_termSearch_enable(source_root).to_owned(), + term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64, } } + pub fn completion_hide_deprecated(&self) -> bool { + *self.completion_hideDeprecated(None) + } + pub fn detached_files(&self) -> &Vec { // FIXME @alibektas : This is the only config that is confusing. If it's a proper configuration // why is it not among the others? If it's client only which I doubt it is current state should be alright @@ -1443,11 +1430,11 @@ impl Config { pub fn diagnostics(&self, source_root: Option) -> DiagnosticsConfig { DiagnosticsConfig { - enabled: *self.diagnostics_enable(), + enabled: *self.diagnostics_enable(source_root), proc_attr_macros_enabled: self.expand_proc_attr_macros(), proc_macros_enabled: *self.procMacro_enable(), - disable_experimental: !self.diagnostics_experimental_enable(), - disabled: self.diagnostics_disabled().clone(), + disable_experimental: !self.diagnostics_experimental_enable(source_root), + disabled: self.diagnostics_disabled(source_root).clone(), expr_fill_default: match self.assist_expressionFillDefault(source_root) { ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo, ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, @@ -1457,7 +1444,7 @@ impl Config { prefer_no_std: self.imports_preferNoStd(source_root).to_owned(), prefer_prelude: self.imports_preferPrelude(source_root).to_owned(), prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(), - style_lints: self.diagnostics_styleLints_enable().to_owned(), + style_lints: self.diagnostics_styleLints_enable(source_root).to_owned(), term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64, term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(), } @@ -1673,78 +1660,95 @@ impl Config { self.workspace_discoverConfig().as_ref() } - pub fn linked_or_discovered_projects(&self) -> Vec { - match self.linkedProjects().as_slice() { - [] => { - let exclude_dirs: Vec<_> = - self.files_excludeDirs().iter().map(|p| self.root_path.join(p)).collect(); - self.discovered_projects - .iter() - .filter(|project| { - !exclude_dirs.iter().any(|p| project.manifest_path().starts_with(p)) - }) - .cloned() - .map(LinkedProject::from) - .collect() + fn discovered_projects(&self) -> Vec { + let exclude_dirs: Vec<_> = + self.files_excludeDirs().iter().map(|p| self.root_path.join(p)).collect(); + + let mut projects = vec![]; + for fs_proj in &self.discovered_projects_from_filesystem { + let manifest_path = fs_proj.manifest_path(); + if exclude_dirs.iter().any(|p| manifest_path.starts_with(p)) { + continue; } - linked_projects => linked_projects - .iter() - .filter_map(|linked_project| match linked_project { - ManifestOrProjectJson::Manifest(it) => { - let path = self.root_path.join(it); - ProjectManifest::from_manifest_file(path) - .map_err(|e| tracing::error!("failed to load linked project: {}", e)) - .ok() - .map(Into::into) - } - ManifestOrProjectJson::DiscoveredProjectJson { data, buildfile } => { - let root_path = - buildfile.parent().expect("Unable to get parent of buildfile"); - Some(ProjectJson::new(None, root_path, data.clone()).into()) - } - ManifestOrProjectJson::ProjectJson(it) => { - Some(ProjectJson::new(None, &self.root_path, it.clone()).into()) - } - }) - .collect(), + let buf: Utf8PathBuf = manifest_path.to_path_buf().into(); + projects.push(ManifestOrProjectJson::Manifest(buf)); + } + + for dis_proj in &self.discovered_projects_from_command { + projects.push(ManifestOrProjectJson::DiscoveredProjectJson { + data: dis_proj.data.clone(), + buildfile: dis_proj.buildfile.clone(), + }); } + + projects + } + + pub fn linked_or_discovered_projects(&self) -> Vec { + let linked_projects = self.linkedProjects(); + let projects = if linked_projects.is_empty() { + self.discovered_projects() + } else { + linked_projects.clone() + }; + + projects + .iter() + .filter_map(|linked_project| match linked_project { + ManifestOrProjectJson::Manifest(it) => { + let path = self.root_path.join(it); + ProjectManifest::from_manifest_file(path) + .map_err(|e| tracing::error!("failed to load linked project: {}", e)) + .ok() + .map(Into::into) + } + ManifestOrProjectJson::DiscoveredProjectJson { data, buildfile } => { + let root_path = buildfile.parent().expect("Unable to get parent of buildfile"); + + Some(ProjectJson::new(None, root_path, data.clone()).into()) + } + ManifestOrProjectJson::ProjectJson(it) => { + Some(ProjectJson::new(None, &self.root_path, it.clone()).into()) + } + }) + .collect() } pub fn prefill_caches(&self) -> bool { self.cachePriming_enable().to_owned() } - pub fn publish_diagnostics(&self) -> bool { - self.diagnostics_enable().to_owned() + pub fn publish_diagnostics(&self, source_root: Option) -> bool { + self.diagnostics_enable(source_root).to_owned() } - pub fn diagnostics_map(&self) -> DiagnosticsMapConfig { + pub fn diagnostics_map(&self, source_root: Option) -> DiagnosticsMapConfig { DiagnosticsMapConfig { - remap_prefix: self.diagnostics_remapPrefix().clone(), - warnings_as_info: self.diagnostics_warningsAsInfo().clone(), - warnings_as_hint: self.diagnostics_warningsAsHint().clone(), - check_ignore: self.check_ignore().clone(), + remap_prefix: self.diagnostics_remapPrefix(source_root).clone(), + warnings_as_info: self.diagnostics_warningsAsInfo(source_root).clone(), + warnings_as_hint: self.diagnostics_warningsAsHint(source_root).clone(), + check_ignore: self.check_ignore(source_root).clone(), } } - pub fn extra_args(&self) -> &Vec { - self.cargo_extraArgs() + pub fn extra_args(&self, source_root: Option) -> &Vec { + self.cargo_extraArgs(source_root) } - pub fn extra_env(&self) -> &FxHashMap { - self.cargo_extraEnv() + pub fn extra_env(&self, source_root: Option) -> &FxHashMap { + self.cargo_extraEnv(source_root) } - pub fn check_extra_args(&self) -> Vec { - let mut extra_args = self.extra_args().clone(); - extra_args.extend_from_slice(self.check_extraArgs()); + pub fn check_extra_args(&self, source_root: Option) -> Vec { + let mut extra_args = self.extra_args(source_root).clone(); + extra_args.extend_from_slice(self.check_extraArgs(source_root)); extra_args } - pub fn check_extra_env(&self) -> FxHashMap { - let mut extra_env = self.cargo_extraEnv().clone(); - extra_env.extend(self.check_extraEnv().clone()); + pub fn check_extra_env(&self, source_root: Option) -> FxHashMap { + let mut extra_env = self.cargo_extraEnv(source_root).clone(); + extra_env.extend(self.check_extraEnv(source_root).clone()); extra_env } @@ -1761,8 +1765,11 @@ impl Config { Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(path))) } - pub fn ignored_proc_macros(&self) -> &FxHashMap, Box<[Box]>> { - self.procMacro_ignored() + pub fn ignored_proc_macros( + &self, + source_root: Option, + ) -> &FxHashMap, Box<[Box]>> { + self.procMacro_ignored(source_root) } pub fn expand_proc_macros(&self) -> bool { @@ -1787,23 +1794,23 @@ impl Config { } } - pub fn cargo_autoreload_config(&self) -> bool { - self.cargo_autoreload().to_owned() + pub fn cargo_autoreload_config(&self, source_root: Option) -> bool { + self.cargo_autoreload(source_root).to_owned() } - pub fn run_build_scripts(&self) -> bool { - self.cargo_buildScripts_enable().to_owned() || self.procMacro_enable().to_owned() + pub fn run_build_scripts(&self, source_root: Option) -> bool { + self.cargo_buildScripts_enable(source_root).to_owned() || self.procMacro_enable().to_owned() } - pub fn cargo(&self) -> CargoConfig { - let rustc_source = self.rustc_source().as_ref().map(|rustc_src| { + pub fn cargo(&self, source_root: Option) -> CargoConfig { + let rustc_source = self.rustc_source(source_root).as_ref().map(|rustc_src| { if rustc_src == "discover" { RustLibSource::Discover } else { RustLibSource::Path(self.root_path.join(rustc_src)) } }); - let sysroot = self.cargo_sysroot().as_ref().map(|sysroot| { + let sysroot = self.cargo_sysroot(source_root).as_ref().map(|sysroot| { if sysroot == "discover" { RustLibSource::Discover } else { @@ -1811,24 +1818,24 @@ impl Config { } }); let sysroot_src = - self.cargo_sysrootSrc().as_ref().map(|sysroot| self.root_path.join(sysroot)); + self.cargo_sysrootSrc(source_root).as_ref().map(|sysroot| self.root_path.join(sysroot)); CargoConfig { - all_targets: *self.cargo_allTargets(), - features: match &self.cargo_features() { + all_targets: *self.cargo_allTargets(source_root), + features: match &self.cargo_features(source_root) { CargoFeaturesDef::All => CargoFeatures::All, CargoFeaturesDef::Selected(features) => CargoFeatures::Selected { features: features.clone(), - no_default_features: self.cargo_noDefaultFeatures().to_owned(), + no_default_features: self.cargo_noDefaultFeatures(source_root).to_owned(), }, }, - target: self.cargo_target().clone(), + target: self.cargo_target(source_root).clone(), sysroot, sysroot_src, rustc_source, cfg_overrides: project_model::CfgOverrides { global: CfgDiff::new( - self.cargo_cfgs() + self.cargo_cfgs(source_root) .iter() .map(|(key, val)| match val { Some(val) => CfgAtom::KeyValue { @@ -1843,18 +1850,65 @@ impl Config { .unwrap(), selective: Default::default(), }, - wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(), - invocation_strategy: match self.cargo_buildScripts_invocationStrategy() { + wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(source_root), + invocation_strategy: match self.cargo_buildScripts_invocationStrategy(source_root) { InvocationStrategy::Once => project_model::InvocationStrategy::Once, InvocationStrategy::PerWorkspace => project_model::InvocationStrategy::PerWorkspace, }, - run_build_script_command: self.cargo_buildScripts_overrideCommand().clone(), - extra_args: self.cargo_extraArgs().clone(), - extra_env: self.cargo_extraEnv().clone(), - target_dir: self.target_dir_from_config(), + run_build_script_command: self.cargo_buildScripts_overrideCommand(source_root).clone(), + extra_args: self.cargo_extraArgs(source_root).clone(), + extra_env: self.cargo_extraEnv(source_root).clone(), + target_dir: self.target_dir_from_config(source_root), } } + pub(crate) fn completion_snippets_default() -> FxHashMap { + serde_json::from_str( + r#"{ + "Arc::new": { + "postfix": "arc", + "body": "Arc::new(${receiver})", + "requires": "std::sync::Arc", + "description": "Put the expression into an `Arc`", + "scope": "expr" + }, + "Rc::new": { + "postfix": "rc", + "body": "Rc::new(${receiver})", + "requires": "std::rc::Rc", + "description": "Put the expression into an `Rc`", + "scope": "expr" + }, + "Box::pin": { + "postfix": "pinbox", + "body": "Box::pin(${receiver})", + "requires": "std::boxed::Box", + "description": "Put the expression into a pinned `Box`", + "scope": "expr" + }, + "Ok": { + "postfix": "ok", + "body": "Ok(${receiver})", + "description": "Wrap the expression in a `Result::Ok`", + "scope": "expr" + }, + "Err": { + "postfix": "err", + "body": "Err(${receiver})", + "description": "Wrap the expression in a `Result::Err`", + "scope": "expr" + }, + "Some": { + "postfix": "some", + "body": "Some(${receiver})", + "description": "Wrap the expression in an `Option::Some`", + "scope": "expr" + } + }"#, + ) + .unwrap() + } + pub fn rustfmt(&self, source_root_id: Option) -> RustfmtConfig { match &self.rustfmt_overrideCommand(source_root_id) { Some(args) if !args.is_empty() => { @@ -1869,37 +1923,37 @@ impl Config { } } - pub fn flycheck_workspace(&self) -> bool { - *self.check_workspace() + pub fn flycheck_workspace(&self, source_root: Option) -> bool { + *self.check_workspace(source_root) } - pub(crate) fn cargo_test_options(&self) -> CargoOptions { + pub(crate) fn cargo_test_options(&self, source_root: Option) -> CargoOptions { CargoOptions { - target_triples: self.cargo_target().clone().into_iter().collect(), + target_triples: self.cargo_target(source_root).clone().into_iter().collect(), all_targets: false, - no_default_features: *self.cargo_noDefaultFeatures(), - all_features: matches!(self.cargo_features(), CargoFeaturesDef::All), - features: match self.cargo_features().clone() { + no_default_features: *self.cargo_noDefaultFeatures(source_root), + all_features: matches!(self.cargo_features(source_root), CargoFeaturesDef::All), + features: match self.cargo_features(source_root).clone() { CargoFeaturesDef::All => vec![], CargoFeaturesDef::Selected(it) => it, }, - extra_args: self.extra_args().clone(), - extra_test_bin_args: self.runnables_extraTestBinaryArgs().clone(), - extra_env: self.extra_env().clone(), - target_dir: self.target_dir_from_config(), + extra_args: self.extra_args(source_root).clone(), + extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(), + extra_env: self.extra_env(source_root).clone(), + target_dir: self.target_dir_from_config(source_root), } } - pub(crate) fn flycheck(&self) -> FlycheckConfig { - match &self.check_overrideCommand() { + pub(crate) fn flycheck(&self, source_root: Option) -> FlycheckConfig { + match &self.check_overrideCommand(source_root) { Some(args) if !args.is_empty() => { let mut args = args.clone(); let command = args.remove(0); FlycheckConfig::CustomCommand { command, args, - extra_env: self.check_extra_env(), - invocation_strategy: match self.check_invocationStrategy() { + extra_env: self.check_extra_env(source_root), + invocation_strategy: match self.check_invocationStrategy(source_root) { InvocationStrategy::Once => crate::flycheck::InvocationStrategy::Once, InvocationStrategy::PerWorkspace => { crate::flycheck::InvocationStrategy::PerWorkspace @@ -1908,44 +1962,50 @@ impl Config { } } Some(_) | None => FlycheckConfig::CargoCommand { - command: self.check_command().clone(), + command: self.check_command(source_root).clone(), options: CargoOptions { target_triples: self - .check_targets() + .check_targets(source_root) .clone() .and_then(|targets| match &targets.0[..] { [] => None, targets => Some(targets.into()), }) - .unwrap_or_else(|| self.cargo_target().clone().into_iter().collect()), - all_targets: self.check_allTargets().unwrap_or(*self.cargo_allTargets()), + .unwrap_or_else(|| { + self.cargo_target(source_root).clone().into_iter().collect() + }), + all_targets: self + .check_allTargets(source_root) + .unwrap_or(*self.cargo_allTargets(source_root)), no_default_features: self - .check_noDefaultFeatures() - .unwrap_or(*self.cargo_noDefaultFeatures()), + .check_noDefaultFeatures(source_root) + .unwrap_or(*self.cargo_noDefaultFeatures(source_root)), all_features: matches!( - self.check_features().as_ref().unwrap_or(self.cargo_features()), + self.check_features(source_root) + .as_ref() + .unwrap_or(self.cargo_features(source_root)), CargoFeaturesDef::All ), features: match self - .check_features() + .check_features(source_root) .clone() - .unwrap_or_else(|| self.cargo_features().clone()) + .unwrap_or_else(|| self.cargo_features(source_root).clone()) { CargoFeaturesDef::All => vec![], CargoFeaturesDef::Selected(it) => it, }, - extra_args: self.check_extra_args(), - extra_test_bin_args: self.runnables_extraTestBinaryArgs().clone(), - extra_env: self.check_extra_env(), - target_dir: self.target_dir_from_config(), + extra_args: self.check_extra_args(source_root), + extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(), + extra_env: self.check_extra_env(source_root), + target_dir: self.target_dir_from_config(source_root), }, ansi_color_output: self.color_diagnostic_output(), }, } } - fn target_dir_from_config(&self) -> Option { - self.cargo_targetDir().as_ref().and_then(|target_dir| match target_dir { + fn target_dir_from_config(&self, source_root: Option) -> Option { + self.cargo_targetDir(source_root).as_ref().and_then(|target_dir| match target_dir { TargetDirectory::UseSubdirectory(true) => { Some(Utf8PathBuf::from("target/rust-analyzer")) } @@ -1955,19 +2015,19 @@ impl Config { }) } - pub fn check_on_save(&self) -> bool { - *self.checkOnSave() + pub fn check_on_save(&self, source_root: Option) -> bool { + *self.checkOnSave(source_root) } - pub fn script_rebuild_on_save(&self) -> bool { - *self.cargo_buildScripts_rebuildOnSave() + pub fn script_rebuild_on_save(&self, source_root: Option) -> bool { + *self.cargo_buildScripts_rebuildOnSave(source_root) } - pub fn runnables(&self) -> RunnablesConfig { + pub fn runnables(&self, source_root: Option) -> RunnablesConfig { RunnablesConfig { - override_cargo: self.runnables_command().clone(), - cargo_extra_args: self.runnables_extraArgs().clone(), - extra_test_binary_args: self.runnables_extraTestBinaryArgs().clone(), + override_cargo: self.runnables_command(source_root).clone(), + cargo_extra_args: self.runnables_extraArgs(source_root).clone(), + extra_test_binary_args: self.runnables_extraTestBinaryArgs(source_root).clone(), } } @@ -2006,19 +2066,19 @@ impl Config { } } - pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig { + pub fn workspace_symbol(&self, source_root: Option) -> WorkspaceSymbolConfig { WorkspaceSymbolConfig { - search_scope: match self.workspace_symbol_search_scope() { + search_scope: match self.workspace_symbol_search_scope(source_root) { WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace, WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => { WorkspaceSymbolSearchScope::WorkspaceAndDependencies } }, - search_kind: match self.workspace_symbol_search_kind() { + search_kind: match self.workspace_symbol_search_kind(source_root) { WorkspaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes, WorkspaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols, }, - search_limit: *self.workspace_symbol_search_limit(), + search_limit: *self.workspace_symbol_search_limit(source_root), } } @@ -2259,18 +2319,6 @@ where se.serialize_str(path.as_str()) } -impl ManifestOrProjectJson { - fn manifest(&self) -> Option<&Utf8Path> { - match self { - ManifestOrProjectJson::Manifest(manifest) => Some(manifest), - ManifestOrProjectJson::DiscoveredProjectJson { buildfile, .. } => { - Some(buildfile.as_ref()) - } - ManifestOrProjectJson::ProjectJson(_) => None, - } - } -} - #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] enum ExprFillDefaultDef { @@ -3522,9 +3570,9 @@ mod tests { })); (config, _, _) = config.apply_change(change); - assert_eq!(config.cargo_targetDir(), &None); + assert_eq!(config.cargo_targetDir(None), &None); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none()) + matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none()) ); } @@ -3540,9 +3588,9 @@ mod tests { (config, _, _) = config.apply_change(change); - assert_eq!(config.cargo_targetDir(), &Some(TargetDirectory::UseSubdirectory(true))); + assert_eq!(config.cargo_targetDir(None), &Some(TargetDirectory::UseSubdirectory(true))); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer"))) + matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer"))) ); } @@ -3559,83 +3607,11 @@ mod tests { (config, _, _) = config.apply_change(change); assert_eq!( - config.cargo_targetDir(), + config.cargo_targetDir(None), &Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder"))) ); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder"))) + matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder"))) ); } - - #[test] - fn toml_unknown_key() { - let config = - Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None); - - let mut change = ConfigChange::default(); - - change.change_user_config(Some( - toml::toml! { - [cargo.cfgs] - these = "these" - should = "should" - be = "be" - valid = "valid" - - [invalid.config] - err = "error" - - [cargo] - target = "ok" - - // FIXME: This should be an error - [cargo.sysroot] - non-table = "expected" - } - .to_string() - .into(), - )); - - let (config, e, _) = config.apply_change(change); - expect_test::expect![[r#" - ConfigErrors( - [ - Toml { - config_key: "invalid/config/err", - error: Error { - inner: Error { - inner: TomlError { - message: "unexpected field", - raw: None, - keys: [], - span: None, - }, - }, - }, - }, - ], - ) - "#]] - .assert_debug_eq(&e); - let mut change = ConfigChange::default(); - - change.change_user_config(Some( - toml::toml! { - [cargo.cfgs] - these = "these" - should = "should" - be = "be" - valid = "valid" - } - .to_string() - .into(), - )); - let (_, e, _) = config.apply_change(change); - expect_test::expect![[r#" - ConfigErrors( - [], - ) - "#]] - .assert_debug_eq(&e); - } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 9d0082c370c7e..89487aa673bf6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -540,7 +540,7 @@ impl GlobalState { } pub(crate) fn respond(&mut self, response: lsp_server::Response) { - if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) { + if let Some((method, start)) = self.req_queue.incoming.complete(&response.id) { if let Some(err) = &response.error { if err.message.starts_with("server panicked") { self.poke_rust_analyzer_developer(format!("{}, check the log", err.message)) @@ -631,6 +631,10 @@ impl GlobalStateSnapshot { file_id_to_url(&self.vfs_read(), id) } + pub(crate) fn vfs_path_to_file_id(&self, vfs_path: &VfsPath) -> anyhow::Result { + vfs_path_to_file_id(&self.vfs_read(), vfs_path) + } + pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable { let endings = self.vfs.read().1[&file_id]; let index = self.analysis.file_line_index(file_id)?; @@ -725,3 +729,9 @@ pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> anyhow::Result anyhow::Result { + let res = + vfs.file_id(vfs_path).ok_or_else(|| anyhow::format_err!("file not found: {vfs_path}"))?; + Ok(res) +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs index f03de8ce0f038..ed7bf27843b5f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs @@ -325,14 +325,14 @@ impl NotificationDispatcher<'_> { pub(crate) fn on_sync_mut( &mut self, f: fn(&mut GlobalState, N::Params) -> anyhow::Result<()>, - ) -> anyhow::Result<&mut Self> + ) -> &mut Self where N: lsp_types::notification::Notification, N::Params: DeserializeOwned + Send + Debug, { let not = match self.not.take() { Some(it) => it, - None => return Ok(self), + None => return self, }; let _guard = tracing::info_span!("notification", method = ?not.method).entered(); @@ -344,7 +344,7 @@ impl NotificationDispatcher<'_> { } Err(ExtractError::MethodMismatch(not)) => { self.not = Some(not); - return Ok(self); + return self; } }; @@ -355,8 +355,10 @@ impl NotificationDispatcher<'_> { version(), N::METHOD )); - f(self.global_state, params)?; - Ok(self) + if let Err(e) = f(self.global_state, params) { + tracing::error!(handler = %N::METHOD, error = %e, "notification handler failed"); + } + self } pub(crate) fn finish(&mut self) { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index 38b88ff2d0403..49b1ba32a7958 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -145,14 +145,18 @@ pub(crate) fn handle_did_save_text_document( state: &mut GlobalState, params: DidSaveTextDocumentParams, ) -> anyhow::Result<()> { - if state.config.script_rebuild_on_save() && state.build_deps_changed { - state.build_deps_changed = false; - state - .fetch_build_data_queue - .request_op("build_deps_changed - save notification".to_owned(), ()); - } - if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { + let snap = state.snapshot(); + let file_id = snap.vfs_path_to_file_id(&vfs_path)?; + let sr = snap.analysis.source_root_id(file_id)?; + + if state.config.script_rebuild_on_save(Some(sr)) && state.build_deps_changed { + state.build_deps_changed = false; + state + .fetch_build_data_queue + .request_op("build_deps_changed - save notification".to_owned(), ()); + } + // Re-fetch workspaces if a workspace related file has changed if let Some(path) = vfs_path.as_path() { let additional_files = &state @@ -182,15 +186,16 @@ pub(crate) fn handle_did_save_text_document( } } - if !state.config.check_on_save() || run_flycheck(state, vfs_path) { + if !state.config.check_on_save(Some(sr)) || run_flycheck(state, vfs_path) { return Ok(()); } - } else if state.config.check_on_save() { + } else if state.config.check_on_save(None) { // No specific flycheck was triggered, so let's trigger all of them. for flycheck in state.flycheck.iter() { flycheck.restart_workspace(None); } } + Ok(()) } @@ -288,6 +293,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { let file_id = state.vfs.read().0.file_id(&vfs_path); if let Some(file_id) = file_id { let world = state.snapshot(); + let source_root_id = world.analysis.source_root_id(file_id).ok(); let mut updated = false; let task = move || -> std::result::Result<(), ide::Cancelled> { // Is the target binary? If so we let flycheck run only for the workspace that contains the crate. @@ -351,7 +357,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { .targets .iter() .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path())); - has_target_with_root.then(|| cargo[pkg].name.clone()) + has_target_with_root.then(|| cargo.package_flag(&cargo[pkg])) }), project_model::ProjectWorkspaceKind::Json(project) => { if !project.crates().any(|(_, krate)| { @@ -373,9 +379,9 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { for (id, package) in workspace_ids.clone() { if id == flycheck.id() { updated = true; - match package - .filter(|_| !world.config.flycheck_workspace() || target.is_some()) - { + match package.filter(|_| { + !world.config.flycheck_workspace(source_root_id) || target.is_some() + }) { Some(package) => flycheck .restart_for_package(package, target.clone().map(TupleExt::head)), None => flycheck.restart_workspace(saved_file.clone()), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 1ad5ff0c8cdc1..bcbd970a0d214 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -40,7 +40,10 @@ use crate::{ hack_recover_crate_name, line_index::LineEndings, lsp::{ - ext::InternalTestingFetchConfigParams, + ext::{ + InternalTestingFetchConfigOption, InternalTestingFetchConfigParams, + InternalTestingFetchConfigResponse, + }, from_proto, to_proto, utils::{all_edits_are_disjoint, invalid_params_error}, LspError, @@ -256,7 +259,7 @@ pub(crate) fn handle_run_test( let handle = CargoTestHandle::new( test_path, - state.config.cargo_test_options(), + state.config.cargo_test_options(None), cargo.workspace_root(), test_target, state.test_run_sender.clone(), @@ -565,7 +568,7 @@ pub(crate) fn handle_workspace_symbol( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_workspace_symbol").entered(); - let config = snap.config.workspace_symbol(); + let config = snap.config.workspace_symbol(None); let (all_symbols, libs) = decide_search_scope_and_kind(¶ms, &config); let query = { @@ -852,6 +855,7 @@ pub(crate) fn handle_runnables( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_runnables").entered(); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let source_root = snap.analysis.source_root_id(file_id).ok(); let line_index = snap.file_line_index(file_id)?; let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok()); let target_spec = TargetSpec::for_file(&snap, file_id)?; @@ -894,7 +898,7 @@ pub(crate) fn handle_runnables( } // Add `cargo check` and `cargo test` for all targets of the whole package - let config = snap.config.runnables(); + let config = snap.config.runnables(source_root); match target_spec { Some(TargetSpec::Cargo(spec)) => { let is_crate_no_std = snap.analysis.is_crate_no_std(spec.crate_id)?; @@ -1602,14 +1606,14 @@ pub(crate) fn handle_inlay_hints_resolve( anyhow::ensure!(snap.file_exists(file_id), "Invalid LSP resolve data"); let line_index = snap.file_line_index(file_id)?; - let hint_position = from_proto::offset(&line_index, original_hint.position)?; + let range = from_proto::text_range(&line_index, resolve_data.resolve_range)?; let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(); forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty(); let resolve_hints = snap.analysis.inlay_hints_resolve( &forced_resolve_inlay_hints_config, file_id, - hint_position, + range, hash, |hint| { std::hash::BuildHasher::hash_one( @@ -2119,7 +2123,7 @@ fn run_rustfmt( RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { // FIXME: Set RUSTUP_TOOLCHAIN let mut cmd = process::Command::new(toolchain::Tool::Rustfmt.path()); - cmd.envs(snap.config.extra_env()); + cmd.envs(snap.config.extra_env(source_root_id)); cmd.args(extra_args); if let Some(edition) = edition { @@ -2177,7 +2181,7 @@ fn run_rustfmt( _ => process::Command::new(cmd), }; - cmd.envs(snap.config.extra_env()); + cmd.envs(snap.config.extra_env(source_root_id)); cmd.args(args); cmd } @@ -2291,7 +2295,7 @@ pub(crate) fn fetch_dependency_list( pub(crate) fn internal_testing_fetch_config( state: GlobalStateSnapshot, params: InternalTestingFetchConfigParams, -) -> anyhow::Result { +) -> anyhow::Result> { let source_root = params .text_document .map(|it| { @@ -2301,15 +2305,18 @@ pub(crate) fn internal_testing_fetch_config( .map_err(anyhow::Error::from) }) .transpose()?; - serde_json::to_value(match &*params.config { - "local" => state.config.assist(source_root).assist_emit_must_use, - "workspace" => matches!( - state.config.rustfmt(source_root), - RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } - ), - _ => return Err(anyhow::anyhow!("Unknown test config key: {}", params.config)), - }) - .map_err(Into::into) + Ok(Some(match params.config { + InternalTestingFetchConfigOption::AssistEmitMustUse => { + InternalTestingFetchConfigResponse::AssistEmitMustUse( + state.config.assist(source_root).assist_emit_must_use, + ) + } + InternalTestingFetchConfigOption::CheckWorkspace => { + InternalTestingFetchConfigResponse::CheckWorkspace( + state.config.flycheck_workspace(source_root), + ) + } + })) } /// Searches for the directory of a Rust crate given this crate's root file path. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index 28f4b809d6c82..118469df730ce 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -167,6 +167,7 @@ fn integrated_completion_benchmark() { prefer_absolute: false, snippets: Vec::new(), limit: None, + add_semicolon_to_unit: true, }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; @@ -213,6 +214,7 @@ fn integrated_completion_benchmark() { prefer_absolute: false, snippets: Vec::new(), limit: None, + add_semicolon_to_unit: true, }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; @@ -257,6 +259,7 @@ fn integrated_completion_benchmark() { prefer_absolute: false, snippets: Vec::new(), limit: None, + add_semicolon_to_unit: true, }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 8d1a686dc4d41..618481bbc66b6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -16,9 +16,22 @@ use serde::{Deserialize, Serialize}; pub enum InternalTestingFetchConfig {} +#[derive(Deserialize, Serialize, Debug)] +pub enum InternalTestingFetchConfigOption { + AssistEmitMustUse, + CheckWorkspace, +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)] +pub enum InternalTestingFetchConfigResponse { + AssistEmitMustUse(bool), + CheckWorkspace(bool), +} + impl Request for InternalTestingFetchConfig { type Params = InternalTestingFetchConfigParams; - type Result = serde_json::Value; + // Option is solely to circumvent Default bound. + type Result = Option; const METHOD: &'static str = "rust-analyzer-internal/internalTestingFetchConfig"; } @@ -26,7 +39,7 @@ impl Request for InternalTestingFetchConfig { #[serde(rename_all = "camelCase")] pub struct InternalTestingFetchConfigParams { pub text_document: Option, - pub config: String, + pub config: InternalTestingFetchConfigOption, } pub enum AnalyzerStatus {} @@ -819,6 +832,7 @@ pub struct InlayHintResolveData { pub file_id: u32, // This is a string instead of a u64 as javascript can't represent u64 fully pub hash: String, + pub resolve_range: lsp_types::Range, pub version: Option, } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index eb6bc2a9ce9b0..4902c9f88c143 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -80,6 +80,7 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { | SymbolKind::ValueParam | SymbolKind::Label => lsp_types::SymbolKind::VARIABLE, SymbolKind::Union => lsp_types::SymbolKind::STRUCT, + SymbolKind::InlineAsmRegOrRegClass => lsp_types::SymbolKind::VARIABLE, } } @@ -159,6 +160,7 @@ pub(crate) fn completion_item_kind( SymbolKind::Variant => lsp_types::CompletionItemKind::ENUM_MEMBER, SymbolKind::BuiltinAttr => lsp_types::CompletionItemKind::FUNCTION, SymbolKind::ToolModule => lsp_types::CompletionItemKind::MODULE, + SymbolKind::InlineAsmRegOrRegClass => lsp_types::CompletionItemKind::KEYWORD, }, } } @@ -228,8 +230,12 @@ pub(crate) fn completion_items( line_index: &LineIndex, version: Option, tdpp: lsp_types::TextDocumentPositionParams, - items: Vec, + mut items: Vec, ) -> Vec { + if config.completion_hide_deprecated() { + items.retain(|item| !item.deprecated); + } + let max_relevance = items.iter().map(|it| it.relevance.score()).max().unwrap_or_default(); let mut res = Vec::with_capacity(items.len()); for item in items { @@ -452,10 +458,13 @@ pub(crate) fn inlay_hint( file_id: FileId, mut inlay_hint: InlayHint, ) -> Cancellable { - let resolve_hash = inlay_hint.needs_resolve().then(|| { - std::hash::BuildHasher::hash_one( - &std::hash::BuildHasherDefault::::default(), - &inlay_hint, + let resolve_range_and_hash = inlay_hint.needs_resolve().map(|range| { + ( + range, + std::hash::BuildHasher::hash_one( + &std::hash::BuildHasherDefault::::default(), + &inlay_hint, + ), ) }); @@ -465,7 +474,7 @@ pub(crate) fn inlay_hint( .visual_studio_code_version() // https://github.com/microsoft/vscode/issues/193124 .map_or(true, |version| VersionReq::parse(">=1.86.0").unwrap().matches(version)) - && resolve_hash.is_some() + && resolve_range_and_hash.is_some() && fields_to_resolve.resolve_text_edits { something_to_resolve |= inlay_hint.text_edit.is_some(); @@ -477,16 +486,17 @@ pub(crate) fn inlay_hint( snap, fields_to_resolve, &mut something_to_resolve, - resolve_hash.is_some(), + resolve_range_and_hash.is_some(), inlay_hint.label, )?; - let data = match resolve_hash { - Some(hash) if something_to_resolve => Some( + let data = match resolve_range_and_hash { + Some((resolve_range, hash)) if something_to_resolve => Some( to_value(lsp_ext::InlayHintResolveData { file_id: file_id.index(), hash: hash.to_string(), version: snap.file_version(file_id), + resolve_range: range(line_index, resolve_range), }) .unwrap(), ), @@ -694,6 +704,7 @@ fn semantic_token_type_and_modifiers( SymbolKind::ProcMacro => types::PROC_MACRO, SymbolKind::BuiltinAttr => types::BUILTIN_ATTRIBUTE, SymbolKind::ToolModule => types::TOOL_MODULE, + SymbolKind::InlineAsmRegOrRegClass => types::KEYWORD, }, HlTag::AttributeBracket => types::ATTRIBUTE_BRACKET, HlTag::BoolLiteral => types::BOOLEAN, @@ -1365,8 +1376,9 @@ pub(crate) fn runnable( snap: &GlobalStateSnapshot, runnable: Runnable, ) -> Cancellable> { - let config = snap.config.runnables(); let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id)?; + let source_root = snap.analysis.source_root_id(runnable.nav.file_id).ok(); + let config = snap.config.runnables(source_root); match target_spec { Some(TargetSpec::Cargo(spec)) => { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 616d6b49351c1..8355923025767 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -4,6 +4,7 @@ use std::{ fmt, ops::Div as _, + panic::AssertUnwindSafe, time::{Duration, Instant}, }; @@ -195,7 +196,7 @@ impl GlobalState { ) { return Ok(()); } - self.handle_event(event)?; + self.handle_event(event); } Err(anyhow::anyhow!("A receiver has been dropped, something panicked!")) @@ -277,7 +278,7 @@ impl GlobalState { .map(Some) } - fn handle_event(&mut self, event: Event) -> anyhow::Result<()> { + fn handle_event(&mut self, event: Event) { let loop_start = Instant::now(); let _p = tracing::info_span!("GlobalState::handle_event", event = %event).entered(); @@ -294,7 +295,7 @@ impl GlobalState { match event { Event::Lsp(msg) => match msg { lsp_server::Message::Request(req) => self.on_new_request(loop_start, req), - lsp_server::Message::Notification(not) => self.on_notification(not)?, + lsp_server::Message::Notification(not) => self.on_notification(not), lsp_server::Message::Response(resp) => self.complete_request(resp), }, Event::QueuedTask(task) => { @@ -404,7 +405,7 @@ impl GlobalState { if self.is_quiescent() { let became_quiescent = !was_quiescent; if became_quiescent { - if self.config.check_on_save() { + if self.config.check_on_save(None) { // Project has loaded properly, kick off initial flycheck self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None)); } @@ -434,7 +435,7 @@ impl GlobalState { let project_or_mem_docs_changed = became_quiescent || state_changed || memdocs_added_or_removed; - if project_or_mem_docs_changed && self.config.publish_diagnostics() { + if project_or_mem_docs_changed && self.config.publish_diagnostics(None) { self.update_diagnostics(); } if project_or_mem_docs_changed && self.config.test_explorer() { @@ -455,7 +456,7 @@ impl GlobalState { } } - if self.config.cargo_autoreload_config() + if self.config.cargo_autoreload_config(None) || self.config.discover_workspace_config().is_some() { if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) = @@ -486,7 +487,6 @@ impl GlobalState { "overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}" )); } - Ok(()) } fn prime_caches(&mut self, cause: String) { @@ -552,23 +552,33 @@ impl GlobalState { let fetch_semantic = self.vfs_done && self.fetch_workspaces_queue.last_op_result().is_some(); move |sender| { - let diags = fetch_native_diagnostics( - &snapshot, - subscriptions.clone(), - slice.clone(), - NativeDiagnosticsFetchKind::Syntax, - ); + // We aren't observing the semantics token cache here + let snapshot = AssertUnwindSafe(&snapshot); + let Ok(diags) = std::panic::catch_unwind(|| { + fetch_native_diagnostics( + &snapshot, + subscriptions.clone(), + slice.clone(), + NativeDiagnosticsFetchKind::Syntax, + ) + }) else { + return; + }; sender .send(Task::Diagnostics(DiagnosticsTaskKind::Syntax(generation, diags))) .unwrap(); if fetch_semantic { - let diags = fetch_native_diagnostics( - &snapshot, - subscriptions, - slice, - NativeDiagnosticsFetchKind::Semantic, - ); + let Ok(diags) = std::panic::catch_unwind(|| { + fetch_native_diagnostics( + &snapshot, + subscriptions.clone(), + slice.clone(), + NativeDiagnosticsFetchKind::Semantic, + ) + }) else { + return; + }; sender .send(Task::Diagnostics(DiagnosticsTaskKind::Semantic( generation, diags, @@ -875,7 +885,7 @@ impl GlobalState { self.discover_workspace_queue.op_completed(()); let mut config = Config::clone(&*self.config); - config.add_linked_projects(project, buildfile); + config.add_discovered_project_from_command(project, buildfile); self.update_configuration(config); } DiscoverProjectMessage::Progress { message } => { @@ -925,7 +935,7 @@ impl GlobalState { FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic } => { let snap = self.snapshot(); let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( - &self.config.diagnostics_map(), + &self.config.diagnostics_map(None), &diagnostic, &workspace_root, &snap, @@ -973,9 +983,9 @@ impl GlobalState { // When we're running multiple flychecks, we have to include a disambiguator in // the title, or the editor complains. Note that this is a user-facing string. let title = if self.flycheck.len() == 1 { - format!("{}", self.config.flycheck()) + format!("{}", self.config.flycheck(None)) } else { - format!("{} (#{})", self.config.flycheck(), id + 1) + format!("{} (#{})", self.config.flycheck(None), id + 1) }; self.report_progress( &title, @@ -1105,37 +1115,32 @@ impl GlobalState { } /// Handles an incoming notification. - fn on_notification(&mut self, not: Notification) -> anyhow::Result<()> { + fn on_notification(&mut self, not: Notification) { let _p = span!(Level::INFO, "GlobalState::on_notification", not.method = ?not.method).entered(); use crate::handlers::notification as handlers; use lsp_types::notification as notifs; NotificationDispatcher { not: Some(not), global_state: self } - .on_sync_mut::(handlers::handle_cancel)? + .on_sync_mut::(handlers::handle_cancel) .on_sync_mut::( handlers::handle_work_done_progress_cancel, - )? - .on_sync_mut::(handlers::handle_did_open_text_document)? - .on_sync_mut::( - handlers::handle_did_change_text_document, - )? - .on_sync_mut::(handlers::handle_did_close_text_document)? - .on_sync_mut::(handlers::handle_did_save_text_document)? + ) + .on_sync_mut::(handlers::handle_did_open_text_document) + .on_sync_mut::(handlers::handle_did_change_text_document) + .on_sync_mut::(handlers::handle_did_close_text_document) + .on_sync_mut::(handlers::handle_did_save_text_document) .on_sync_mut::( handlers::handle_did_change_configuration, - )? + ) .on_sync_mut::( handlers::handle_did_change_workspace_folders, - )? - .on_sync_mut::( - handlers::handle_did_change_watched_files, - )? - .on_sync_mut::(handlers::handle_cancel_flycheck)? - .on_sync_mut::(handlers::handle_clear_flycheck)? - .on_sync_mut::(handlers::handle_run_flycheck)? - .on_sync_mut::(handlers::handle_abort_run_test)? + ) + .on_sync_mut::(handlers::handle_did_change_watched_files) + .on_sync_mut::(handlers::handle_cancel_flycheck) + .on_sync_mut::(handlers::handle_clear_flycheck) + .on_sync_mut::(handlers::handle_run_flycheck) + .on_sync_mut::(handlers::handle_abort_run_test) .finish(); - Ok(()) } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs index eab9733872402..5c4c858e1509b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs @@ -37,9 +37,13 @@ impl Default for OpQueue { } impl OpQueue { + /// Request an operation to start. pub(crate) fn request_op(&mut self, reason: Cause, args: Args) { self.op_requested = Some((reason, args)); } + + /// If there was an operation requested, mark this queue as + /// started and return the request arguments. pub(crate) fn should_start_op(&mut self) -> Option<(Cause, Args)> { if self.op_in_progress { return None; @@ -47,18 +51,25 @@ impl OpQueue { self.op_in_progress = self.op_requested.is_some(); self.op_requested.take() } + + /// Mark an operation as completed. pub(crate) fn op_completed(&mut self, result: Output) { assert!(self.op_in_progress); self.op_in_progress = false; self.last_op_result = result; } + /// Get the result of the last operation. pub(crate) fn last_op_result(&self) -> &Output { &self.last_op_result } + + // Is there an operation that has started, but hasn't yet finished? pub(crate) fn op_in_progress(&self) -> bool { self.op_in_progress } + + // Has an operation been requested? pub(crate) fn op_requested(&self) -> bool { self.op_requested.is_some() } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 68366136eda60..f6765715c5a17 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -16,8 +16,9 @@ use std::{iter, mem}; use hir::{db::DefDatabase, ChangeWithProcMacros, ProcMacros, ProcMacrosBuilder}; +use ide::CrateId; use ide_db::{ - base_db::{salsa::Durability, CrateGraph, ProcMacroPaths, Version}, + base_db::{salsa::Durability, CrateGraph, CrateWorkspaceData, ProcMacroPaths}, FxHashMap, }; use itertools::Itertools; @@ -100,7 +101,7 @@ impl GlobalState { { let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }; self.fetch_workspaces_queue.request_op("discovered projects changed".to_owned(), req) - } else if self.config.flycheck() != old_config.flycheck() { + } else if self.config.flycheck(None) != old_config.flycheck(None) { self.reload_flycheck(); } @@ -122,7 +123,7 @@ impl GlobalState { }; let mut message = String::new(); - if !self.config.cargo_autoreload() + if !self.config.cargo_autoreload_config(None) && self.is_quiescent() && self.fetch_workspaces_queue.op_requested() && self.config.discover_workspace_config().is_none() @@ -264,7 +265,7 @@ impl GlobalState { .map(ManifestPath::try_from) .filter_map(Result::ok) .collect(); - let cargo_config = self.config.cargo(); + let cargo_config = self.config.cargo(None); let discover_command = self.config.discover_workspace_config().cloned(); let is_quiescent = !(self.discover_workspace_queue.op_in_progress() || self.vfs_progress_config_version < self.vfs_config_version @@ -357,7 +358,7 @@ impl GlobalState { pub(crate) fn fetch_build_data(&mut self, cause: Cause) { info!(%cause, "will fetch build data"); let workspaces = Arc::clone(&self.workspaces); - let config = self.config.cargo(); + let config = self.config.cargo(None); let root_path = self.config.root_path().clone(); self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| { @@ -382,7 +383,7 @@ impl GlobalState { pub(crate) fn fetch_proc_macros(&mut self, cause: Cause, paths: Vec) { info!(%cause, "will load proc macros"); - let ignored_proc_macros = self.config.ignored_proc_macros().clone(); + let ignored_proc_macros = self.config.ignored_proc_macros(None).clone(); let proc_macro_clients = self.proc_macro_clients.clone(); self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| { @@ -507,7 +508,7 @@ impl GlobalState { // FIXME: can we abort the build scripts here if they are already running? self.workspaces = Arc::new(workspaces); - if self.config.run_build_scripts() { + if self.config.run_build_scripts(None) { self.build_deps_changed = false; self.fetch_build_data_queue.request_op("workspace updated".to_owned(), ()); } @@ -627,7 +628,7 @@ impl GlobalState { .. } => cargo_config_extra_env .iter() - .chain(self.config.extra_env()) + .chain(self.config.extra_env(None)) .map(|(a, b)| (a.clone(), b.clone())) .chain( ws.sysroot @@ -692,7 +693,7 @@ impl GlobalState { }) .collect(); - let (crate_graph, proc_macro_paths, layouts, toolchains) = { + let (crate_graph, proc_macro_paths, ws_data) = { // Create crate graph from all the workspaces let vfs = &mut self.vfs.write().0; @@ -702,7 +703,7 @@ impl GlobalState { vfs.file_id(&vfs_path) }; - ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load) + ws_to_crate_graph(&self.workspaces, self.config.extra_env(None), load) }; let mut change = ChangeWithProcMacros::new(); if self.config.expand_proc_macros() { @@ -721,9 +722,7 @@ impl GlobalState { .collect(), ); } - change.set_crate_graph(crate_graph); - change.set_target_data_layouts(layouts); - change.set_toolchains(toolchains); + change.set_crate_graph(crate_graph, ws_data); self.analysis_host.apply_change(change); self.report_progress( "Building CrateGraph", @@ -791,7 +790,7 @@ impl GlobalState { fn reload_flycheck(&mut self) { let _p = tracing::info_span!("GlobalState::reload_flycheck").entered(); - let config = self.config.flycheck(); + let config = self.config.flycheck(None); let sender = self.flycheck_sender.clone(); let invocation_strategy = match config { FlycheckConfig::CargoCommand { .. } => { @@ -863,51 +862,27 @@ pub fn ws_to_crate_graph( workspaces: &[ProjectWorkspace], extra_env: &FxHashMap, mut load: impl FnMut(&AbsPath) -> Option, -) -> (CrateGraph, Vec, Vec, Arc>>, Vec>) { +) -> (CrateGraph, Vec, FxHashMap>) { let mut crate_graph = CrateGraph::default(); let mut proc_macro_paths = Vec::default(); - let mut layouts = Vec::default(); - let mut toolchains = Vec::default(); - let e = Err(Arc::from("missing layout")); + let mut ws_data = FxHashMap::default(); for ws in workspaces { let (other, mut crate_proc_macros) = ws.to_crate_graph(&mut load, extra_env); - let num_layouts = layouts.len(); - let num_toolchains = toolchains.len(); let ProjectWorkspace { toolchain, target_layout, .. } = ws; - let mapping = crate_graph.extend( - other, - &mut crate_proc_macros, - |(cg_id, cg_data), (_o_id, o_data)| { - // if the newly created crate graph's layout is equal to the crate of the merged graph, then - // we can merge the crates. - let id = cg_id.into_raw().into_u32() as usize; - layouts[id] == *target_layout && toolchains[id] == *toolchain && cg_data == o_data - }, - ); + let mapping = crate_graph.extend(other, &mut crate_proc_macros); // Populate the side tables for the newly merged crates - mapping.values().for_each(|val| { - let idx = val.into_raw().into_u32() as usize; - // we only need to consider crates that were not merged and remapped, as the - // ones that were remapped already have the correct layout and toolchain - if idx >= num_layouts { - if layouts.len() <= idx { - layouts.resize(idx + 1, e.clone()); - } - layouts[idx].clone_from(target_layout); - } - if idx >= num_toolchains { - if toolchains.len() <= idx { - toolchains.resize(idx + 1, None); - } - toolchains[idx].clone_from(toolchain); - } - }); + ws_data.extend(mapping.values().copied().zip(iter::repeat(Arc::new(CrateWorkspaceData { + toolchain: toolchain.clone(), + data_layout: target_layout.clone(), + proc_macro_cwd: Some(ws.workspace_root().to_owned()), + })))); proc_macro_paths.push(crate_proc_macros); } + crate_graph.shrink_to_fit(); proc_macro_paths.shrink_to_fit(); - (crate_graph, proc_macro_paths, layouts, toolchains) + (crate_graph, proc_macro_paths, ws_data) } pub(crate) fn should_refresh_for_change( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs index 954e13cbf2727..b4aa73d2780d6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs @@ -113,7 +113,7 @@ impl CargoTargetSpec { kind: &RunnableKind, cfg: &Option, ) -> (Vec, Vec) { - let config = snap.config.runnables(); + let config = snap.config.runnables(None); let extra_test_binary_args = config.extra_test_binary_args; let mut cargo_args = Vec::new(); @@ -168,7 +168,7 @@ impl CargoTargetSpec { (Default::default(), Default::default()) }; - let cargo_config = snap.config.cargo(); + let cargo_config = snap.config.cargo(None); match &cargo_config.features { CargoFeatures::All => { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs deleted file mode 100644 index 04b6713b8d188..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs +++ /dev/null @@ -1,126 +0,0 @@ -use std::path::PathBuf; - -use project_model::{ - CargoWorkspace, ManifestPath, Metadata, ProjectWorkspace, ProjectWorkspaceKind, Sysroot, - WorkspaceBuildScripts, -}; -use rust_analyzer::ws_to_crate_graph; -use rustc_hash::FxHashMap; -use serde::de::DeserializeOwned; -use vfs::{AbsPathBuf, FileId}; - -fn load_cargo_with_fake_sysroot(file: &str) -> ProjectWorkspace { - let meta: Metadata = get_test_json_file(file); - let manifest_path = - ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap(); - let cargo_workspace = CargoWorkspace::new(meta, manifest_path); - ProjectWorkspace { - kind: ProjectWorkspaceKind::Cargo { - cargo: cargo_workspace, - build_scripts: WorkspaceBuildScripts::default(), - rustc: Err(None), - cargo_config_extra_env: Default::default(), - error: None, - }, - sysroot: get_fake_sysroot(), - rustc_cfg: Vec::new(), - cfg_overrides: Default::default(), - toolchain: None, - target_layout: Err("target_data_layout not loaded".into()), - } -} - -fn get_test_json_file(file: &str) -> T { - let base = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let file = base.join("tests/test_data").join(file); - let data = std::fs::read_to_string(file).unwrap(); - let mut json = data.parse::().unwrap(); - fixup_paths(&mut json); - return serde_json::from_value(json).unwrap(); - - fn fixup_paths(val: &mut serde_json::Value) { - match val { - serde_json::Value::String(s) => replace_root(s, true), - serde_json::Value::Array(vals) => vals.iter_mut().for_each(fixup_paths), - serde_json::Value::Object(kvals) => kvals.values_mut().for_each(fixup_paths), - serde_json::Value::Null | serde_json::Value::Bool(_) | serde_json::Value::Number(_) => { - } - } - } -} - -fn replace_root(s: &mut String, direction: bool) { - if direction { - let root = if cfg!(windows) { r#"C:\\ROOT\"# } else { "/ROOT/" }; - *s = s.replace("$ROOT$", root) - } else { - let root = if cfg!(windows) { r#"C:\\\\ROOT\\"# } else { "/ROOT/" }; - *s = s.replace(root, "$ROOT$") - } -} - -fn get_fake_sysroot_path() -> PathBuf { - let base = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - base.join("../project-model/test_data/fake-sysroot") -} - -fn get_fake_sysroot() -> Sysroot { - let sysroot_path = get_fake_sysroot_path(); - // there's no `libexec/` directory with a `proc-macro-srv` binary in that - // fake sysroot, so we give them both the same path: - let sysroot_dir = AbsPathBuf::assert_utf8(sysroot_path); - let sysroot_src_dir = sysroot_dir.clone(); - Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir)) -} - -#[test] -fn test_deduplicate_origin_dev() { - let path_map = &mut FxHashMap::default(); - let ws = load_cargo_with_fake_sysroot("deduplication_crate_graph_A.json"); - let ws2 = load_cargo_with_fake_sysroot("deduplication_crate_graph_B.json"); - - let (crate_graph, ..) = ws_to_crate_graph(&[ws, ws2], &Default::default(), |path| { - let len = path_map.len(); - Some(*path_map.entry(path.to_path_buf()).or_insert(FileId::from_raw(len as u32))) - }); - - let mut crates_named_p2 = vec![]; - for id in crate_graph.iter() { - let krate = &crate_graph[id]; - if let Some(name) = krate.display_name.as_ref() { - if name.to_string() == "p2" { - crates_named_p2.push(krate); - } - } - } - - assert_eq!(crates_named_p2.len(), 1); - let p2 = crates_named_p2[0]; - assert!(p2.origin.is_local()); -} - -#[test] -fn test_deduplicate_origin_dev_rev() { - let path_map = &mut FxHashMap::default(); - let ws = load_cargo_with_fake_sysroot("deduplication_crate_graph_B.json"); - let ws2 = load_cargo_with_fake_sysroot("deduplication_crate_graph_A.json"); - - let (crate_graph, ..) = ws_to_crate_graph(&[ws, ws2], &Default::default(), |path| { - let len = path_map.len(); - Some(*path_map.entry(path.to_path_buf()).or_insert(FileId::from_raw(len as u32))) - }); - - let mut crates_named_p2 = vec![]; - for id in crate_graph.iter() { - let krate = &crate_graph[id]; - if let Some(name) = krate.display_name.as_ref() { - if name.to_string() == "p2" { - crates_named_p2.push(krate); - } - } - } - - assert_eq!(crates_named_p2.len(), 1); - let p2 = crates_named_p2[0]; - assert!(p2.origin.is_local()); -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs index 295d1d4e8e909..a857e0c2967c8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs @@ -9,18 +9,13 @@ use lsp_types::{ use paths::Utf8PathBuf; use rust_analyzer::config::Config; -use rust_analyzer::lsp::ext::{InternalTestingFetchConfig, InternalTestingFetchConfigParams}; +use rust_analyzer::lsp::ext::{ + InternalTestingFetchConfig, InternalTestingFetchConfigOption, InternalTestingFetchConfigParams, + InternalTestingFetchConfigResponse, +}; use serde_json::json; use test_utils::skip_slow_tests; -enum QueryType { - Local, - /// A query whose config key is a part of the global configs, so that - /// testing for changes to this config means testing if global changes - /// take affect. - Workspace, -} - struct RatomlTest { urls: Vec, server: Server, @@ -158,20 +153,24 @@ impl RatomlTest { }); } - fn query(&self, query: QueryType, source_file_idx: usize) -> bool { - let config = match query { - QueryType::Local => "local".to_owned(), - QueryType::Workspace => "workspace".to_owned(), - }; + fn query( + &self, + query: InternalTestingFetchConfigOption, + source_file_idx: usize, + expected: InternalTestingFetchConfigResponse, + ) { let res = self.server.send_request::( InternalTestingFetchConfigParams { text_document: Some(TextDocumentIdentifier { uri: self.urls[source_file_idx].clone(), }), - config, + config: query, }, ); - res.as_bool().unwrap() + assert_eq!( + serde_json::from_value::(res).unwrap(), + expected + ) } } @@ -206,7 +205,11 @@ enum Value { })), ); - assert!(server.query(QueryType::Local, 1)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 1, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); } /// Checks if client config can be modified. @@ -311,7 +314,11 @@ enum Value { None, ); - assert!(server.query(QueryType::Local, 2)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 2, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); } #[test] @@ -341,12 +348,20 @@ enum Value { None, ); - assert!(!server.query(QueryType::Local, 1)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 1, + InternalTestingFetchConfigResponse::AssistEmitMustUse(false), + ); server.create( "//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml", RatomlTest::EMIT_MUST_USE.to_owned(), ); - assert!(server.query(QueryType::Local, 1)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 1, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); } #[test] @@ -378,9 +393,17 @@ assist.emitMustUse = true"#, None, ); - assert!(server.query(QueryType::Local, 1)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 1, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); server.edit(2, String::new()); - assert!(!server.query(QueryType::Local, 1)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 1, + InternalTestingFetchConfigResponse::AssistEmitMustUse(false), + ); } #[test] @@ -412,9 +435,17 @@ assist.emitMustUse = true"#, None, ); - assert!(server.query(QueryType::Local, 1)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 1, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); server.delete(2); - assert!(!server.query(QueryType::Local, 1)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 1, + InternalTestingFetchConfigResponse::AssistEmitMustUse(false), + ); } #[test] @@ -461,7 +492,11 @@ pub fn add(left: usize, right: usize) -> usize { None, ); - assert!(server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); } #[test] @@ -508,9 +543,17 @@ pub fn add(left: usize, right: usize) -> usize { None, ); - assert!(!server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(false), + ); server.edit(1, "assist.emitMustUse = true".to_owned()); - assert!(server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); } #[test] @@ -557,9 +600,17 @@ pub fn add(left: usize, right: usize) -> usize { None, ); - assert!(server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); server.delete(1); - assert!(!server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(false), + ); } #[test] @@ -606,9 +657,17 @@ pub fn add(left: usize, right: usize) -> usize { None, ); - assert!(server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); server.create("//- /p1/p2/rust-analyzer.toml", RatomlTest::EMIT_MUST_NOT_USE.to_owned()); - assert!(!server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(false), + ); } #[test] @@ -656,9 +715,17 @@ pub fn add(left: usize, right: usize) -> usize { None, ); - assert!(server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); server.delete(1); - assert!(!server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(false), + ); } #[test] @@ -705,8 +772,16 @@ enum Value { None, ); - assert!(server.query(QueryType::Local, 3)); - assert!(server.query(QueryType::Local, 4)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 4, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); } #[test] @@ -744,7 +819,11 @@ fn ratoml_multiple_ratoml_in_single_source_root() { None, ); - assert!(server.query(QueryType::Local, 3)); + server.query( + InternalTestingFetchConfigOption::AssistEmitMustUse, + 3, + InternalTestingFetchConfigResponse::AssistEmitMustUse(true), + ); } /// If a root is non-local, so we cannot find what its parent is @@ -765,7 +844,7 @@ fn ratoml_multiple_ratoml_in_single_source_root() { // [dependencies] // p2 = { path = "../p2" } -// #, +// "#, // r#" // //- /p1/src/lib.rs // enum Value { @@ -836,7 +915,7 @@ edition = "2021" "#, r#" //- /p1/rust-analyzer.toml -rustfmt.rangeFormatting.enable = true +check.workspace = false "#, r#" //- /p1/src/lib.rs @@ -848,7 +927,11 @@ fn main() { None, ); - assert!(server.query(QueryType::Workspace, 2)); + server.query( + InternalTestingFetchConfigOption::CheckWorkspace, + 2, + InternalTestingFetchConfigResponse::CheckWorkspace(false), + ) } #[test] @@ -868,7 +951,7 @@ edition = "2021" "#, r#" //- /p1/rust-analyzer.toml -rustfmt.rangeFormatting.enable = true +check.workspace = false "#, r#" //- /p1/src/lib.rs @@ -880,9 +963,17 @@ fn main() { None, ); - assert!(server.query(QueryType::Workspace, 2)); - server.edit(1, "rustfmt.rangeFormatting.enable = false".to_owned()); - assert!(!server.query(QueryType::Workspace, 2)); + server.query( + InternalTestingFetchConfigOption::CheckWorkspace, + 2, + InternalTestingFetchConfigResponse::CheckWorkspace(false), + ); + server.edit(1, "check.workspace = true".to_owned()); + server.query( + InternalTestingFetchConfigOption::CheckWorkspace, + 2, + InternalTestingFetchConfigResponse::CheckWorkspace(true), + ); } #[test] @@ -902,7 +993,7 @@ edition = "2021" "#, r#" //- /p1/rust-analyzer.toml -rustfmt.rangeFormatting.enable = true +check.workspace = false "#, r#" //- /p1/src/lib.rs @@ -914,7 +1005,15 @@ fn main() { None, ); - assert!(server.query(QueryType::Workspace, 2)); + server.query( + InternalTestingFetchConfigOption::CheckWorkspace, + 2, + InternalTestingFetchConfigResponse::CheckWorkspace(false), + ); server.delete(1); - assert!(!server.query(QueryType::Workspace, 2)); + server.query( + InternalTestingFetchConfigOption::CheckWorkspace, + 2, + InternalTestingFetchConfigResponse::CheckWorkspace(true), + ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_A.json b/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_A.json deleted file mode 100644 index b0fb5845cef76..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_A.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "packages": [ - { - "name": "p1", - "version": "0.1.0", - "id": "p1 0.1.0 (path+file:///example_project/p1)", - "license": null, - "license_file": null, - "description": null, - "source": null, - "dependencies": [ - { - "name": "p2", - "source": null, - "req": "*", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "$ROOT$example_project/p2" - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "p1", - "src_path": "$ROOT$example_project/p1/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$example_project/p1/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [], - "categories": [], - "keywords": [], - "readme": null, - "repository": null, - "homepage": null, - "documentation": null, - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": null - }, - { - "name": "p2", - "version": "0.1.0", - "id": "p2 0.1.0 (path+file:///example_project/p2)", - "license": null, - "license_file": null, - "description": null, - "source": null, - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "p2", - "src_path": "$ROOT$example_project/p2/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$example_project/p2/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [], - "categories": [], - "keywords": [], - "readme": null, - "repository": null, - "homepage": null, - "documentation": null, - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": null - } - ], - "workspace_members": [ - "p1 0.1.0 (path+file:///example_project/p1)" - ], - "workspace_default_members": [ - "p1 0.1.0 (path+file:///example_project/p1)" - ], - "resolve": { - "nodes": [ - { - "id": "p1 0.1.0 (path+file:///example_project/p1)", - "dependencies": [ - "p2 0.1.0 (path+file:///example_project/p2)" - ], - "deps": [ - { - "name": "p2", - "pkg": "p2 0.1.0 (path+file:///example_project/p2)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "p2 0.1.0 (path+file:///example_project/p2)", - "dependencies": [], - "deps": [], - "features": [] - } - ], - "root": "p1 0.1.0 (path+file:///example_project/p1)" - }, - "target_directory": "$ROOT$example_project/p1/target", - "version": 1, - "workspace_root": "$ROOT$example_project/p1", - "metadata": null -} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_B.json b/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_B.json deleted file mode 100644 index b5d1e16e62e03..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_B.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "packages": [ - { - "name": "p2", - "version": "0.1.0", - "id": "p2 0.1.0 (path+file:///example_project/p2)", - "license": null, - "license_file": null, - "description": null, - "source": null, - "dependencies": [], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "p2", - "src_path": "$ROOT$example_project/p2/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$example_project/p2/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [], - "categories": [], - "keywords": [], - "readme": null, - "repository": null, - "homepage": null, - "documentation": null, - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": null - } - ], - "workspace_members": [ - "p2 0.1.0 (path+file:///example_project/p2)" - ], - "workspace_default_members": [ - "p2 0.1.0 (path+file:///example_project/p2)" - ], - "resolve": { - "nodes": [ - { - "id": "p2 0.1.0 (path+file:///example_project/p2)", - "dependencies": [], - "deps": [], - "features": [] - } - ], - "root": "p2 0.1.0 (path+file:///example_project/p2)" - }, - "target_directory": "$ROOT$example_project/p2/target", - "version": 1, - "workspace_root": "$ROOT$example_project/p2", - "metadata": null -} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index 874480c59fbf3..cb9c092f5fcd0 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -81,7 +81,7 @@ pub struct SyntaxContextData { /// Invariant: Only [`SyntaxContextId::ROOT`] has a [`None`] outer expansion. // FIXME: The None case needs to encode the context crate id. We can encode that as the MSB of // MacroCallId is reserved anyways so we can do bit tagging here just fine. - // The bigger issue is that that will cause interning to now create completely separate chains + // The bigger issue is that this will cause interning to now create completely separate chains // per crate. Though that is likely not a problem as `MacroCallId`s are already crate calling dependent. pub outer_expn: Option, pub outer_transparency: Transparency, diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs index c539754979d6a..f80de05ec6521 100644 --- a/src/tools/rust-analyzer/crates/span/src/map.rs +++ b/src/tools/rust-analyzer/crates/span/src/map.rs @@ -13,6 +13,7 @@ use crate::{ /// Maps absolute text ranges for the corresponding file to the relevant span data. #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct SpanMap { + /// The offset stored here is the *end* of the node. spans: Vec<(TextSize, SpanData)>, /// Index of the matched macro arm on successful expansion for declarative macros. // FIXME: Does it make sense to have this here? @@ -104,6 +105,52 @@ where pub fn iter(&self) -> impl Iterator)> + '_ { self.spans.iter().copied() } + + /// Merges this span map with another span map, where `other` is inserted at (and replaces) `other_range`. + /// + /// The length of the replacement node needs to be `other_size`. + pub fn merge(&mut self, other_range: TextRange, other_size: TextSize, other: &SpanMap) { + // I find the following diagram helpful to illustrate the bounds and why we use `<` or `<=`: + // -------------------------------------------------------------------- + // 1 3 5 6 7 10 11 <-- offsets we store + // 0-1 1-3 3-5 5-6 6-7 7-10 10-11 <-- ranges these offsets refer to + // 3 .. 7 <-- other_range + // 3-5 5-6 6-7 <-- ranges we replace (len = 7-3 = 4) + // ^^^^^^^^^^^ ^^^^^^^^^^ + // remove shift + // 2 3 5 9 <-- offsets we insert + // 0-2 2-3 3-5 5-9 <-- ranges we insert (other_size = 9-0 = 9) + // ------------------------------------ + // 1 3 + // 0-1 1-3 <-- these remain intact + // 5 6 8 12 + // 3-5 5-6 6-8 8-12 <-- we shift these by other_range.start() and insert them + // 15 16 + // 12-15 15-16 <-- we shift these by other_size-other_range.len() = 9-4 = 5 + // ------------------------------------ + // 1 3 5 6 8 12 15 16 <-- final offsets we store + // 0-1 1-3 3-5 5-6 6-8 8-12 12-15 15-16 <-- final ranges + + self.spans.retain_mut(|(offset, _)| { + if other_range.start() < *offset && *offset <= other_range.end() { + false + } else { + if *offset > other_range.end() { + *offset += other_size; + *offset -= other_range.len(); + } + true + } + }); + + self.spans + .extend(other.spans.iter().map(|&(offset, span)| (offset + other_range.start(), span))); + + self.spans.sort_unstable_by_key(|&(offset, _)| offset); + + // Matched arm info is no longer correct once we have multiple macros. + self.matched_arm = None; + } } #[derive(PartialEq, Eq, Hash, Debug)] diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index 56e43e82ed27a..0ccd08867602c 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -17,6 +17,7 @@ use tt::{ token_to_literal, }; +pub mod prettify_macro_expansion; mod to_parser_input; pub use to_parser_input::to_parser_input; // FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs similarity index 85% rename from src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs rename to src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs index dd4a665e8eb4f..fc7caaa988658 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs @@ -7,13 +7,20 @@ use syntax::{ SyntaxNode, SyntaxToken, WalkEvent, T, }; -// FIXME: It would also be cool to share logic here and in the mbe tests, -// which are pretty unreadable at the moment. /// Renders a [`SyntaxNode`] with whitespace inserted between tokens that require them. -pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { +/// +/// This is an internal API that is only exported because `mbe` needs it for tests and cannot depend +/// on `hir-expand`. For any purpose other than tests, you are supposed to use the `prettify_macro_expansion` +/// from `hir-expand` that handles `$crate` for you. +#[deprecated = "use `hir_expand::prettify_macro_expansion()` instead"] +pub fn prettify_macro_expansion( + syn: SyntaxNode, + dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> SyntaxToken, +) -> SyntaxNode { let mut indent = 0; let mut last: Option = None; let mut mods = Vec::new(); + let mut dollar_crate_replacements = Vec::new(); let syn = syn.clone_subtree().clone_for_update(); let before = Position::before; @@ -51,6 +58,9 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { } _ => continue, }; + if token.kind() == SyntaxKind::IDENT && token.text() == "$crate" { + dollar_crate_replacements.push((token.clone(), dollar_crate_replacement(&token))); + } let tok = &token; let is_next = |f: fn(SyntaxKind) -> bool, default| -> bool { @@ -122,6 +132,9 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { for (pos, insert) in mods { ted::insert(pos, insert); } + for (old, new) in dollar_crate_replacements { + ted::replace(old, new); + } if let Some(it) = syn.last_token().filter(|it| it.kind() == SyntaxKind::WHITESPACE) { ted::remove(it); diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 43375ce6ae051..52ad439e4decc 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -391,8 +391,33 @@ Expr = OffsetOfExpr = Attr* 'builtin' '#' 'offset_of' '(' Type ',' fields:(NameRef ('.' NameRef)* ) ')' +// asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")" +// global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")" +// format_string := STRING_LITERAL / RAW_STRING_LITERAL AsmExpr = - Attr* 'builtin' '#' 'asm' '(' Expr ')' + Attr* 'builtin' '#' 'asm' '(' template:(Expr (',' Expr)*) (AsmPiece (',' AsmPiece)*)? ','? ')' + +// operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" +AsmOperandExpr = in_expr:Expr ('=>' out_expr:Expr)? +// dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout" +AsmDirSpec = 'in' | 'out' | 'lateout' | 'inout' | 'inlateout' +// reg_spec := / "\"" "\"" +AsmRegSpec = '@string' | NameRef +// reg_operand := [ident "="] dir_spec "(" reg_spec ")" operand_expr +AsmRegOperand = AsmDirSpec '(' AsmRegSpec ')' AsmOperandExpr +// clobber_abi := "clobber_abi(" *("," ) [","] ")" +AsmClobberAbi = 'clobber_abi' '(' ('@string' (',' '@string')* ','?) ')' +// option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" +AsmOption = 'pure' | 'nomem' | 'readonly' | 'preserves_flags' | 'noreturn' | 'nostack' | 'att_syntax' | 'raw' | 'may_unwind' +// options := "options(" option *("," option) [","] ")" +AsmOptions = 'options' '(' AsmOption *(',' AsmOption) ','? ')' +AsmLabel = 'label' BlockExpr +AsmSym = 'sym' Path +AsmConst = 'const' Expr +// operand := reg_operand / clobber_abi / options +AsmOperand = AsmRegOperand | AsmLabel | AsmSym | AsmConst +AsmOperandNamed = (Name '=')? AsmOperand +AsmPiece = AsmOperandNamed | AsmClobberAbi | AsmOptions FormatArgsExpr = Attr* 'builtin' '#' 'format_args' '(' diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index c9b39e9922c92..c81a19f3bda41 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -64,6 +64,53 @@ impl ArrayType { pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmClobberAbi { + pub(crate) syntax: SyntaxNode, +} +impl AsmClobberAbi { + #[inline] + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + #[inline] + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + #[inline] + pub fn clobber_abi_token(&self) -> Option { + support::token(&self.syntax, T![clobber_abi]) + } + #[inline] + pub fn string_token(&self) -> Option { support::token(&self.syntax, T![string]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmConst { + pub(crate) syntax: SyntaxNode, +} +impl AsmConst { + #[inline] + pub fn expr(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmDirSpec { + pub(crate) syntax: SyntaxNode, +} +impl AsmDirSpec { + #[inline] + pub fn in_token(&self) -> Option { support::token(&self.syntax, T![in]) } + #[inline] + pub fn inlateout_token(&self) -> Option { + support::token(&self.syntax, T![inlateout]) + } + #[inline] + pub fn inout_token(&self) -> Option { support::token(&self.syntax, T![inout]) } + #[inline] + pub fn lateout_token(&self) -> Option { support::token(&self.syntax, T![lateout]) } + #[inline] + pub fn out_token(&self) -> Option { support::token(&self.syntax, T![out]) } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AsmExpr { pub(crate) syntax: SyntaxNode, @@ -71,7 +118,9 @@ pub struct AsmExpr { impl ast::HasAttrs for AsmExpr {} impl AsmExpr { #[inline] - pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn asm_pieces(&self) -> AstChildren { support::children(&self.syntax) } + #[inline] + pub fn template(&self) -> AstChildren { support::children(&self.syntax) } #[inline] pub fn pound_token(&self) -> Option { support::token(&self.syntax, T![#]) } #[inline] @@ -79,11 +128,142 @@ impl AsmExpr { #[inline] pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } #[inline] + pub fn comma_token(&self) -> Option { support::token(&self.syntax, T![,]) } + #[inline] pub fn asm_token(&self) -> Option { support::token(&self.syntax, T![asm]) } #[inline] pub fn builtin_token(&self) -> Option { support::token(&self.syntax, T![builtin]) } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmLabel { + pub(crate) syntax: SyntaxNode, +} +impl AsmLabel { + #[inline] + pub fn block_expr(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn label_token(&self) -> Option { support::token(&self.syntax, T![label]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmOperandExpr { + pub(crate) syntax: SyntaxNode, +} +impl AsmOperandExpr { + #[inline] + pub fn in_expr(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn out_expr(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn fat_arrow_token(&self) -> Option { support::token(&self.syntax, T![=>]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmOperandNamed { + pub(crate) syntax: SyntaxNode, +} +impl ast::HasName for AsmOperandNamed {} +impl AsmOperandNamed { + #[inline] + pub fn asm_operand(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmOption { + pub(crate) syntax: SyntaxNode, +} +impl AsmOption { + #[inline] + pub fn att_syntax_token(&self) -> Option { + support::token(&self.syntax, T![att_syntax]) + } + #[inline] + pub fn may_unwind_token(&self) -> Option { + support::token(&self.syntax, T![may_unwind]) + } + #[inline] + pub fn nomem_token(&self) -> Option { support::token(&self.syntax, T![nomem]) } + #[inline] + pub fn noreturn_token(&self) -> Option { + support::token(&self.syntax, T![noreturn]) + } + #[inline] + pub fn nostack_token(&self) -> Option { support::token(&self.syntax, T![nostack]) } + #[inline] + pub fn preserves_flags_token(&self) -> Option { + support::token(&self.syntax, T![preserves_flags]) + } + #[inline] + pub fn pure_token(&self) -> Option { support::token(&self.syntax, T![pure]) } + #[inline] + pub fn raw_token(&self) -> Option { support::token(&self.syntax, T![raw]) } + #[inline] + pub fn readonly_token(&self) -> Option { + support::token(&self.syntax, T![readonly]) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmOptions { + pub(crate) syntax: SyntaxNode, +} +impl AsmOptions { + #[inline] + pub fn asm_option(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn asm_options(&self) -> AstChildren { support::children(&self.syntax) } + #[inline] + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + #[inline] + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + #[inline] + pub fn comma_token(&self) -> Option { support::token(&self.syntax, T![,]) } + #[inline] + pub fn options_token(&self) -> Option { support::token(&self.syntax, T![options]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmRegOperand { + pub(crate) syntax: SyntaxNode, +} +impl AsmRegOperand { + #[inline] + pub fn asm_dir_spec(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn asm_operand_expr(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn asm_reg_spec(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + #[inline] + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmRegSpec { + pub(crate) syntax: SyntaxNode, +} +impl AsmRegSpec { + #[inline] + pub fn name_ref(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn string_token(&self) -> Option { support::token(&self.syntax, T![string]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsmSym { + pub(crate) syntax: SyntaxNode, +} +impl AsmSym { + #[inline] + pub fn path(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn sym_token(&self) -> Option { support::token(&self.syntax, T![sym]) } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AssocItemList { pub(crate) syntax: SyntaxNode, @@ -2051,6 +2231,21 @@ impl ast::HasGenericParams for Adt {} impl ast::HasName for Adt {} impl ast::HasVisibility for Adt {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum AsmOperand { + AsmConst(AsmConst), + AsmLabel(AsmLabel), + AsmRegOperand(AsmRegOperand), + AsmSym(AsmSym), +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum AsmPiece { + AsmClobberAbi(AsmClobberAbi), + AsmOperandNamed(AsmOperandNamed), + AsmOptions(AsmOptions), +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum AssocItem { Const(Const), @@ -2316,6 +2511,48 @@ impl AstNode for ArrayType { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for AsmClobberAbi { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CLOBBER_ABI } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmConst { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CONST } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmDirSpec { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_DIR_SPEC } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for AsmExpr { #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR } @@ -2330,6 +2567,118 @@ impl AstNode for AsmExpr { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for AsmLabel { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_LABEL } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmOperandExpr { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_EXPR } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmOperandNamed { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_NAMED } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmOption { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTION } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmOptions { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTIONS } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmRegOperand { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_OPERAND } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmRegSpec { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_SPEC } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AstNode for AsmSym { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_SYM } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for AssocItemList { #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST } @@ -4268,6 +4617,84 @@ impl AstNode for Adt { } } } +impl From for AsmOperand { + #[inline] + fn from(node: AsmConst) -> AsmOperand { AsmOperand::AsmConst(node) } +} +impl From for AsmOperand { + #[inline] + fn from(node: AsmLabel) -> AsmOperand { AsmOperand::AsmLabel(node) } +} +impl From for AsmOperand { + #[inline] + fn from(node: AsmRegOperand) -> AsmOperand { AsmOperand::AsmRegOperand(node) } +} +impl From for AsmOperand { + #[inline] + fn from(node: AsmSym) -> AsmOperand { AsmOperand::AsmSym(node) } +} +impl AstNode for AsmOperand { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, ASM_CONST | ASM_LABEL | ASM_REG_OPERAND | ASM_SYM) + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + ASM_CONST => AsmOperand::AsmConst(AsmConst { syntax }), + ASM_LABEL => AsmOperand::AsmLabel(AsmLabel { syntax }), + ASM_REG_OPERAND => AsmOperand::AsmRegOperand(AsmRegOperand { syntax }), + ASM_SYM => AsmOperand::AsmSym(AsmSym { syntax }), + _ => return None, + }; + Some(res) + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + match self { + AsmOperand::AsmConst(it) => &it.syntax, + AsmOperand::AsmLabel(it) => &it.syntax, + AsmOperand::AsmRegOperand(it) => &it.syntax, + AsmOperand::AsmSym(it) => &it.syntax, + } + } +} +impl From for AsmPiece { + #[inline] + fn from(node: AsmClobberAbi) -> AsmPiece { AsmPiece::AsmClobberAbi(node) } +} +impl From for AsmPiece { + #[inline] + fn from(node: AsmOperandNamed) -> AsmPiece { AsmPiece::AsmOperandNamed(node) } +} +impl From for AsmPiece { + #[inline] + fn from(node: AsmOptions) -> AsmPiece { AsmPiece::AsmOptions(node) } +} +impl AstNode for AsmPiece { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, ASM_CLOBBER_ABI | ASM_OPERAND_NAMED | ASM_OPTIONS) + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + ASM_CLOBBER_ABI => AsmPiece::AsmClobberAbi(AsmClobberAbi { syntax }), + ASM_OPERAND_NAMED => AsmPiece::AsmOperandNamed(AsmOperandNamed { syntax }), + ASM_OPTIONS => AsmPiece::AsmOptions(AsmOptions { syntax }), + _ => return None, + }; + Some(res) + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + match self { + AsmPiece::AsmClobberAbi(it) => &it.syntax, + AsmPiece::AsmOperandNamed(it) => &it.syntax, + AsmPiece::AsmOptions(it) => &it.syntax, + } + } +} impl From for AssocItem { #[inline] fn from(node: Const) -> AssocItem { AssocItem::Const(node) } @@ -5803,7 +6230,8 @@ impl AstNode for AnyHasName { fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - CONST + ASM_OPERAND_NAMED + | CONST | CONST_PARAM | ENUM | FN @@ -5832,6 +6260,10 @@ impl AstNode for AnyHasName { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl From for AnyHasName { + #[inline] + fn from(node: AsmOperandNamed) -> AnyHasName { AnyHasName { syntax: node.syntax } } +} impl From for AnyHasName { #[inline] fn from(node: Const) -> AnyHasName { AnyHasName { syntax: node.syntax } } @@ -6072,6 +6504,16 @@ impl std::fmt::Display for Adt { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AsmOperand { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmPiece { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AssocItem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -6142,11 +6584,66 @@ impl std::fmt::Display for ArrayType { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AsmClobberAbi { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmConst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmDirSpec { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AsmExpr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AsmLabel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmOperandExpr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmOperandNamed { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmOption { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmOptions { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmRegOperand { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmRegSpec { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AsmSym { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AssocItemList { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index abf1a1f38207f..fcdc97ce32704 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -1162,7 +1162,7 @@ pub mod tokens { pub(super) static SOURCE_FILE: LazyLock> = LazyLock::new(|| { SourceFile::parse( - "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, { let _ @ [] })\n;\n\nimpl A for B where: {}", Edition::CURRENT, + "use crate::foo; const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, async { let _ @ [] })\n;\n\nimpl A for B where: {}", Edition::CURRENT, ) }); @@ -1188,6 +1188,17 @@ pub mod tokens { .unwrap() } + pub fn crate_kw() -> SyntaxToken { + SOURCE_FILE + .tree() + .syntax() + .clone_for_update() + .descendants_with_tokens() + .filter_map(|it| it.into_token()) + .find(|it| it.kind() == CRATE_KW) + .unwrap() + } + pub fn whitespace(text: &str) -> SyntaxToken { assert!(text.trim().is_empty()); let sf = SourceFile::parse(text, Edition::CURRENT).ok().unwrap(); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/traits.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/traits.rs index 152b0cb98c2ab..5d6aa4331b02c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/traits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/traits.rs @@ -75,6 +75,33 @@ pub trait HasAttrs: AstNode { fn has_atom_attr(&self, atom: &str) -> bool { self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom) } + + /// Returns all attributes of this node, including inner attributes that may not be directly under this node + /// but under a child. + fn attrs_including_inner(self) -> impl Iterator + where + Self: Sized, + { + let inner_attrs_node = if let Some(it) = + support::child::(self.syntax()).and_then(|it| it.stmt_list()) + { + Some(it.syntax) + } else if let Some(it) = support::child::(self.syntax()) { + Some(it.syntax) + } else if let Some(it) = support::child::(self.syntax()) { + Some(it.syntax) + } else if let Some(it) = support::child::(self.syntax()) { + Some(it.syntax) + } else if let Some(it) = support::child::(self.syntax()) { + Some(it.syntax) + } else if let Some(it) = support::child::(self.syntax()) { + Some(it.syntax) + } else { + None + }; + + self.attrs().chain(inner_attrs_node.into_iter().flat_map(|it| support::children(&it))) + } } pub trait HasDocComments: HasAttrs { diff --git a/src/tools/rust-analyzer/crates/syntax/src/hacks.rs b/src/tools/rust-analyzer/crates/syntax/src/hacks.rs index 9e63448ce9630..2184359f1d0c4 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/hacks.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/hacks.rs @@ -8,10 +8,15 @@ use crate::{ast, AstNode}; pub fn parse_expr_from_str(s: &str, edition: Edition) -> Option { let s = s.trim(); - let file = ast::SourceFile::parse(&format!("const _: () = {s};"), edition); - let expr = file.syntax_node().descendants().find_map(ast::Expr::cast)?; - if expr.syntax().text() != s { - return None; - } - Some(expr) + + let file = ast::SourceFile::parse( + // Need a newline because the text may contain line comments. + &format!("const _: () = ({s}\n);"), + edition, + ); + let expr = file.syntax_node().descendants().find_map(ast::ParenExpr::cast)?; + // Can't check the text because the original text may contain whitespace and comments. + // Wrap in parentheses to better allow for verification. Of course, the real fix is + // to get rid of this hack. + expr.expr() } diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index b68374848b90c..c1554c4b2942a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -40,6 +40,7 @@ pub mod ast; #[doc(hidden)] pub mod fuzz; pub mod hacks; +pub mod syntax_editor; pub mod ted; pub mod utils; @@ -65,7 +66,7 @@ pub use rowan::{ TokenAtOffset, WalkEvent, }; pub use rustc_lexer::unescape; -pub use smol_str::{format_smolstr, SmolStr, ToSmolStr}; +pub use smol_str::{format_smolstr, SmolStr, SmolStrBuilder, ToSmolStr}; /// `Parse` is the result of the parsing: a syntax tree and a collection of /// errors. diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs new file mode 100644 index 0000000000000..eb114f5e5f1f7 --- /dev/null +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -0,0 +1,611 @@ +//! Syntax Tree editor +//! +//! Inspired by Roslyn's [`SyntaxEditor`], but is temporarily built upon mutable syntax tree editing. +//! +//! [`SyntaxEditor`]: https://github.com/dotnet/roslyn/blob/43b0b05cc4f492fd5de00f6f6717409091df8daa/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs + +use std::{ + num::NonZeroU32, + ops::RangeInclusive, + sync::atomic::{AtomicU32, Ordering}, +}; + +use rowan::TextRange; +use rustc_hash::FxHashMap; + +use crate::{SyntaxElement, SyntaxNode, SyntaxToken}; + +mod edit_algo; +mod mapping; + +pub use mapping::{SyntaxMapping, SyntaxMappingBuilder}; + +#[derive(Debug)] +pub struct SyntaxEditor { + root: SyntaxNode, + changes: Vec, + mappings: SyntaxMapping, + annotations: Vec<(SyntaxElement, SyntaxAnnotation)>, +} + +impl SyntaxEditor { + /// Creates a syntax editor to start editing from `root` + pub fn new(root: SyntaxNode) -> Self { + Self { root, changes: vec![], mappings: SyntaxMapping::new(), annotations: vec![] } + } + + pub fn add_annotation(&mut self, element: impl Element, annotation: SyntaxAnnotation) { + self.annotations.push((element.syntax_element(), annotation)) + } + + pub fn merge(&mut self, mut other: SyntaxEditor) { + debug_assert!( + self.root == other.root || other.root.ancestors().any(|node| node == self.root), + "{:?} is not in the same tree as {:?}", + other.root, + self.root + ); + + self.changes.append(&mut other.changes); + self.mappings.merge(other.mappings); + self.annotations.append(&mut other.annotations); + } + + pub fn insert(&mut self, position: Position, element: impl Element) { + debug_assert!(is_ancestor_or_self(&position.parent(), &self.root)); + self.changes.push(Change::Insert(position, element.syntax_element())) + } + + pub fn insert_all(&mut self, position: Position, elements: Vec) { + debug_assert!(is_ancestor_or_self(&position.parent(), &self.root)); + self.changes.push(Change::InsertAll(position, elements)) + } + + pub fn delete(&mut self, element: impl Element) { + let element = element.syntax_element(); + debug_assert!(is_ancestor_or_self_of_element(&element, &self.root)); + debug_assert!( + !matches!(&element, SyntaxElement::Node(node) if node == &self.root), + "should not delete root node" + ); + self.changes.push(Change::Replace(element.syntax_element(), None)); + } + + pub fn replace(&mut self, old: impl Element, new: impl Element) { + let old = old.syntax_element(); + debug_assert!(is_ancestor_or_self_of_element(&old, &self.root)); + self.changes.push(Change::Replace(old.syntax_element(), Some(new.syntax_element()))); + } + + pub fn replace_with_many(&mut self, old: impl Element, new: Vec) { + let old = old.syntax_element(); + debug_assert!(is_ancestor_or_self_of_element(&old, &self.root)); + debug_assert!( + !(matches!(&old, SyntaxElement::Node(node) if node == &self.root) && new.len() > 1), + "cannot replace root node with many elements" + ); + self.changes.push(Change::ReplaceWithMany(old.syntax_element(), new)); + } + + pub fn replace_all(&mut self, range: RangeInclusive, new: Vec) { + if range.start() == range.end() { + self.replace_with_many(range.start(), new); + return; + } + + debug_assert!(is_ancestor_or_self_of_element(range.start(), &self.root)); + self.changes.push(Change::ReplaceAll(range, new)) + } + + pub fn finish(self) -> SyntaxEdit { + edit_algo::apply_edits(self) + } +} + +/// Represents a completed [`SyntaxEditor`] operation. +pub struct SyntaxEdit { + old_root: SyntaxNode, + new_root: SyntaxNode, + changed_elements: Vec, + annotations: FxHashMap>, +} + +impl SyntaxEdit { + /// Root of the initial unmodified syntax tree. + pub fn old_root(&self) -> &SyntaxNode { + &self.old_root + } + + /// Root of the modified syntax tree. + pub fn new_root(&self) -> &SyntaxNode { + &self.new_root + } + + /// Which syntax elements in the modified syntax tree were inserted or + /// modified as part of the edit. + /// + /// Note that for syntax nodes, only the upper-most parent of a set of + /// changes is included, not any child elements that may have been modified. + pub fn changed_elements(&self) -> &[SyntaxElement] { + self.changed_elements.as_slice() + } + + /// Finds which syntax elements have been annotated with the given + /// annotation. + /// + /// Note that an annotation might not appear in the modified syntax tree if + /// the syntax elements that were annotated did not make it into the final + /// syntax tree. + pub fn find_annotation(&self, annotation: SyntaxAnnotation) -> &[SyntaxElement] { + self.annotations.get(&annotation).as_ref().map_or(&[], |it| it.as_slice()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct SyntaxAnnotation(NonZeroU32); + +impl SyntaxAnnotation { + /// Creates a unique syntax annotation to attach data to. + pub fn new() -> Self { + static COUNTER: AtomicU32 = AtomicU32::new(1); + + // Only consistency within a thread matters, as SyntaxElements are !Send + let id = COUNTER.fetch_add(1, Ordering::Relaxed); + + Self(NonZeroU32::new(id).expect("syntax annotation id overflow")) + } +} + +impl Default for SyntaxAnnotation { + fn default() -> Self { + Self::new() + } +} + +/// Position describing where to insert elements +#[derive(Debug)] +pub struct Position { + repr: PositionRepr, +} + +impl Position { + pub(crate) fn parent(&self) -> SyntaxNode { + self.place().0 + } + + pub(crate) fn place(&self) -> (SyntaxNode, usize) { + match &self.repr { + PositionRepr::FirstChild(parent) => (parent.clone(), 0), + PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1), + } + } +} + +#[derive(Debug)] +enum PositionRepr { + FirstChild(SyntaxNode), + After(SyntaxElement), +} + +impl Position { + pub fn after(elem: impl Element) -> Position { + let repr = PositionRepr::After(elem.syntax_element()); + Position { repr } + } + + pub fn before(elem: impl Element) -> Position { + let elem = elem.syntax_element(); + let repr = match elem.prev_sibling_or_token() { + Some(it) => PositionRepr::After(it), + None => PositionRepr::FirstChild(elem.parent().unwrap()), + }; + Position { repr } + } + + pub fn first_child_of(node: &(impl Into + Clone)) -> Position { + let repr = PositionRepr::FirstChild(node.clone().into()); + Position { repr } + } + + pub fn last_child_of(node: &(impl Into + Clone)) -> Position { + let node = node.clone().into(); + let repr = match node.last_child_or_token() { + Some(it) => PositionRepr::After(it), + None => PositionRepr::FirstChild(node), + }; + Position { repr } + } +} + +#[derive(Debug)] +enum Change { + /// Inserts a single element at the specified position. + Insert(Position, SyntaxElement), + /// Inserts many elements in-order at the specified position. + InsertAll(Position, Vec), + /// Represents both a replace single element and a delete element operation. + Replace(SyntaxElement, Option), + /// Replaces a single element with many elements. + ReplaceWithMany(SyntaxElement, Vec), + /// Replaces a range of elements with another list of elements. + /// Range will always have start != end. + ReplaceAll(RangeInclusive, Vec), +} + +impl Change { + fn target_range(&self) -> TextRange { + match self { + Change::Insert(target, _) | Change::InsertAll(target, _) => match &target.repr { + PositionRepr::FirstChild(parent) => TextRange::at( + parent.first_child_or_token().unwrap().text_range().start(), + 0.into(), + ), + PositionRepr::After(child) => TextRange::at(child.text_range().end(), 0.into()), + }, + Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => target.text_range(), + Change::ReplaceAll(range, _) => { + range.start().text_range().cover(range.end().text_range()) + } + } + } + + fn target_parent(&self) -> SyntaxNode { + match self { + Change::Insert(target, _) | Change::InsertAll(target, _) => target.parent(), + Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => match target { + SyntaxElement::Node(target) => target.parent().unwrap_or_else(|| target.clone()), + SyntaxElement::Token(target) => target.parent().unwrap(), + }, + Change::ReplaceAll(target, _) => target.start().parent().unwrap(), + } + } + + fn change_kind(&self) -> ChangeKind { + match self { + Change::Insert(_, _) | Change::InsertAll(_, _) => ChangeKind::Insert, + Change::Replace(_, _) | Change::ReplaceWithMany(_, _) => ChangeKind::Replace, + Change::ReplaceAll(_, _) => ChangeKind::ReplaceRange, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum ChangeKind { + Insert, + ReplaceRange, + Replace, +} + +/// Utility trait to allow calling syntax editor functions with references or owned +/// nodes. Do not use outside of this module. +pub trait Element { + fn syntax_element(self) -> SyntaxElement; +} + +impl Element for &'_ E { + fn syntax_element(self) -> SyntaxElement { + self.clone().syntax_element() + } +} + +impl Element for SyntaxElement { + fn syntax_element(self) -> SyntaxElement { + self + } +} + +impl Element for SyntaxNode { + fn syntax_element(self) -> SyntaxElement { + self.into() + } +} + +impl Element for SyntaxToken { + fn syntax_element(self) -> SyntaxElement { + self.into() + } +} + +fn is_ancestor_or_self(node: &SyntaxNode, ancestor: &SyntaxNode) -> bool { + node == ancestor || node.ancestors().any(|it| &it == ancestor) +} + +fn is_ancestor_or_self_of_element(node: &SyntaxElement, ancestor: &SyntaxNode) -> bool { + matches!(node, SyntaxElement::Node(node) if node == ancestor) + || node.ancestors().any(|it| &it == ancestor) +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + use itertools::Itertools; + + use crate::{ + ast::{self, make, HasName}, + AstNode, + }; + + use super::*; + + fn make_ident_pat( + editor: Option<&mut SyntaxEditor>, + ref_: bool, + mut_: bool, + name: ast::Name, + ) -> ast::IdentPat { + let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update(); + + if let Some(editor) = editor { + let mut mapping = SyntaxMappingBuilder::new(ast.syntax().clone()); + mapping.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + mapping.finish(editor); + } + + ast + } + + fn make_let_stmt( + editor: Option<&mut SyntaxEditor>, + pattern: ast::Pat, + ty: Option, + initializer: Option, + ) -> ast::LetStmt { + let ast = + make::let_stmt(pattern.clone(), ty.clone(), initializer.clone()).clone_for_update(); + + if let Some(editor) = editor { + let mut mapping = SyntaxMappingBuilder::new(ast.syntax().clone()); + mapping.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone()); + if let Some(input) = ty { + mapping.map_node(input.syntax().clone(), ast.ty().unwrap().syntax().clone()); + } + if let Some(input) = initializer { + mapping + .map_node(input.syntax().clone(), ast.initializer().unwrap().syntax().clone()); + } + mapping.finish(editor); + } + + ast + } + + fn make_block_expr( + editor: Option<&mut SyntaxEditor>, + stmts: impl IntoIterator, + tail_expr: Option, + ) -> ast::BlockExpr { + let stmts = stmts.into_iter().collect_vec(); + let input = stmts.iter().map(|it| it.syntax().clone()).collect_vec(); + + let ast = make::block_expr(stmts, tail_expr.clone()).clone_for_update(); + + if let Some((editor, stmt_list)) = editor.zip(ast.stmt_list()) { + let mut mapping = SyntaxMappingBuilder::new(stmt_list.syntax().clone()); + + mapping.map_children( + input.into_iter(), + stmt_list.statements().map(|it| it.syntax().clone()), + ); + + if let Some((input, output)) = tail_expr.zip(stmt_list.tail_expr()) { + mapping.map_node(input.syntax().clone(), output.syntax().clone()); + } + + mapping.finish(editor); + } + + ast + } + + #[test] + fn basic_usage() { + let root = make::match_arm( + [make::wildcard_pat().into()], + None, + make::expr_tuple([ + make::expr_bin_op( + make::expr_literal("2").into(), + ast::BinaryOp::ArithOp(ast::ArithOp::Add), + make::expr_literal("2").into(), + ), + make::expr_literal("true").into(), + ]), + ); + + let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap(); + let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap(); + + let mut editor = SyntaxEditor::new(root.syntax().clone()); + + let name = make::name("var_name"); + let name_ref = make::name_ref("var_name").clone_for_update(); + + let placeholder_snippet = SyntaxAnnotation::new(); + editor.add_annotation(name.syntax(), placeholder_snippet); + editor.add_annotation(name_ref.syntax(), placeholder_snippet); + + let make_ident_pat = make_ident_pat(Some(&mut editor), false, false, name); + let make_let_stmt = make_let_stmt( + Some(&mut editor), + make_ident_pat.into(), + None, + Some(to_replace.clone().into()), + ); + let new_block = make_block_expr( + Some(&mut editor), + [make_let_stmt.into()], + Some(to_wrap.clone().into()), + ); + + editor.replace(to_replace.syntax(), name_ref.syntax()); + editor.replace(to_wrap.syntax(), new_block.syntax()); + + let edit = editor.finish(); + + let expect = expect![[r#" + _ => { + let var_name = 2 + 2; + (var_name, true) + }"#]]; + expect.assert_eq(&edit.new_root.to_string()); + + assert_eq!(edit.find_annotation(placeholder_snippet).len(), 2); + assert!(edit + .annotations + .iter() + .flat_map(|(_, elements)| elements) + .all(|element| element.ancestors().any(|it| &it == edit.new_root()))) + } + + #[test] + fn test_insert_independent() { + let root = make::block_expr( + [make::let_stmt( + make::ext::simple_ident_pat(make::name("second")).into(), + None, + Some(make::expr_literal("2").into()), + ) + .into()], + None, + ); + + let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap(); + + let mut editor = SyntaxEditor::new(root.syntax().clone()); + + editor.insert( + Position::first_child_of(root.stmt_list().unwrap().syntax()), + make_let_stmt( + None, + make::ext::simple_ident_pat(make::name("first")).into(), + None, + Some(make::expr_literal("1").into()), + ) + .syntax(), + ); + + editor.insert( + Position::after(second_let.syntax()), + make_let_stmt( + None, + make::ext::simple_ident_pat(make::name("third")).into(), + None, + Some(make::expr_literal("3").into()), + ) + .syntax(), + ); + + let edit = editor.finish(); + + let expect = expect![[r#" + let first = 1;{ + let second = 2;let third = 3; + }"#]]; + expect.assert_eq(&edit.new_root.to_string()); + } + + #[test] + fn test_insert_dependent() { + let root = make::block_expr( + [], + Some( + make::block_expr( + [make::let_stmt( + make::ext::simple_ident_pat(make::name("second")).into(), + None, + Some(make::expr_literal("2").into()), + ) + .into()], + None, + ) + .into(), + ), + ); + + let inner_block = + root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap(); + let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap(); + + let mut editor = SyntaxEditor::new(root.syntax().clone()); + + let new_block_expr = + make_block_expr(Some(&mut editor), [], Some(ast::Expr::BlockExpr(inner_block.clone()))); + + let first_let = make_let_stmt( + Some(&mut editor), + make::ext::simple_ident_pat(make::name("first")).into(), + None, + Some(make::expr_literal("1").into()), + ); + + let third_let = make_let_stmt( + Some(&mut editor), + make::ext::simple_ident_pat(make::name("third")).into(), + None, + Some(make::expr_literal("3").into()), + ); + + editor.insert( + Position::first_child_of(inner_block.stmt_list().unwrap().syntax()), + first_let.syntax(), + ); + editor.insert(Position::after(second_let.syntax()), third_let.syntax()); + editor.replace(inner_block.syntax(), new_block_expr.syntax()); + + let edit = editor.finish(); + + let expect = expect![[r#" + { + { + let first = 1;{ + let second = 2;let third = 3; + } + } + }"#]]; + expect.assert_eq(&edit.new_root.to_string()); + } + + #[test] + fn test_replace_root_with_dependent() { + let root = make::block_expr( + [make::let_stmt( + make::ext::simple_ident_pat(make::name("second")).into(), + None, + Some(make::expr_literal("2").into()), + ) + .into()], + None, + ); + + let inner_block = root.clone(); + + let mut editor = SyntaxEditor::new(root.syntax().clone()); + + let new_block_expr = + make_block_expr(Some(&mut editor), [], Some(ast::Expr::BlockExpr(inner_block.clone()))); + + let first_let = make_let_stmt( + Some(&mut editor), + make::ext::simple_ident_pat(make::name("first")).into(), + None, + Some(make::expr_literal("1").into()), + ); + + editor.insert( + Position::first_child_of(inner_block.stmt_list().unwrap().syntax()), + first_let.syntax(), + ); + editor.replace(inner_block.syntax(), new_block_expr.syntax()); + + let edit = editor.finish(); + + let expect = expect![[r#" + { + let first = 1;{ + let second = 2; + } + }"#]]; + expect.assert_eq(&edit.new_root.to_string()); + } +} diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs new file mode 100644 index 0000000000000..b769c941105b7 --- /dev/null +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -0,0 +1,367 @@ +//! Implementation of applying changes to a syntax tree. + +use std::{cmp::Ordering, collections::VecDeque, ops::RangeInclusive}; + +use rowan::TextRange; +use rustc_hash::FxHashMap; + +use crate::{ + syntax_editor::{mapping::MissingMapping, Change, ChangeKind, PositionRepr}, + SyntaxElement, SyntaxNode, SyntaxNodePtr, +}; + +use super::{SyntaxEdit, SyntaxEditor}; + +pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { + // Algorithm overview: + // + // - Sort changes by (range, type) + // - Ensures that parent edits are before child edits + // - Ensures that inserts will be guaranteed to be inserted at the right range + // - Validate changes + // - Checking for invalid changes is easy since the changes will be sorted by range + // - Fixup change targets + // - standalone change? map to original syntax tree + // - dependent change? + // - try to map to parent change (either independent or another dependent) + // - note: need to keep track of a parent change stack, since a change can be a parent of multiple changes + // - Apply changes + // - find changes to apply to real tree by applying nested changes first + // - changed nodes become part of the changed node set (useful for the formatter to only change those parts) + // - Propagate annotations + + let SyntaxEditor { root, mut changes, mappings, annotations } = editor; + + let mut node_depths = FxHashMap::::default(); + let mut get_node_depth = |node: SyntaxNode| { + *node_depths.entry(node).or_insert_with_key(|node| node.ancestors().count()) + }; + + // Sort changes by range, then depth, then change kind, so that we can: + // - ensure that parent edits are ordered before child edits + // - ensure that inserts will be guaranteed to be inserted at the right range + // - easily check for disjoint replace ranges + changes.sort_by(|a, b| { + a.target_range() + .start() + .cmp(&b.target_range().start()) + .then_with(|| { + let a_target = a.target_parent(); + let b_target = b.target_parent(); + + if a_target == b_target { + return Ordering::Equal; + } + + get_node_depth(a_target).cmp(&get_node_depth(b_target)) + }) + .then(a.change_kind().cmp(&b.change_kind())) + }); + + let disjoint_replaces_ranges = changes + .iter() + .zip(changes.iter().skip(1)) + .filter(|(l, r)| { + // We only care about checking for disjoint replace ranges + matches!( + (l.change_kind(), r.change_kind()), + ( + ChangeKind::Replace | ChangeKind::ReplaceRange, + ChangeKind::Replace | ChangeKind::ReplaceRange + ) + ) + }) + .all(|(l, r)| { + get_node_depth(l.target_parent()) != get_node_depth(r.target_parent()) + || l.target_range().intersect(r.target_range()).is_none() + }); + + if stdx::never!( + !disjoint_replaces_ranges, + "some replace change ranges intersect: {:?}", + changes + ) { + return SyntaxEdit { + old_root: root.clone(), + new_root: root, + annotations: Default::default(), + changed_elements: vec![], + }; + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + struct DependentChange { + parent: u32, + child: u32, + } + + // Build change tree + let mut changed_ancestors: VecDeque = VecDeque::new(); + let mut dependent_changes = vec![]; + let mut independent_changes = vec![]; + + for (change_index, change) in changes.iter().enumerate() { + // Check if this change is dependent on another change (i.e. it's contained within another range) + if let Some(index) = changed_ancestors + .iter() + .rev() + .position(|ancestor| ancestor.affected_range().contains_range(change.target_range())) + { + // Pop off any ancestors that aren't applicable + changed_ancestors.drain((index + 1)..); + + // FIXME: Resolve changes that depend on a range of elements + let ancestor = &changed_ancestors[index]; + + dependent_changes.push(DependentChange { + parent: ancestor.change_index as u32, + child: change_index as u32, + }); + } else { + // This change is independent of any other change + + // Drain the changed ancestors since we're no longer in a set of dependent changes + changed_ancestors.drain(..); + + independent_changes.push(change_index as u32); + } + + // Add to changed ancestors, if applicable + match change { + Change::Insert(_, _) | Change::InsertAll(_, _) => {} + Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => { + changed_ancestors.push_back(ChangedAncestor::single(target, change_index)) + } + Change::ReplaceAll(range, _) => { + changed_ancestors.push_back(ChangedAncestor::multiple(range, change_index)) + } + } + } + + // Map change targets to the correct syntax nodes + let tree_mutator = TreeMutator::new(&root); + let mut changed_elements = vec![]; + + for index in independent_changes { + match &mut changes[index as usize] { + Change::Insert(target, _) | Change::InsertAll(target, _) => { + match &mut target.repr { + PositionRepr::FirstChild(parent) => { + *parent = tree_mutator.make_syntax_mut(parent); + } + PositionRepr::After(child) => { + *child = tree_mutator.make_element_mut(child); + } + }; + } + Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => { + *target = tree_mutator.make_element_mut(target); + } + Change::ReplaceAll(range, _) => { + let start = tree_mutator.make_element_mut(range.start()); + let end = tree_mutator.make_element_mut(range.end()); + + *range = start..=end; + } + } + + // Collect changed elements + match &changes[index as usize] { + Change::Insert(_, element) => changed_elements.push(element.clone()), + Change::InsertAll(_, elements) => changed_elements.extend(elements.iter().cloned()), + Change::Replace(_, Some(element)) => changed_elements.push(element.clone()), + Change::Replace(_, None) => {} + Change::ReplaceWithMany(_, elements) => { + changed_elements.extend(elements.iter().cloned()) + } + Change::ReplaceAll(_, elements) => changed_elements.extend(elements.iter().cloned()), + } + } + + for DependentChange { parent, child } in dependent_changes.into_iter() { + let (input_ancestor, output_ancestor) = match &changes[parent as usize] { + // No change will depend on an insert since changes can only depend on nodes in the root tree + Change::Insert(_, _) | Change::InsertAll(_, _) => unreachable!(), + Change::Replace(target, Some(new_target)) => { + (to_owning_node(target), to_owning_node(new_target)) + } + // Silently drop outdated change + Change::Replace(_, None) => continue, + Change::ReplaceAll(_, _) | Change::ReplaceWithMany(_, _) => { + unimplemented!("cannot resolve changes that depend on replacing many elements") + } + }; + + let upmap_target_node = |target: &SyntaxNode| { + match mappings.upmap_child(target, &input_ancestor, &output_ancestor) { + Ok(it) => it, + Err(MissingMapping(current)) => unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}"), + } + }; + + let upmap_target = |target: &SyntaxElement| { + match mappings.upmap_child_element(target, &input_ancestor, &output_ancestor) { + Ok(it) => it, + Err(MissingMapping(current)) => unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}"), + } + }; + + match &mut changes[child as usize] { + Change::Insert(target, _) | Change::InsertAll(target, _) => match &mut target.repr { + PositionRepr::FirstChild(parent) => { + *parent = upmap_target_node(parent); + } + PositionRepr::After(child) => { + *child = upmap_target(child); + } + }, + Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => { + *target = upmap_target(target); + } + Change::ReplaceAll(range, _) => { + *range = upmap_target(range.start())..=upmap_target(range.end()); + } + } + } + + // Apply changes + let mut root = tree_mutator.mutable_clone; + + for change in changes { + match change { + Change::Insert(position, element) => { + let (parent, index) = position.place(); + parent.splice_children(index..index, vec![element]); + } + Change::InsertAll(position, elements) => { + let (parent, index) = position.place(); + parent.splice_children(index..index, elements); + } + Change::Replace(target, None) => { + target.detach(); + } + Change::Replace(SyntaxElement::Node(target), Some(new_target)) if target == root => { + root = new_target.into_node().expect("root node replacement should be a node"); + } + Change::Replace(target, Some(new_target)) => { + let parent = target.parent().unwrap(); + parent.splice_children(target.index()..target.index() + 1, vec![new_target]); + } + Change::ReplaceWithMany(target, elements) => { + let parent = target.parent().unwrap(); + parent.splice_children(target.index()..target.index() + 1, elements); + } + Change::ReplaceAll(range, elements) => { + let start = range.start().index(); + let end = range.end().index(); + let parent = range.start().parent().unwrap(); + parent.splice_children(start..end + 1, elements); + } + } + } + + // Propagate annotations + let annotations = annotations.into_iter().filter_map(|(element, annotation)| { + match mappings.upmap_element(&element, &root) { + // Needed to follow the new tree to find the resulting element + Some(Ok(mapped)) => Some((mapped, annotation)), + // Element did not need to be mapped + None => Some((element, annotation)), + // Element did not make it to the final tree + Some(Err(_)) => None, + } + }); + + let mut annotation_groups = FxHashMap::default(); + + for (element, annotation) in annotations { + annotation_groups.entry(annotation).or_insert(vec![]).push(element); + } + + SyntaxEdit { + old_root: tree_mutator.immutable, + new_root: root, + changed_elements, + annotations: annotation_groups, + } +} + +fn to_owning_node(element: &SyntaxElement) -> SyntaxNode { + match element { + SyntaxElement::Node(node) => node.clone(), + SyntaxElement::Token(token) => token.parent().unwrap().clone(), + } +} + +struct ChangedAncestor { + kind: ChangedAncestorKind, + change_index: usize, +} + +enum ChangedAncestorKind { + Single { node: SyntaxNode }, + Range { _changed_elements: RangeInclusive, _in_parent: SyntaxNode }, +} + +impl ChangedAncestor { + fn single(element: &SyntaxElement, change_index: usize) -> Self { + let kind = match element { + SyntaxElement::Node(node) => ChangedAncestorKind::Single { node: node.clone() }, + SyntaxElement::Token(token) => { + ChangedAncestorKind::Single { node: token.parent().unwrap() } + } + }; + + Self { kind, change_index } + } + + fn multiple(range: &RangeInclusive, change_index: usize) -> Self { + Self { + kind: ChangedAncestorKind::Range { + _changed_elements: range.clone(), + _in_parent: range.start().parent().unwrap(), + }, + change_index, + } + } + + fn affected_range(&self) -> TextRange { + match &self.kind { + ChangedAncestorKind::Single { node } => node.text_range(), + ChangedAncestorKind::Range { _changed_elements: changed_nodes, _in_parent: _ } => { + TextRange::new( + changed_nodes.start().text_range().start(), + changed_nodes.end().text_range().end(), + ) + } + } + } +} + +struct TreeMutator { + immutable: SyntaxNode, + mutable_clone: SyntaxNode, +} + +impl TreeMutator { + fn new(immutable: &SyntaxNode) -> TreeMutator { + let immutable = immutable.clone(); + let mutable_clone = immutable.clone_for_update(); + TreeMutator { immutable, mutable_clone } + } + + fn make_element_mut(&self, element: &SyntaxElement) -> SyntaxElement { + match element { + SyntaxElement::Node(node) => SyntaxElement::Node(self.make_syntax_mut(node)), + SyntaxElement::Token(token) => { + let parent = self.make_syntax_mut(&token.parent().unwrap()); + parent.children_with_tokens().nth(token.index()).unwrap() + } + } + } + + fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode { + let ptr = SyntaxNodePtr::new(node); + ptr.to_node(&self.mutable_clone) + } +} diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs new file mode 100644 index 0000000000000..9bb5e6d933822 --- /dev/null +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs @@ -0,0 +1,272 @@ +//! Maps syntax elements through disjoint syntax nodes. +//! +//! [`SyntaxMappingBuilder`] should be used to create mappings to add to a [`SyntaxEditor`] + +use itertools::Itertools; +use rustc_hash::FxHashMap; + +use crate::{SyntaxElement, SyntaxNode}; + +use super::SyntaxEditor; + +#[derive(Debug, Default)] +pub struct SyntaxMapping { + // important information to keep track of: + // node -> node + // token -> token (implicit in mappings) + // input parent -> output parent (for deep lookups) + + // mappings -> parents + entry_parents: Vec, + node_mappings: FxHashMap, +} + +impl SyntaxMapping { + pub fn new() -> Self { + Self::default() + } + + /// Like [`SyntaxMapping::upmap_child`] but for syntax elements. + pub fn upmap_child_element( + &self, + child: &SyntaxElement, + input_ancestor: &SyntaxNode, + output_ancestor: &SyntaxNode, + ) -> Result { + match child { + SyntaxElement::Node(node) => { + self.upmap_child(node, input_ancestor, output_ancestor).map(SyntaxElement::Node) + } + SyntaxElement::Token(token) => { + let upmap_parent = + self.upmap_child(&token.parent().unwrap(), input_ancestor, output_ancestor)?; + + let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap(); + debug_assert!( + element.as_token().is_some_and(|it| it.kind() == token.kind()), + "token upmapping mapped to the wrong node ({token:?} -> {element:?})" + ); + + Ok(element) + } + } + } + + /// Maps a child node of the input ancestor to the corresponding node in + /// the output ancestor. + pub fn upmap_child( + &self, + child: &SyntaxNode, + input_ancestor: &SyntaxNode, + output_ancestor: &SyntaxNode, + ) -> Result { + debug_assert!( + child == input_ancestor + || child.ancestors().any(|ancestor| &ancestor == input_ancestor) + ); + + // Build a list mapping up to the first mappable ancestor + let to_first_upmap = if child != input_ancestor { + std::iter::successors(Some((child.index(), child.clone())), |(_, current)| { + let parent = current.parent().unwrap(); + + if &parent == input_ancestor { + return None; + } + + Some((parent.index(), parent)) + }) + .map(|(i, _)| i) + .collect::>() + } else { + vec![] + }; + + // Progressively up-map the input ancestor until we get to the output ancestor + let to_output_ancestor = if input_ancestor != output_ancestor { + self.upmap_to_ancestor(input_ancestor, output_ancestor)? + } else { + vec![] + }; + + let to_map_down = + to_output_ancestor.into_iter().rev().chain(to_first_upmap.into_iter().rev()); + + let mut target = output_ancestor.clone(); + + for index in to_map_down { + target = target + .children_with_tokens() + .nth(index) + .and_then(|it| it.into_node()) + .expect("equivalent ancestor node should be present in target tree"); + } + + debug_assert_eq!(child.kind(), target.kind()); + + Ok(target) + } + + fn upmap_to_ancestor( + &self, + input_ancestor: &SyntaxNode, + output_ancestor: &SyntaxNode, + ) -> Result, MissingMapping> { + let mut current = + self.upmap_node_single(input_ancestor).unwrap_or_else(|| input_ancestor.clone()); + let mut upmap_chain = vec![current.index()]; + + loop { + let Some(parent) = current.parent() else { break }; + + if &parent == output_ancestor { + return Ok(upmap_chain); + } + + current = match self.upmap_node_single(&parent) { + Some(next) => next, + None => parent, + }; + upmap_chain.push(current.index()); + } + + Err(MissingMapping(current)) + } + + pub fn upmap_element( + &self, + input: &SyntaxElement, + output_root: &SyntaxNode, + ) -> Option> { + match input { + SyntaxElement::Node(node) => { + Some(self.upmap_node(node, output_root)?.map(SyntaxElement::Node)) + } + SyntaxElement::Token(token) => { + let upmap_parent = match self.upmap_node(&token.parent().unwrap(), output_root)? { + Ok(it) => it, + Err(err) => return Some(Err(err)), + }; + + let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap(); + debug_assert!( + element.as_token().is_some_and(|it| it.kind() == token.kind()), + "token upmapping mapped to the wrong node ({token:?} -> {element:?})" + ); + + Some(Ok(element)) + } + } + } + + pub fn upmap_node( + &self, + input: &SyntaxNode, + output_root: &SyntaxNode, + ) -> Option> { + // Try to follow the mapping tree, if it exists + let input_mapping = self.upmap_node_single(input); + let input_ancestor = + input.ancestors().find_map(|ancestor| self.upmap_node_single(&ancestor)); + + match (input_mapping, input_ancestor) { + (Some(input_mapping), _) => { + // A mapping exists at the input, follow along the tree + Some(self.upmap_child(&input_mapping, &input_mapping, output_root)) + } + (None, Some(input_ancestor)) => { + // A mapping exists at an ancestor, follow along the tree + Some(self.upmap_child(input, &input_ancestor, output_root)) + } + (None, None) => { + // No mapping exists at all, is the same position in the final tree + None + } + } + } + + pub fn merge(&mut self, mut other: SyntaxMapping) { + // Remap other's entry parents to be after the current list of entry parents + let remap_base: u32 = self.entry_parents.len().try_into().unwrap(); + + self.entry_parents.append(&mut other.entry_parents); + self.node_mappings.extend(other.node_mappings.into_iter().map(|(node, entry)| { + (node, MappingEntry { parent: entry.parent + remap_base, ..entry }) + })); + } + + /// Follows the input one step along the syntax mapping tree + fn upmap_node_single(&self, input: &SyntaxNode) -> Option { + let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?; + + let output = self.entry_parents[*parent as usize] + .children_with_tokens() + .nth(*child_slot as usize) + .and_then(SyntaxElement::into_node) + .unwrap(); + + debug_assert_eq!(input.kind(), output.kind()); + Some(output) + } + + fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) { + let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping; + + let parent_entry: u32 = self.entry_parents.len().try_into().unwrap(); + self.entry_parents.push(parent_node); + + let node_entries = node_mappings + .into_iter() + .map(|(node, slot)| (node, MappingEntry { parent: parent_entry, child_slot: slot })); + + self.node_mappings.extend(node_entries); + } +} + +#[derive(Debug)] +pub struct SyntaxMappingBuilder { + parent_node: SyntaxNode, + node_mappings: Vec<(SyntaxNode, u32)>, +} + +impl SyntaxMappingBuilder { + pub fn new(parent_node: SyntaxNode) -> Self { + Self { parent_node, node_mappings: vec![] } + } + + pub fn map_node(&mut self, input: SyntaxNode, output: SyntaxNode) { + debug_assert_eq!(output.parent().as_ref(), Some(&self.parent_node)); + self.node_mappings.push((input, output.index() as u32)); + } + + pub fn map_children( + &mut self, + input: impl Iterator, + output: impl Iterator, + ) { + for pairs in input.zip_longest(output) { + let (input, output) = match pairs { + itertools::EitherOrBoth::Both(l, r) => (l, r), + itertools::EitherOrBoth::Left(_) => { + unreachable!("mapping more input nodes than there are output nodes") + } + itertools::EitherOrBoth::Right(_) => break, + }; + + self.map_node(input, output); + } + } + + pub fn finish(self, editor: &mut SyntaxEditor) { + editor.mappings.add_mapping(self); + } +} + +#[derive(Debug)] +pub struct MissingMapping(pub SyntaxNode); + +#[derive(Debug, Clone, Copy)] +struct MappingEntry { + parent: u32, + child_slot: u32, +} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ted.rs b/src/tools/rust-analyzer/crates/syntax/src/ted.rs index 29788d05e845f..8592df1597551 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ted.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ted.rs @@ -147,6 +147,11 @@ pub fn append_child_raw(node: &(impl Into + Clone), child: impl Elem insert_raw(position, child); } +pub fn prepend_child(node: &(impl Into + Clone), child: impl Element) { + let position = Position::first_child_of(node); + insert(position, child); +} + fn ws_before(position: &Position, new: &SyntaxElement) -> Option { let prev = match &position.repr { PositionRepr::FirstChild(_) => return None, diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 03e85a898ab0c..593e31c2fbb85 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -2,8 +2,8 @@ use std::{iter, mem, str::FromStr, sync}; use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileChange, - FileSet, LangCrateOrigin, SourceRoot, SourceRootDatabase, Version, VfsPath, + CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, CrateWorkspaceData, Dependency, + Env, FileChange, FileSet, LangCrateOrigin, SourceRoot, SourceRootDatabase, Version, VfsPath, }; use cfg::CfgOptions; use hir_expand::{ @@ -13,7 +13,7 @@ use hir_expand::{ proc_macro::{ ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacrosBuilder, }, - FileRange, + quote, FileRange, }; use intern::Symbol; use rustc_hash::FxHashMap; @@ -95,8 +95,10 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static { fn test_crate(&self) -> CrateId { let crate_graph = self.crate_graph(); let mut it = crate_graph.iter(); - let res = it.next().unwrap(); - assert!(it.next().is_none()); + let mut res = it.next().unwrap(); + while crate_graph[res].origin.is_lang() { + res = it.next().unwrap(); + } res } } @@ -352,23 +354,27 @@ impl ChangeFixture { }; roots.push(root); - let mut change = ChangeWithProcMacros { - source_change, - proc_macros: Some(proc_macros.build()), - toolchains: Some(iter::repeat(toolchain).take(crate_graph.len()).collect()), - target_data_layouts: Some( - iter::repeat(target_data_layout).take(crate_graph.len()).collect(), - ), - }; + let mut change = + ChangeWithProcMacros { source_change, proc_macros: Some(proc_macros.build()) }; change.source_change.set_roots(roots); + change.source_change.set_ws_data( + crate_graph + .iter() + .zip(iter::repeat(From::from(CrateWorkspaceData { + proc_macro_cwd: None, + data_layout: target_data_layout, + toolchain, + }))) + .collect(), + ); change.source_change.set_crate_graph(crate_graph); ChangeFixture { file_position, files, change } } } -fn default_test_proc_macros() -> [(String, ProcMacro); 5] { +fn default_test_proc_macros() -> [(String, ProcMacro); 6] { [ ( r#" @@ -445,6 +451,21 @@ pub fn shorten(input: TokenStream) -> TokenStream { disabled: false, }, ), + ( + r#" +#[proc_macro_attribute] +pub fn issue_18089(_attr: TokenStream, _item: TokenStream) -> TokenStream { + loop {} +} +"# + .into(), + ProcMacro { + name: Symbol::intern("issue_18089"), + kind: ProcMacroKind::Attr, + expander: sync::Arc::new(Issue18089ProcMacroExpander), + disabled: false, + }, + ), ] } @@ -565,11 +586,41 @@ impl ProcMacroExpander for IdentityProcMacroExpander { _: Span, _: Span, _: Span, + _: Option, ) -> Result, ProcMacroExpansionError> { Ok(subtree.clone()) } } +// Expands to a macro_rules! macro, for issue #18089. +#[derive(Debug)] +struct Issue18089ProcMacroExpander; +impl ProcMacroExpander for Issue18089ProcMacroExpander { + fn expand( + &self, + subtree: &Subtree, + _: Option<&Subtree>, + _: &Env, + _: Span, + call_site: Span, + _: Span, + _: Option, + ) -> Result, ProcMacroExpansionError> { + let macro_name = &subtree.token_trees[1]; + Ok(quote! { call_site => + #[macro_export] + macro_rules! my_macro___ { + ($($token:tt)*) => {{ + }}; + } + + pub use my_macro___ as #macro_name; + + #subtree + }) + } +} + // Pastes the attribute input as its output #[derive(Debug)] struct AttributeInputReplaceProcMacroExpander; @@ -582,6 +633,7 @@ impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { _: Span, _: Span, _: Span, + _: Option, ) -> Result, ProcMacroExpansionError> { attrs .cloned() @@ -600,6 +652,7 @@ impl ProcMacroExpander for MirrorProcMacroExpander { _: Span, _: Span, _: Span, + _: Option, ) -> Result, ProcMacroExpansionError> { fn traverse(input: &Subtree) -> Subtree { let mut token_trees = vec![]; @@ -630,6 +683,7 @@ impl ProcMacroExpander for ShortenProcMacroExpander { _: Span, _: Span, _: Span, + _: Option, ) -> Result, ProcMacroExpansionError> { return Ok(traverse(input)); diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 3be4469beef0a..67629fcf7cc5e 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -33,6 +33,7 @@ //! from: sized //! future: pin //! coroutine: pin +//! dispatch_from_dyn: unsize, pin //! hash: //! include: //! index: sized @@ -64,6 +65,7 @@ //! todo: panic //! unimplemented: panic //! column: +//! addr_of: #![rustc_coherence_is_core] @@ -169,7 +171,7 @@ pub mod default { macro_rules! impl_default { ($v:literal; $($t:ty)*) => { $( - impl const Default for $t { + impl Default for $t { fn default() -> Self { $v } @@ -420,6 +422,17 @@ pub mod ptr { } // endregion:coerce_unsized // endregion:non_null + + // region:addr_of + #[rustc_macro_transparency = "semitransparent"] + pub macro addr_of($place:expr) { + &raw const $place + } + #[rustc_macro_transparency = "semitransparent"] + pub macro addr_of_mut($place:expr) { + &raw mut $place + } + // endregion:addr_of } pub mod ops { @@ -673,7 +686,7 @@ pub mod ops { // endregion:fn // region:try mod try_ { - use super::super::convert::Infallible; + use crate::convert::Infallible; pub enum ControlFlow { #[lang = "Continue"] @@ -743,7 +756,7 @@ pub mod ops { // endregion:option // region:result // region:from - use super::super::convert::From; + use crate::convert::From; impl Try for Result { type Output = T; @@ -764,7 +777,7 @@ pub mod ops { impl> FromResidual> for Result { fn from_residual(residual: Result) -> Self { match residual { - Err(e) => Err(From::from(e)), + Err(e) => Err(F::from(e)), Ok(_) => loop {}, } } @@ -822,6 +835,24 @@ pub mod ops { } pub use self::coroutine::{Coroutine, CoroutineState}; // endregion:coroutine + + // region:dispatch_from_dyn + mod dispatch_from_dyn { + use crate::marker::Unsize; + + #[lang = "dispatch_from_dyn"] + pub trait DispatchFromDyn {} + + impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} + + impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} + + impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} + + impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} + } + pub use self::dispatch_from_dyn::DispatchFromDyn; + // endregion:dispatch_from_dyn } // region:eq @@ -1183,6 +1214,12 @@ pub mod pin { } } // endregion:deref + // region:dispatch_from_dyn + impl crate::ops::DispatchFromDyn> for Pin where + Ptr: crate::ops::DispatchFromDyn + { + } + // endregion:dispatch_from_dyn } // endregion:pin @@ -1309,7 +1346,10 @@ pub mod iter { self } // region:iterators - fn take(self, n: usize) -> crate::iter::Take { + fn take(self, n: usize) -> crate::iter::Take + where + Self: Sized, + { loop {} } fn filter_map(self, _f: F) -> crate::iter::FilterMap @@ -1435,6 +1475,19 @@ mod panicking { } // endregion:panic +// region:asm +mod arch { + #[rustc_builtin_macro] + pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) { + /* compiler built-in */ + } + #[rustc_builtin_macro] + pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) { + /* compiler built-in */ + } +} +// endregion:asm + #[macro_use] mod macros { // region:panic @@ -1447,16 +1500,6 @@ mod macros { } // endregion:panic - // region:asm - #[macro_export] - #[rustc_builtin_macro] - macro_rules! asm { - ($($arg:tt)*) => { - /* compiler built-in */ - }; - } - // endregion:asm - // region:assert #[macro_export] #[rustc_builtin_macro] diff --git a/src/tools/rust-analyzer/crates/tt/src/iter.rs b/src/tools/rust-analyzer/crates/tt/src/iter.rs index e96bed0319e12..587b903aa97a5 100644 --- a/src/tools/rust-analyzer/crates/tt/src/iter.rs +++ b/src/tools/rust-analyzer/crates/tt/src/iter.rs @@ -57,6 +57,13 @@ impl<'a, S: Copy> TtIter<'a, S> { } } + pub fn expect_comma(&mut self) -> Result<(), ()> { + match self.expect_leaf()? { + Leaf::Punct(Punct { char: ',', .. }) => Ok(()), + _ => Err(()), + } + } + pub fn expect_ident(&mut self) -> Result<&'a Ident, ()> { match self.expect_leaf()? { Leaf::Ident(it) if it.sym != sym::underscore => Ok(it), diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs index bc40e03c5a246..a26444e9ea230 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs @@ -67,7 +67,7 @@ pub struct FileId(u32); // pub struct FileId(NonMaxU32); impl FileId { - pub const MAX: u32 = 0x7fff_ffff; + const MAX: u32 = 0x7fff_ffff; #[inline] pub const fn from_raw(raw: u32) -> FileId { diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 4786bd54d59be..b7bac4d29fad9 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ $DIR/issue-102467.rs:7:17 + --> $DIR/associated-constant-not-allowed-102467.rs:7:17 | LL | type A: S = 34>; | ^^^^^^^^ associated item constraint not allowed here @@ -11,7 +11,7 @@ LL + type A: S; | error[E0229]: associated item constraints are not allowed here - --> $DIR/issue-102467.rs:7:17 + --> $DIR/associated-constant-not-allowed-102467.rs:7:17 | LL | type A: S = 34>; | ^^^^^^^^ associated item constraint not allowed here diff --git a/tests/rustdoc-ui/doctest/doctest-output-include-fail.md b/tests/rustdoc-ui/doctest/doctest-output-include-fail.md new file mode 100644 index 0000000000000..a8e61238f3115 --- /dev/null +++ b/tests/rustdoc-ui/doctest/doctest-output-include-fail.md @@ -0,0 +1,7 @@ +With a code sample, that has an error: + +```rust +fn main() { + let x = 234 // no semicolon here! oh no! +} +``` diff --git a/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs b/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs new file mode 100644 index 0000000000000..4fc0674a0c98b --- /dev/null +++ b/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs @@ -0,0 +1,7 @@ +//@ compile-flags:--test --test-args=--test-threads=1 +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +// https://github.com/rust-lang/rust/issues/130470 +#![doc = include_str!("doctest-output-include-fail.md")] diff --git a/tests/rustdoc-ui/doctest/doctest-output-include-fail.stdout b/tests/rustdoc-ui/doctest/doctest-output-include-fail.stdout new file mode 100644 index 0000000000000..22d15f8743c68 --- /dev/null +++ b/tests/rustdoc-ui/doctest/doctest-output-include-fail.stdout @@ -0,0 +1,24 @@ + +running 1 test +test $DIR/doctest-output-include-fail.md - (line 3) ... FAILED + +failures: + +---- $DIR/doctest-output-include-fail.md - (line 3) stdout ---- +error: expected `;`, found `}` + --> $DIR/doctest-output-include-fail.md:5:16 + | +LL | let x = 234 // no semicolon here! oh no! + | ^ help: add `;` here +LL | } + | - unexpected token + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/doctest-output-include-fail.md - (line 3) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/doctest-output.stdout b/tests/rustdoc-ui/doctest/doctest-output.stdout index 35b0e366fb5cc..c3b1570c43ec1 100644 --- a/tests/rustdoc-ui/doctest/doctest-output.stdout +++ b/tests/rustdoc-ui/doctest/doctest-output.stdout @@ -1,7 +1,7 @@ running 3 tests test $DIR/doctest-output.rs - (line 8) ... ok -test $DIR/doctest-output.rs - ExpandedStruct (line 24) ... ok +test $DIR/doctest-output.rs - ExpandedStruct (line 25) ... ok test $DIR/doctest-output.rs - foo::bar (line 18) ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/non-local-defs-impl.rs b/tests/rustdoc-ui/doctest/non-local-defs-impl.rs index 37c80bc1f2728..b1ab5323a2bc8 100644 --- a/tests/rustdoc-ui/doctest/non-local-defs-impl.rs +++ b/tests/rustdoc-ui/doctest/non-local-defs-impl.rs @@ -15,7 +15,10 @@ /// # use pub_trait::Trait; /// /// struct Local; -/// impl Trait for &Local {} +/// +/// fn foo() { +/// impl Trait for &Local {} +/// } /// ``` /// /// But this shoudln't produce a warning: diff --git a/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout b/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout index 27797e22f8ecb..f39d2c2608b88 100644 --- a/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout +++ b/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout @@ -1,24 +1,23 @@ running 2 tests test $DIR/non-local-defs-impl.rs - doctest (line 13) - compile ... FAILED -test $DIR/non-local-defs-impl.rs - doctest (line 22) - compile ... ok +test $DIR/non-local-defs-impl.rs - doctest (line 25) - compile ... ok failures: ---- $DIR/non-local-defs-impl.rs - doctest (line 13) stdout ---- error: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/non-local-defs-impl.rs:18:1 + --> $DIR/non-local-defs-impl.rs:20:5 | -LL | impl Trait for &Local {} - | ^^^^^-----^^^^^------ - | | | - | | `&'_ Local` is not local - | | help: remove `&` to make the `impl` local - | `Trait` is not local +LL | fn foo() { + | -------- move the `impl` block outside of this function `foo` and up 3 bodies +LL | impl Trait for &Local {} + | ^^^^^-----^^^^^^----- + | | | + | | `Local` is not local + | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = help: make this doc-test a standalone test with its own `fn main() { ... }` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue note: the lint level is defined here --> $DIR/non-local-defs-impl.rs:11:9 diff --git a/tests/rustdoc-ui/doctest/non_local_defs.rs b/tests/rustdoc-ui/doctest/non_local_defs.rs index 83327eb1e3f49..a2f66c392231a 100644 --- a/tests/rustdoc-ui/doctest/non_local_defs.rs +++ b/tests/rustdoc-ui/doctest/non_local_defs.rs @@ -4,8 +4,6 @@ //@ normalize-stderr-test: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" -#![doc(test(attr(warn(non_local_definitions))))] - //! ``` //! #[macro_export] //! macro_rules! a_macro { () => {} } diff --git a/tests/rustdoc-ui/doctest/non_local_defs.stderr b/tests/rustdoc-ui/doctest/non_local_defs.stderr index 13cd2558793f8..2b47e6b5bc4d5 100644 --- a/tests/rustdoc-ui/doctest/non_local_defs.stderr +++ b/tests/rustdoc-ui/doctest/non_local_defs.stderr @@ -1,5 +1,5 @@ warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/non_local_defs.rs:11:1 + --> $DIR/non_local_defs.rs:9:1 | LL | macro_rules! a_macro { () => {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,11 +7,7 @@ LL | macro_rules! a_macro { () => {} } = help: remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() { ... }` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/non_local_defs.rs:8:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default warning: 1 warning emitted diff --git a/tests/rustdoc-ui/doctest/non_local_defs.stdout b/tests/rustdoc-ui/doctest/non_local_defs.stdout index 61b4074886e4b..bee195fcdd772 100644 --- a/tests/rustdoc-ui/doctest/non_local_defs.stdout +++ b/tests/rustdoc-ui/doctest/non_local_defs.stdout @@ -1,6 +1,6 @@ running 1 test -test $DIR/non_local_defs.rs - (line 9) ... ok +test $DIR/non_local_defs.rs - (line 7) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/issue-110629-private-type-cycle.rs b/tests/rustdoc-ui/private-type-cycle-110629.rs similarity index 83% rename from tests/rustdoc-ui/issue-110629-private-type-cycle.rs rename to tests/rustdoc-ui/private-type-cycle-110629.rs index b31b9d03e7cb3..fecb0239a3c22 100644 --- a/tests/rustdoc-ui/issue-110629-private-type-cycle.rs +++ b/tests/rustdoc-ui/private-type-cycle-110629.rs @@ -1,4 +1,5 @@ //@ check-pass +// https://github.com/rust-lang/rust/issues/110629 #![feature(type_alias_impl_trait)] diff --git a/tests/rustdoc-ui/issue-110629-private-type-cycle-dyn.rs b/tests/rustdoc-ui/private-type-cycle-dyn-110629.rs similarity index 83% rename from tests/rustdoc-ui/issue-110629-private-type-cycle-dyn.rs rename to tests/rustdoc-ui/private-type-cycle-dyn-110629.rs index c920a815fda75..91bf64cdc567d 100644 --- a/tests/rustdoc-ui/issue-110629-private-type-cycle-dyn.rs +++ b/tests/rustdoc-ui/private-type-cycle-dyn-110629.rs @@ -1,3 +1,5 @@ +// https://github.com/rust-lang/rust/issues/110629 + type Bar<'a, 'b> = Box>>; //~^ ERROR cycle detected when expanding type alias diff --git a/tests/rustdoc-ui/issue-110629-private-type-cycle-dyn.stderr b/tests/rustdoc-ui/private-type-cycle-dyn-110629.stderr similarity index 88% rename from tests/rustdoc-ui/issue-110629-private-type-cycle-dyn.stderr rename to tests/rustdoc-ui/private-type-cycle-dyn-110629.stderr index 9394b019e11e0..6ee7e4b781c5b 100644 --- a/tests/rustdoc-ui/issue-110629-private-type-cycle-dyn.stderr +++ b/tests/rustdoc-ui/private-type-cycle-dyn-110629.stderr @@ -1,5 +1,5 @@ error[E0391]: cycle detected when expanding type alias `Bar` - --> $DIR/issue-110629-private-type-cycle-dyn.rs:1:38 + --> $DIR/private-type-cycle-dyn-110629.rs:3:38 | LL | type Bar<'a, 'b> = Box>>; | ^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | type Bar<'a, 'b> = Box>>; = help: consider using a struct, enum, or union instead to break the cycle = help: see for more information note: cycle used when checking that `Bar` is well-formed - --> $DIR/issue-110629-private-type-cycle-dyn.rs:1:1 + --> $DIR/private-type-cycle-dyn-110629.rs:3:1 | LL | type Bar<'a, 'b> = Box>>; | ^^^^^^^^^^^^^^^^ diff --git a/tests/rustdoc-ui/projection-as-union-type-error.rs b/tests/rustdoc-ui/projection-as-union-type-error.rs new file mode 100644 index 0000000000000..d1d2e72249dc0 --- /dev/null +++ b/tests/rustdoc-ui/projection-as-union-type-error.rs @@ -0,0 +1,14 @@ +// Test to ensure that there is no ICE when normalizing a projection. +// See also . +// issue: rust-lang/rust#107872 + +pub trait Identity { + type Identity; +} + +pub type Foo = u8; + +pub union Bar { + a: ::Identity, //~ ERROR the trait bound `u8: Identity` is not satisfied + b: u8, +} diff --git a/tests/rustdoc-ui/projection-as-union-type-error.stderr b/tests/rustdoc-ui/projection-as-union-type-error.stderr new file mode 100644 index 0000000000000..32598015864cb --- /dev/null +++ b/tests/rustdoc-ui/projection-as-union-type-error.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `u8: Identity` is not satisfied + --> $DIR/projection-as-union-type-error.rs:12:9 + | +LL | a: ::Identity, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Identity` is not implemented for `u8` + | +help: this trait has no implementations, consider adding one + --> $DIR/projection-as-union-type-error.rs:5:1 + | +LL | pub trait Identity { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/rustdoc-ui/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/tests/rustdoc-ui/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs new file mode 100644 index 0000000000000..9f8053d553876 --- /dev/null +++ b/tests/rustdoc-ui/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs @@ -0,0 +1,23 @@ +// issue: rust-lang/rust#98250 +//@ check-pass + +#![feature(type_alias_impl_trait)] + +mod foo { + pub type Foo = impl PartialEq<(Foo, i32)>; + + fn foo() -> Foo { + super::Bar + } +} +use foo::Foo; + +struct Bar; + +impl PartialEq<(Foo, i32)> for Bar { + fn eq(&self, _other: &(Foo, i32)) -> bool { + true + } +} + +fn main() {} diff --git a/tests/rustdoc/issue-108931-anonymous-reexport.rs b/tests/rustdoc/anonymous-reexport-108931.rs similarity index 92% rename from tests/rustdoc/issue-108931-anonymous-reexport.rs rename to tests/rustdoc/anonymous-reexport-108931.rs index 300ee3baf053f..f4cc7f1239628 100644 --- a/tests/rustdoc/issue-108931-anonymous-reexport.rs +++ b/tests/rustdoc/anonymous-reexport-108931.rs @@ -1,4 +1,5 @@ // Ensuring that anonymous re-exports are always inlined. +// https://github.com/rust-lang/rust/issues/108931 #![crate_name = "foo"] diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs index ac55a6302f785..a71825d883d6a 100644 --- a/tests/rustdoc/const-display.rs +++ b/tests/rustdoc/const-display.rs @@ -1,8 +1,6 @@ #![crate_name = "foo"] -#![unstable(feature = "humans", - reason = "who ever let humans program computers, we're apparently really bad at it", - issue = "none")] +#![stable(feature = "rust1", since = "1.0.0")] #![feature(foo, foo2)] #![feature(staged_api)] @@ -48,10 +46,18 @@ pub const unsafe fn foo2_gated() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const unsafe fn bar2_gated() -> u32 { 42 } -//@ has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' -//@ !hasraw - '//span[@class="since"]' -pub const unsafe fn bar_not_gated() -> u32 { 42 } +#[unstable( + feature = "humans", + reason = "who ever let humans program computers, we're apparently really bad at it", + issue = "none", +)] +pub mod unstable { + //@ has 'foo/unstable/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' + //@ !hasraw - '//span[@class="since"]' + pub const unsafe fn bar_not_gated() -> u32 { 42 } +} +#[stable(feature = "rust1", since = "1.0.0")] pub struct Foo; impl Foo { diff --git a/tests/rustdoc/issue-109695-crate-doc-hidden.rs b/tests/rustdoc/crate-doc-hidden-109695.rs similarity index 78% rename from tests/rustdoc/issue-109695-crate-doc-hidden.rs rename to tests/rustdoc/crate-doc-hidden-109695.rs index 8dc077d15657e..fc8361ab2976b 100644 --- a/tests/rustdoc/issue-109695-crate-doc-hidden.rs +++ b/tests/rustdoc/crate-doc-hidden-109695.rs @@ -1,5 +1,6 @@ // This test ensures that even if the crate module is `#[doc(hidden)]`, the file // is generated. +// https://github.com/rust-lang/rust/issues/109695 //@ has 'foo/index.html' //@ has 'foo/all.html' diff --git a/tests/rustdoc/deref/issue-100679-sidebar-links-deref.rs b/tests/rustdoc/deref/sidebar-links-deref-100679.rs similarity index 93% rename from tests/rustdoc/deref/issue-100679-sidebar-links-deref.rs rename to tests/rustdoc/deref/sidebar-links-deref-100679.rs index 44ac08de0b820..d0c37529487eb 100644 --- a/tests/rustdoc/deref/issue-100679-sidebar-links-deref.rs +++ b/tests/rustdoc/deref/sidebar-links-deref-100679.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/100679 #![crate_name="foo"] pub struct Vec; diff --git a/tests/rustdoc/issue-109449-doc-hidden-reexports.rs b/tests/rustdoc/doc-hidden-reexports-109449.rs similarity index 100% rename from tests/rustdoc/issue-109449-doc-hidden-reexports.rs rename to tests/rustdoc/doc-hidden-reexports-109449.rs diff --git a/tests/rustdoc/issue-113982-doc_auto_cfg-reexport-foreign.rs b/tests/rustdoc/doc_auto_cfg-reexport-foreign-113982.rs similarity index 92% rename from tests/rustdoc/issue-113982-doc_auto_cfg-reexport-foreign.rs rename to tests/rustdoc/doc_auto_cfg-reexport-foreign-113982.rs index c083d9495f43c..76b25127a9c64 100644 --- a/tests/rustdoc/issue-113982-doc_auto_cfg-reexport-foreign.rs +++ b/tests/rustdoc/doc_auto_cfg-reexport-foreign-113982.rs @@ -1,5 +1,6 @@ //@ aux-build: issue-113982-doc_auto_cfg-reexport-foreign.rs +// https://github.com/rust-lang/rust/issues/113982 #![feature(no_core, doc_auto_cfg)] #![no_core] #![crate_name = "foo"] diff --git a/tests/rustdoc/duplicate_impls/issue-33054.rs b/tests/rustdoc/duplicate_impls/sidebar-links-duplicate-impls-33054.rs similarity index 76% rename from tests/rustdoc/duplicate_impls/issue-33054.rs rename to tests/rustdoc/duplicate_impls/sidebar-links-duplicate-impls-33054.rs index 24ff30668cfac..511a40c38a0a2 100644 --- a/tests/rustdoc/duplicate_impls/issue-33054.rs +++ b/tests/rustdoc/duplicate_impls/sidebar-links-duplicate-impls-33054.rs @@ -1,11 +1,13 @@ // ignore-tidy-linelength +// https://github.com/rust-lang/rust/issues/100679 +#![crate_name="foo"] -//@ has issue_33054/impls/struct.Foo.html +//@ has foo/impls/struct.Foo.html //@ has - '//h3[@class="code-header"]' 'impl Foo' //@ has - '//h3[@class="code-header"]' 'impl Bar for Foo' //@ count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 //@ count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl"]' 1 -//@ has issue_33054/impls/bar/trait.Bar.html +//@ has foo/impls/bar/trait.Bar.html //@ has - '//h3[@class="code-header"]' 'impl Bar for Foo' //@ count - '//*[@class="struct"]' 1 pub mod impls; diff --git a/tests/rustdoc/empty-mod-private.rs b/tests/rustdoc/empty-mod-private.rs index 4e408e3d4240a..5a8638cd5f5cd 100644 --- a/tests/rustdoc/empty-mod-private.rs +++ b/tests/rustdoc/empty-mod-private.rs @@ -2,15 +2,18 @@ //@ has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo' //@ hasraw 'empty_mod_private/sidebar-items.js' 'foo' -//@ matches 'empty_mod_private/foo/index.html' '//h1' 'Module empty_mod_private::foo' +//@ matches 'empty_mod_private/foo/index.html' '//h1' 'Module foo' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private' mod foo {} //@ has 'empty_mod_private/index.html' '//a[@href="bar/index.html"]' 'bar' //@ hasraw 'empty_mod_private/sidebar-items.js' 'bar' -//@ matches 'empty_mod_private/bar/index.html' '//h1' 'Module empty_mod_private::bar' +//@ matches 'empty_mod_private/bar/index.html' '//h1' 'Module bar' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private' mod bar { //@ has 'empty_mod_private/bar/index.html' '//a[@href="baz/index.html"]' 'baz' //@ hasraw 'empty_mod_private/bar/sidebar-items.js' 'baz' - //@ matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module empty_mod_private::bar::baz' + //@ matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module baz' + //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private::bar' mod baz {} } diff --git a/tests/rustdoc/empty-mod-public.rs b/tests/rustdoc/empty-mod-public.rs index b5a63525524ce..f06ac69f3ed81 100644 --- a/tests/rustdoc/empty-mod-public.rs +++ b/tests/rustdoc/empty-mod-public.rs @@ -1,14 +1,17 @@ //@ has 'empty_mod_public/index.html' '//a[@href="foo/index.html"]' 'foo' //@ hasraw 'empty_mod_public/sidebar-items.js' 'foo' -//@ matches 'empty_mod_public/foo/index.html' '//h1' 'Module empty_mod_public::foo' +//@ matches 'empty_mod_public/foo/index.html' '//h1' 'Module foo' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public' pub mod foo {} //@ has 'empty_mod_public/index.html' '//a[@href="bar/index.html"]' 'bar' //@ hasraw 'empty_mod_public/sidebar-items.js' 'bar' -//@ matches 'empty_mod_public/bar/index.html' '//h1' 'Module empty_mod_public::bar' +//@ matches 'empty_mod_public/bar/index.html' '//h1' 'Module bar' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public' pub mod bar { //@ has 'empty_mod_public/bar/index.html' '//a[@href="baz/index.html"]' 'baz' //@ hasraw 'empty_mod_public/bar/sidebar-items.js' 'baz' - //@ matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module empty_mod_public::bar::baz' + //@ matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module baz' + //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public::bar' pub mod baz {} } diff --git a/tests/rustdoc/issue-118180-empty-tuple-struct.rs b/tests/rustdoc/empty-tuple-struct-118180.rs similarity index 51% rename from tests/rustdoc/issue-118180-empty-tuple-struct.rs rename to tests/rustdoc/empty-tuple-struct-118180.rs index 2cd1df27b2bf0..614857ad5aeab 100644 --- a/tests/rustdoc/issue-118180-empty-tuple-struct.rs +++ b/tests/rustdoc/empty-tuple-struct-118180.rs @@ -1,9 +1,12 @@ -//@ has issue_118180_empty_tuple_struct/enum.Enum.html +// https://github.com/rust-lang/rust/issues/118180 +#![crate_name="foo"] + +//@ has foo/enum.Enum.html pub enum Enum { //@ has - '//*[@id="variant.Empty"]//h3' 'Empty()' Empty(), } -//@ has issue_118180_empty_tuple_struct/struct.Empty.html +//@ has foo/struct.Empty.html //@ has - '//pre/code' 'Empty()' pub struct Empty(); diff --git a/tests/rustdoc/issue-108925.rs b/tests/rustdoc/enum-non-exhaustive-108925.rs similarity index 64% rename from tests/rustdoc/issue-108925.rs rename to tests/rustdoc/enum-non-exhaustive-108925.rs index a332771616d4a..ea2462449d2b7 100644 --- a/tests/rustdoc/issue-108925.rs +++ b/tests/rustdoc/enum-non-exhaustive-108925.rs @@ -1,4 +1,7 @@ -//@ has issue_108925/enum.MyThing.html +// https://github.com/rust-lang/rust/issues/108925 +#![crate_name="foo"] + +//@ has foo/enum.MyThing.html //@ has - '//code' 'Shown' //@ !has - '//code' 'NotShown' //@ !has - '//code' '// some variants omitted' diff --git a/tests/rustdoc/issue-111249-file-creation.rs b/tests/rustdoc/file-creation-111249.rs similarity index 95% rename from tests/rustdoc/issue-111249-file-creation.rs rename to tests/rustdoc/file-creation-111249.rs index 89a25aef97def..a6522d682f191 100644 --- a/tests/rustdoc/issue-111249-file-creation.rs +++ b/tests/rustdoc/file-creation-111249.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/111249 #![crate_name = "foo"] #![feature(no_core)] #![no_core] diff --git a/tests/rustdoc/generic-associated-types/issue-94683.rs b/tests/rustdoc/generic-associated-types/gat-elided-lifetime-94683.rs similarity index 82% rename from tests/rustdoc/generic-associated-types/issue-94683.rs rename to tests/rustdoc/generic-associated-types/gat-elided-lifetime-94683.rs index 19a1e9d448e65..c1cacaf3f1158 100644 --- a/tests/rustdoc/generic-associated-types/issue-94683.rs +++ b/tests/rustdoc/generic-associated-types/gat-elided-lifetime-94683.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/94683 #![crate_name = "foo"] pub trait Trait { diff --git a/tests/rustdoc/generic-associated-types/issue-109488.rs b/tests/rustdoc/generic-associated-types/gat-linkification-109488.rs similarity index 84% rename from tests/rustdoc/generic-associated-types/issue-109488.rs rename to tests/rustdoc/generic-associated-types/gat-linkification-109488.rs index 12f8988f52002..be55a10b4033d 100644 --- a/tests/rustdoc/generic-associated-types/issue-109488.rs +++ b/tests/rustdoc/generic-associated-types/gat-linkification-109488.rs @@ -1,8 +1,10 @@ // Make sure that we escape the arguments of the GAT projection even if we fail to compute // the href of the corresponding trait (in this case it is private). // Further, test that we also linkify the GAT arguments. +// https://github.com/rust-lang/rust/issues/94683 +#![crate_name="foo"] -//@ has 'issue_109488/type.A.html' +//@ has 'foo/type.A.html' //@ has - '//pre[@class="rust item-decl"]' '::P>' //@ has - '//pre[@class="rust item-decl"]//a[@class="enum"]/@href' '{{channel}}/core/option/enum.Option.html' pub type A = ::P>; diff --git a/tests/rustdoc/html-no-source.rs b/tests/rustdoc/html-no-source.rs index 100ab0031f787..248afbd00eff9 100644 --- a/tests/rustdoc/html-no-source.rs +++ b/tests/rustdoc/html-no-source.rs @@ -11,14 +11,14 @@ //@ files 'src/foo' '[]' //@ has foo/fn.foo.html -//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · ' -//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' +//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0' +//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source' #[stable(feature = "bar", since = "1.0")] pub fn foo() {} //@ has foo/struct.Bar.html -//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · ' -//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' +//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0' +//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source' #[stable(feature = "bar", since = "1.0")] pub struct Bar; diff --git a/tests/rustdoc/impl-associated-items-order.rs b/tests/rustdoc/impl-associated-items-order.rs new file mode 100644 index 0000000000000..759e0f0b40095 --- /dev/null +++ b/tests/rustdoc/impl-associated-items-order.rs @@ -0,0 +1,42 @@ +// This test ensures that impl associated items always follow this order: +// +// 1. Consts +// 2. Types +// 3. Functions + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] +#![crate_name = "foo"] + +//@ has 'foo/struct.Bar.html' +pub struct Bar; + +impl Bar { + //@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[3]/h4' \ + // 'pub fn foo()' + pub fn foo() {} + //@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[1]/h4' \ + // 'pub const X: u8 = 12u8' + pub const X: u8 = 12; + //@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[2]/h4' \ + // 'pub type Y = u8' + pub type Y = u8; +} + +pub trait Foo { + const W: u32; + fn yeay(); + type Z; +} + +impl Foo for Bar { + //@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[2]/h4' \ + // 'type Z = u8' + type Z = u8; + //@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[1]/h4' \ + // 'const W: u32 = 12u32' + const W: u32 = 12; + //@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[3]/h4' \ + // 'fn yeay()' + fn yeay() {} +} diff --git a/tests/rustdoc/impl-associated-items-sidebar.rs b/tests/rustdoc/impl-associated-items-sidebar.rs new file mode 100644 index 0000000000000..d393a577e5009 --- /dev/null +++ b/tests/rustdoc/impl-associated-items-sidebar.rs @@ -0,0 +1,42 @@ +// This test ensures that impl/trait associated items are listed in the sidebar. + +// ignore-tidy-linelength + +#![feature(inherent_associated_types)] +#![feature(associated_type_defaults)] +#![allow(incomplete_features)] +#![crate_name = "foo"] + +//@ has 'foo/struct.Bar.html' +pub struct Bar; + +impl Bar { + //@ has - '//*[@class="sidebar-elems"]//h3[1]' 'Associated Constants' + //@ has - '//*[@class="sidebar-elems"]//ul[@class="block associatedconstant"]/li/a[@href="#associatedconstant.X"]' 'X' + pub const X: u8 = 12; + //@ has - '//*[@class="sidebar-elems"]//h3[2]' 'Associated Types' + //@ has - '//*[@class="sidebar-elems"]//ul[@class="block associatedtype"]/li/a[@href="#associatedtype.Y"]' 'Y' + pub type Y = u8; +} + +//@ has 'foo/trait.Foo.html' +pub trait Foo { + //@ has - '//*[@class="sidebar-elems"]//h3[5]' 'Required Methods' + //@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][5]/li/a[@href="#tymethod.yeay"]' 'yeay' + fn yeay(); + //@ has - '//*[@class="sidebar-elems"]//h3[6]' 'Provided Methods' + //@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][6]/li/a[@href="#method.boo"]' 'boo' + fn boo() {} + //@ has - '//*[@class="sidebar-elems"]//h3[1]' 'Required Associated Constants' + //@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][1]/li/a[@href="#associatedconstant.W"]' 'W' + const W: u32; + //@ has - '//*[@class="sidebar-elems"]//h3[2]' 'Provided Associated Constants' + //@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][2]/li/a[@href="#associatedconstant.U"]' 'U' + const U: u32 = 0; + //@ has - '//*[@class="sidebar-elems"]//h3[3]' 'Required Associated Types' + //@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][3]/li/a[@href="#associatedtype.Z"]' 'Z' + type Z; + //@ has - '//*[@class="sidebar-elems"]//h3[4]' 'Provided Associated Types' + //@ has - '//*[@class="sidebar-elems"]//ul[@class="block"][4]/li/a[@href="#associatedtype.T"]' 'T' + type T = u32; +} diff --git a/tests/rustdoc/inline_cross/auxiliary/repr.rs b/tests/rustdoc/inline_cross/auxiliary/repr.rs index 35f08c11b7b3a..0211e1a86588f 100644 --- a/tests/rustdoc/inline_cross/auxiliary/repr.rs +++ b/tests/rustdoc/inline_cross/auxiliary/repr.rs @@ -6,7 +6,7 @@ pub struct ReprC { } #[repr(simd, packed(2))] pub struct ReprSimd { - field: u8, + field: [u8; 1], } #[repr(transparent)] pub struct ReprTransparent { diff --git a/tests/rustdoc/inline_cross/renamed-via-module.rs b/tests/rustdoc/inline_cross/renamed-via-module.rs index bdaf2cf1f620c..8bcdd9f7a39d0 100644 --- a/tests/rustdoc/inline_cross/renamed-via-module.rs +++ b/tests/rustdoc/inline_cross/renamed-via-module.rs @@ -10,15 +10,19 @@ extern crate foo; //@ has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy" //@ has - '//a/[@href="struct.StepBy.html"]' "StepBy" //@ has foo/iter/struct.DeprecatedStepBy.html -//@ has - '//h1' "Struct foo::iter::DeprecatedStepBy" +//@ has - '//h1' "Struct DeprecatedStepBy" +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo::iter' //@ has foo/iter/struct.StepBy.html -//@ has - '//h1' "Struct foo::iter::StepBy" +//@ has - '//h1' "Struct StepBy" +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo::iter' //@ has bar/iter/index.html //@ has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy" //@ has - '//a/[@href="struct.StepBy.html"]' "StepBy" //@ has bar/iter/struct.DeprecatedStepBy.html -//@ has - '//h1' "Struct bar::iter::DeprecatedStepBy" +//@ has - '//h1' "Struct DeprecatedStepBy" +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'bar::iter' //@ has bar/iter/struct.StepBy.html -//@ has - '//h1' "Struct bar::iter::StepBy" +//@ has - '//h1' "Struct StepBy" +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'bar::iter' pub use foo::iter; diff --git a/tests/rustdoc/issue-110422-inner-private.rs b/tests/rustdoc/inner-private-110422.rs similarity index 100% rename from tests/rustdoc/issue-110422-inner-private.rs rename to tests/rustdoc/inner-private-110422.rs diff --git a/tests/rustdoc/keyword.rs b/tests/rustdoc/keyword.rs index 0157c35288e87..519e1944bc78a 100644 --- a/tests/rustdoc/keyword.rs +++ b/tests/rustdoc/keyword.rs @@ -6,7 +6,6 @@ //@ has foo/index.html '//a[@href="keyword.match.html"]' 'match' //@ has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords' //@ has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords' -//@ has foo/keyword.match.html '//a[@class="keyword"]' 'match' //@ has foo/keyword.match.html '//h1' 'Keyword match' //@ has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' //@ has foo/index.html '//a/@href' '../foo/index.html' diff --git a/tests/rustdoc/issue-115295-macro-const-display.rs b/tests/rustdoc/macro-const-display-115295.rs similarity index 96% rename from tests/rustdoc/issue-115295-macro-const-display.rs rename to tests/rustdoc/macro-const-display-115295.rs index 0dadb76ae5cdd..445b47e0b2467 100644 --- a/tests/rustdoc/issue-115295-macro-const-display.rs +++ b/tests/rustdoc/macro-const-display-115295.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/115295 #![crate_name = "foo"] //@ has foo/trait.Trait.html diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs new file mode 100644 index 0000000000000..fdafb3b7ac341 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs @@ -0,0 +1,5 @@ +//@ doc-flags:--merge=shared +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs new file mode 100644 index 0000000000000..ff12fe98d82c2 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs @@ -0,0 +1,8 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ doc-flags:--merge=shared +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs b/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs new file mode 100644 index 0000000000000..665f9567ba2d2 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs @@ -0,0 +1,25 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=shared +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html +//@ has index.html '//h1' 'List of all crates' +//@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec' +//@ has index.html '//ul[@class="all-items"]//a[@href="sierra/index.html"]' 'sierra' +//@ has index.html '//ul[@class="all-items"]//a[@href="tango/index.html"]' 'tango' +//@ has quebec/struct.Quebec.html +//@ has sierra/struct.Sierra.html +//@ has tango/trait.Tango.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html' +//@ hasraw search-index.js 'Tango' +//@ hasraw search-index.js 'Sierra' +//@ hasraw search-index.js 'Quebec' + +// similar to cargo-workflow-transitive, but we use --merge=read-write, +// which is the default. +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs new file mode 100644 index 0000000000000..d10bc0316ccad --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs @@ -0,0 +1,7 @@ +//@ unique-doc-out-dir +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs new file mode 100644 index 0000000000000..6d0c8651db53f --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs @@ -0,0 +1,10 @@ +//@ aux-build:sierra.rs +//@ build-aux-docs +//@ unique-doc-out-dir +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/romeo +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate sierra; +pub type Romeo = sierra::Sierra; diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs new file mode 100644 index 0000000000000..10898f3886477 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs @@ -0,0 +1,11 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ unique-doc-out-dir +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/sierra +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs new file mode 100644 index 0000000000000..3c3721ee6eb7d --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs @@ -0,0 +1,10 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ unique-doc-out-dir +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/tango +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs new file mode 100644 index 0000000000000..f03f6bd6026fa --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs @@ -0,0 +1,35 @@ +//@ aux-build:tango.rs +//@ aux-build:romeo.rs +//@ aux-build:quebec.rs +//@ aux-build:sierra.rs +//@ build-aux-docs +//@ doc-flags:--merge=finalize +//@ doc-flags:--include-parts-dir=info/doc.parts/tango +//@ doc-flags:--include-parts-dir=info/doc.parts/romeo +//@ doc-flags:--include-parts-dir=info/doc.parts/quebec +//@ doc-flags:--include-parts-dir=info/doc.parts/sierra +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html '//h1' 'List of all crates' +//@ has index.html +//@ has index.html '//ul[@class="all-items"]//a[@href="indigo/index.html"]' 'indigo' +//@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec' +//@ has index.html '//ul[@class="all-items"]//a[@href="romeo/index.html"]' 'romeo' +//@ has index.html '//ul[@class="all-items"]//a[@href="sierra/index.html"]' 'sierra' +//@ has index.html '//ul[@class="all-items"]//a[@href="tango/index.html"]' 'tango' +//@ !has quebec/struct.Quebec.html +//@ !has romeo/type.Romeo.html +//@ !has sierra/struct.Sierra.html +//@ !has tango/trait.Tango.html +//@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html' +//@ hasraw search-index.js 'Quebec' +//@ hasraw search-index.js 'Romeo' +//@ hasraw search-index.js 'Sierra' +//@ hasraw search-index.js 'Tango' +//@ has type.impl/sierra/struct.Sierra.js +//@ hasraw type.impl/sierra/struct.Sierra.js 'Tango' +//@ hasraw type.impl/sierra/struct.Sierra.js 'Romeo' + +// document everything in the default mode, there are separate out +// directories that are linked together diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs new file mode 100644 index 0000000000000..61210529fa6bc --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs @@ -0,0 +1,6 @@ +//@ unique-doc-out-dir +//@ doc-flags:--merge=none +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs new file mode 100644 index 0000000000000..70d8a4b91f549 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs @@ -0,0 +1,9 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ unique-doc-out-dir +//@ doc-flags:--merge=none +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs b/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs new file mode 100644 index 0000000000000..7eac207e51886 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs @@ -0,0 +1,17 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=none +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ !has index.html +//@ has sierra/struct.Sierra.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ !has trait.impl/tango/trait.Tango.js +//@ !has search-index.js + +// we don't generate any cross-crate info if --merge=none, even if we +// document crates separately +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs new file mode 100644 index 0000000000000..6ab921533b037 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs @@ -0,0 +1,6 @@ +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs new file mode 100644 index 0000000000000..9fa99d3be8af4 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs @@ -0,0 +1,9 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/tango +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs b/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs new file mode 100644 index 0000000000000..f3340a80c848b --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs @@ -0,0 +1,18 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/sierra +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ !has index.html +//@ has sierra/struct.Sierra.html +//@ has tango/trait.Tango.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ !has trait.impl/tango/trait.Tango.js +//@ !has search-index.js + +// we --merge=none, so --parts-out-dir doesn't do anything +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs new file mode 100644 index 0000000000000..6ab921533b037 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs @@ -0,0 +1,6 @@ +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs new file mode 100644 index 0000000000000..9fa99d3be8af4 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs @@ -0,0 +1,9 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/tango +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs b/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs new file mode 100644 index 0000000000000..8eb0f1d049831 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs @@ -0,0 +1,22 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=finalize +//@ doc-flags:--include-parts-dir=info/doc.parts/tango +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has quebec/struct.Quebec.html +//@ has sierra/struct.Sierra.html +//@ has tango/trait.Tango.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html' +//@ hasraw search-index.js 'Tango' +//@ hasraw search-index.js 'Sierra' +//@ !hasraw search-index.js 'Quebec' + +// we overwrite quebec and tango's cross-crate information, but we +// include the info from tango meaning that it should appear in the out +// dir +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs new file mode 100644 index 0000000000000..d10bc0316ccad --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs @@ -0,0 +1,7 @@ +//@ unique-doc-out-dir +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs new file mode 100644 index 0000000000000..3c3721ee6eb7d --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs @@ -0,0 +1,10 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ unique-doc-out-dir +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/tango +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs b/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs new file mode 100644 index 0000000000000..4ee036238b4b1 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs @@ -0,0 +1,25 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=finalize +//@ doc-flags:--include-parts-dir=info/doc.parts/tango +//@ doc-flags:--include-parts-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html +//@ has index.html '//h1' 'List of all crates' +//@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec' +//@ has index.html '//ul[@class="all-items"]//a[@href="sierra/index.html"]' 'sierra' +//@ has index.html '//ul[@class="all-items"]//a[@href="tango/index.html"]' 'tango' +//@ has sierra/struct.Sierra.html +//@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html' +//@ hasraw search-index.js 'Tango' +//@ hasraw search-index.js 'Sierra' +//@ hasraw search-index.js 'Quebec' + +// If these were documeted into the same directory, the info would be +// overwritten. However, since they are merged, we can still recover all +// of the cross-crate information +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/quebec.rs new file mode 100644 index 0000000000000..0e28d8e646647 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/quebec.rs @@ -0,0 +1,5 @@ +//@ doc-flags:--merge=none +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/tango.rs new file mode 100644 index 0000000000000..363b2d5508e63 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/tango.rs @@ -0,0 +1,8 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ doc-flags:--merge=finalize +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs b/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs new file mode 100644 index 0000000000000..11e61dd2744b6 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs @@ -0,0 +1,20 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=shared +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has quebec/struct.Quebec.html +//@ has sierra/struct.Sierra.html +//@ has tango/trait.Tango.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html' +//@ hasraw search-index.js 'Tango' +//@ hasraw search-index.js 'Sierra' +//@ !hasraw search-index.js 'Quebec' + +// since tango is documented with --merge=finalize, we overwrite q's +// cross-crate information +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs b/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs new file mode 100644 index 0000000000000..09bb78c06f1c2 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs @@ -0,0 +1,13 @@ +//@ doc-flags:--merge=finalize +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html +//@ has index.html '//h1' 'List of all crates' +//@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec' +//@ has quebec/struct.Quebec.html +//@ hasraw search-index.js 'Quebec' + +// there is nothing to read from the output directory if we use a single +// crate +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs b/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs new file mode 100644 index 0000000000000..72475426f6edd --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs @@ -0,0 +1,12 @@ +//@ doc-flags:--merge=shared +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html +//@ has index.html '//h1' 'List of all crates' +//@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec' +//@ has quebec/struct.Quebec.html +//@ hasraw search-index.js 'Quebec' + +// read-write is the default and this does the same as `single-crate` +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs b/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs new file mode 100644 index 0000000000000..b20e173a8307e --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs @@ -0,0 +1,13 @@ +//@ doc-flags:--parts-out-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html +//@ has index.html '//h1' 'List of all crates' +//@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec' +//@ has quebec/struct.Quebec.html +//@ hasraw search-index.js 'Quebec' + +// we can --parts-out-dir, but that doesn't do anything other than create +// the file +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs b/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs new file mode 100644 index 0000000000000..e888a43c46042 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs @@ -0,0 +1,11 @@ +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ !has index.html +//@ has quebec/struct.Quebec.html +//@ !has search-index.js + +// --merge=none doesn't write anything, despite --parts-out-dir +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs new file mode 100644 index 0000000000000..1beca543f814f --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs @@ -0,0 +1,5 @@ +//@ doc-flags:--merge=finalize +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs new file mode 100644 index 0000000000000..363b2d5508e63 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs @@ -0,0 +1,8 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ doc-flags:--merge=finalize +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs b/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs new file mode 100644 index 0000000000000..68fc4b13fa8f7 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs @@ -0,0 +1,20 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=finalize +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html +//@ has index.html '//h1' 'List of all crates' +//@ has index.html '//ul[@class="all-items"]//a[@href="sierra/index.html"]' 'sierra' +//@ has index.html '//ul[@class="all-items"]//a[@href="tango/index.html"]' 'tango' +//@ has sierra/struct.Sierra.html +//@ has tango/trait.Tango.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html' +//@ hasraw search-index.js 'Sierra' + +// write only overwrites stuff in the output directory +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs new file mode 100644 index 0000000000000..6ab921533b037 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs @@ -0,0 +1,6 @@ +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs new file mode 100644 index 0000000000000..9fa99d3be8af4 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs @@ -0,0 +1,9 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ doc-flags:--merge=none +//@ doc-flags:--parts-out-dir=info/doc.parts/tango +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs b/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs new file mode 100644 index 0000000000000..b407228085e88 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs @@ -0,0 +1,27 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=finalize +//@ doc-flags:--include-parts-dir=info/doc.parts/tango +//@ doc-flags:--include-parts-dir=info/doc.parts/quebec +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html +//@ has index.html '//h1' 'List of all crates' +//@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec' +//@ has index.html '//ul[@class="all-items"]//a[@href="sierra/index.html"]' 'sierra' +//@ has index.html '//ul[@class="all-items"]//a[@href="tango/index.html"]' 'tango' +//@ has quebec/struct.Quebec.html +//@ has sierra/struct.Sierra.html +//@ has tango/trait.Tango.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html' +//@ hasraw search-index.js 'Tango' +//@ hasraw search-index.js 'Sierra' +//@ hasraw search-index.js 'Quebec' + +// We avoid writing any cross-crate information, preferring to include it +// with --include-parts-dir. +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs new file mode 100644 index 0000000000000..1beca543f814f --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs @@ -0,0 +1,5 @@ +//@ doc-flags:--merge=finalize +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs new file mode 100644 index 0000000000000..ff12fe98d82c2 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs @@ -0,0 +1,8 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ doc-flags:--merge=shared +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs b/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs new file mode 100644 index 0000000000000..15e32d5941fb2 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs @@ -0,0 +1,25 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=shared +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ has index.html +//@ has index.html '//h1' 'List of all crates' +//@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec' +//@ has index.html '//ul[@class="all-items"]//a[@href="sierra/index.html"]' 'sierra' +//@ has index.html '//ul[@class="all-items"]//a[@href="tango/index.html"]' 'tango' +//@ has quebec/struct.Quebec.html +//@ has sierra/struct.Sierra.html +//@ has tango/trait.Tango.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html' +//@ hasraw search-index.js 'Tango' +//@ hasraw search-index.js 'Sierra' +//@ hasraw search-index.js 'Quebec' + +// We can use read-write to emulate the default behavior of rustdoc, when +// --merge is left out. +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs b/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs new file mode 100644 index 0000000000000..0e28d8e646647 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs @@ -0,0 +1,5 @@ +//@ doc-flags:--merge=none +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +pub struct Quebec; diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs b/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs new file mode 100644 index 0000000000000..3827119f696f5 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs @@ -0,0 +1,8 @@ +//@ aux-build:quebec.rs +//@ build-aux-docs +//@ doc-flags:--merge=none +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +extern crate quebec; +pub trait Tango {} diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs b/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs new file mode 100644 index 0000000000000..3eb2cebd74363 --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs @@ -0,0 +1,17 @@ +//@ aux-build:tango.rs +//@ build-aux-docs +//@ doc-flags:--merge=none +//@ doc-flags:--enable-index-page +//@ doc-flags:-Zunstable-options + +//@ !has index.html +//@ has sierra/struct.Sierra.html +//@ has tango/trait.Tango.html +//@ hasraw sierra/struct.Sierra.html 'Tango' +//@ !has trait.impl/tango/trait.Tango.js +//@ !has search-index.js + +// --merge=none on all crates does not generate any cross-crate info +extern crate tango; +pub struct Sierra; +impl tango::Tango for Sierra {} diff --git a/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs b/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs new file mode 100644 index 0000000000000..e492b700dbc2b --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs @@ -0,0 +1,5 @@ +//@ unique-doc-out-dir +//@ doc-flags:--parts-out-dir=info/doc.parts/foxtrot +//@ doc-flags:-Zunstable-options + +pub trait Foxtrot {} diff --git a/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs b/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs new file mode 100644 index 0000000000000..ee2b646e43cda --- /dev/null +++ b/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs @@ -0,0 +1,16 @@ +//@ aux-build:foxtrot.rs +//@ build-aux-docs +//@ doc-flags:--include-parts-dir=info/doc.parts/foxtrot +//@ doc-flags:-Zunstable-options + +//@ has echo/enum.Echo.html +//@ hasraw echo/enum.Echo.html 'Foxtrot' +//@ hasraw trait.impl/foxtrot/trait.Foxtrot.js 'enum.Echo.html' +//@ hasraw search-index.js 'Foxtrot' +//@ hasraw search-index.js 'Echo' + +// document two crates in different places, and merge their docs after +// they are generated +extern crate foxtrot; +pub enum Echo {} +impl foxtrot::Foxtrot for Echo {} diff --git a/tests/rustdoc/issue-109258-missing-private-inlining.rs b/tests/rustdoc/missing-private-inlining-109258.rs similarity index 100% rename from tests/rustdoc/issue-109258-missing-private-inlining.rs rename to tests/rustdoc/missing-private-inlining-109258.rs diff --git a/tests/rustdoc/primitive-reference.rs b/tests/rustdoc/primitive-reference.rs index c12d65ee0c578..bd6b2a32f754f 100644 --- a/tests/rustdoc/primitive-reference.rs +++ b/tests/rustdoc/primitive-reference.rs @@ -8,7 +8,6 @@ //@ has - '//div[@class="sidebar-elems"]//li/a' 'Primitive Types' //@ has - '//div[@class="sidebar-elems"]//li/a/@href' '#primitives' //@ has foo/primitive.reference.html -//@ has - '//a[@class="primitive"]' 'reference' //@ has - '//h1' 'Primitive Type reference' //@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' diff --git a/tests/rustdoc/primitive-slice-auto-trait.rs b/tests/rustdoc/primitive-slice-auto-trait.rs index a877b73cf9f86..e78d1d9461421 100644 --- a/tests/rustdoc/primitive-slice-auto-trait.rs +++ b/tests/rustdoc/primitive-slice-auto-trait.rs @@ -3,8 +3,7 @@ #![crate_name = "foo"] #![feature(rustc_attrs)] -//@ has foo/primitive.slice.html '//a[@class="primitive"]' 'slice' -//@ has - '//h1' 'Primitive Type slice' +//@ has foo/primitive.slice.html '//h1' 'Primitive Type slice' //@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' //@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' //@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for [T]where T: Send' diff --git a/tests/rustdoc/primitive-tuple-auto-trait.rs b/tests/rustdoc/primitive-tuple-auto-trait.rs index 060c4ecfbdc1d..045478e6b4f8c 100644 --- a/tests/rustdoc/primitive-tuple-auto-trait.rs +++ b/tests/rustdoc/primitive-tuple-auto-trait.rs @@ -3,8 +3,7 @@ #![crate_name = "foo"] #![feature(rustc_attrs)] -//@ has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple' -//@ has - '//h1' 'Primitive Type tuple' +//@ has foo/primitive.tuple.html '//h1' 'Primitive Type tuple' //@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' //@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' //@ has - '//div[@id="synthetic-implementations-list"]//h3' 'Send' diff --git a/tests/rustdoc/primitive-unit-auto-trait.rs b/tests/rustdoc/primitive-unit-auto-trait.rs index 7751a2bf1d043..6cae094c21c81 100644 --- a/tests/rustdoc/primitive-unit-auto-trait.rs +++ b/tests/rustdoc/primitive-unit-auto-trait.rs @@ -3,8 +3,7 @@ #![crate_name = "foo"] #![feature(rustc_attrs)] -//@ has foo/primitive.unit.html '//a[@class="primitive"]' 'unit' -//@ has - '//h1' 'Primitive Type unit' +//@ has foo/primitive.unit.html '//h1' 'Primitive Type unit' //@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' //@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' //@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()' diff --git a/tests/rustdoc/issue-110629-private-type-cycle.rs b/tests/rustdoc/private-type-cycle-110629.rs similarity index 80% rename from tests/rustdoc/issue-110629-private-type-cycle.rs rename to tests/rustdoc/private-type-cycle-110629.rs index 22ea721fd440d..e237680969795 100644 --- a/tests/rustdoc/issue-110629-private-type-cycle.rs +++ b/tests/rustdoc/private-type-cycle-110629.rs @@ -1,10 +1,12 @@ //@ compile-flags: --document-private-items +// https://github.com/rust-lang/rust/issues/110629 +#![crate_name="foo"] #![feature(type_alias_impl_trait)] type Bar<'a, 'b> = impl PartialEq> + std::fmt::Debug; -//@ has issue_110629_private_type_cycle/type.Bar.html +//@ has foo/type.Bar.html //@ has - '//pre[@class="rust item-decl"]' \ // "pub(crate) type Bar<'a, 'b> = impl PartialEq> + Debug;" diff --git a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs b/tests/rustdoc/reexport-trait-from-hidden-111064-2.rs similarity index 93% rename from tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs rename to tests/rustdoc/reexport-trait-from-hidden-111064-2.rs index 4b80f508e7f53..2b21f9862b447 100644 --- a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs +++ b/tests/rustdoc/reexport-trait-from-hidden-111064-2.rs @@ -1,3 +1,4 @@ +// Regression test for . #![feature(no_core)] #![no_core] #![crate_name = "foo"] diff --git a/tests/rustdoc/issue-111064-reexport-trait-from-hidden.rs b/tests/rustdoc/reexport-trait-from-hidden-111064.rs similarity index 100% rename from tests/rustdoc/issue-111064-reexport-trait-from-hidden.rs rename to tests/rustdoc/reexport-trait-from-hidden-111064.rs diff --git a/tests/rustdoc/sidebar/module.rs b/tests/rustdoc/sidebar/module.rs new file mode 100644 index 0000000000000..b5bcb9f232c75 --- /dev/null +++ b/tests/rustdoc/sidebar/module.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +//@ has 'foo/index.html' +//@ has - '//section[@id="rustdoc-toc"]/h3' 'Crate Items' + +//@ has 'foo/bar/index.html' +//@ has - '//section[@id="rustdoc-toc"]/h3' 'Module Items' +pub mod bar { + //@ has 'foo/bar/struct.Baz.html' + //@ !has - '//section[@id="rustdoc-toc"]/h3' 'Module Items' + pub struct Baz; +} + +//@ has 'foo/baz/index.html' +//@ !has - '//section[@id="rustdoc-toc"]/h3' 'Module Items' +pub mod baz {} diff --git a/tests/rustdoc/sidebar-all-page.rs b/tests/rustdoc/sidebar/sidebar-all-page.rs similarity index 100% rename from tests/rustdoc/sidebar-all-page.rs rename to tests/rustdoc/sidebar/sidebar-all-page.rs diff --git a/tests/rustdoc/sidebar-items.rs b/tests/rustdoc/sidebar/sidebar-items.rs similarity index 100% rename from tests/rustdoc/sidebar-items.rs rename to tests/rustdoc/sidebar/sidebar-items.rs diff --git a/tests/rustdoc/sidebar-link-generation.rs b/tests/rustdoc/sidebar/sidebar-link-generation.rs similarity index 100% rename from tests/rustdoc/sidebar-link-generation.rs rename to tests/rustdoc/sidebar/sidebar-link-generation.rs diff --git a/tests/rustdoc/sidebar-links-to-foreign-impl.rs b/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs similarity index 100% rename from tests/rustdoc/sidebar-links-to-foreign-impl.rs rename to tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs new file mode 100644 index 0000000000000..0f60396043475 --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -0,0 +1,23 @@ +// ignore-tidy-linelength + +#![crate_name = "foo"] +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +//! # Basic [link](https://example.com), *emphasis*, **_very emphasis_** and `code` +//! +//! This test case covers TOC entries with rich text inside. +//! Rustdoc normally supports headers with links, but for the +//! TOC, that would break the layout. +//! +//! For consistency, emphasis is also filtered out. + +//@ has foo/index.html +// User header +//@ has - '//section[@id="rustdoc-toc"]/h3' 'Sections' +//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/@title' 'Basic link, emphasis, very emphasis and `code`' +//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]' 'Basic link, emphasis, very emphasis and code' +//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/em' 0 +//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/a' 0 +//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 1 +//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 'code' diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc/sidebar/top-toc-idmap.rs new file mode 100644 index 0000000000000..af07cb4179b1f --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-idmap.rs @@ -0,0 +1,44 @@ +#![crate_name = "foo"] +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +//! # Structs +//! +//! This header has the same name as a built-in header, +//! and we need to make sure they're disambiguated with +//! suffixes. +//! +//! Module-like headers get derived from the internal ID map, +//! so the *internal* one gets a suffix here. To make sure it +//! works right, the one in the `top-toc` needs to match the one +//! in the `top-doc`, and the one that's not in the `top-doc` +//! needs to match the one that isn't in the `top-toc`. + +//@ has foo/index.html +// User header +//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' +//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs' +// Built-in header +//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' +//@ has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs' + +/// # Fields +/// ## Fields +/// ### Fields +/// +/// The difference between struct-like headers and module-like headers +/// is strange, but not actually a problem as long as we're consistent. + +//@ has foo/struct.MyStruct.html +// User header +//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' +//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields' +// Only one level of nesting +//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]//a' 2 +// Built-in header +//@ has - '//section[@id="rustdoc-toc"]/h3/a[@href="#fields"]' 'Fields' +//@ has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields' + +pub struct MyStruct { + pub fields: i32, +} diff --git a/tests/rustdoc/sidebar/top-toc-nil.rs b/tests/rustdoc/sidebar/top-toc-nil.rs new file mode 100644 index 0000000000000..d72d41abf8892 --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-nil.rs @@ -0,0 +1,7 @@ +#![crate_name = "foo"] + +//! This test case covers missing top TOC entries. + +//@ has foo/index.html +// User header +//@ !has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]' 'Basic link and emphasis' diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-version-separator.rs index a998c538eed74..9709bbe3c7181 100644 --- a/tests/rustdoc/source-version-separator.rs +++ b/tests/rustdoc/source-version-separator.rs @@ -3,7 +3,7 @@ #![feature(staged_api)] //@ has foo/trait.Bar.html -//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' +//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source' #[stable(feature = "bar", since = "1.0")] pub trait Bar { //@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source' @@ -14,7 +14,7 @@ pub trait Bar { //@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source' //@ has foo/struct.Foo.html -//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' +//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source' #[stable(feature = "baz", since = "1.0")] pub struct Foo; diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs index 270da822c009b..de855b43ba538 100644 --- a/tests/rustdoc/stability.rs +++ b/tests/rustdoc/stability.rs @@ -1,6 +1,6 @@ #![feature(staged_api)] -#![unstable(feature = "test", issue = "none")] +#![stable(feature = "rust1", since = "1.0.0")] //@ has stability/index.html //@ has - '//ul[@class="item-table"]/li[1]//a' AaStable @@ -10,6 +10,7 @@ #[stable(feature = "rust2", since = "2.2.2")] pub struct AaStable; +#[unstable(feature = "test", issue = "none")] pub struct Unstable { //@ has stability/struct.Unstable.html \ // '//span[@class="item-info"]//div[@class="stab unstable"]' \ @@ -21,3 +22,31 @@ pub struct Unstable { #[stable(feature = "rust2", since = "2.2.2")] pub struct ZzStable; + +#[unstable(feature = "unstable", issue = "none")] +pub mod unstable { + //@ !hasraw stability/unstable/struct.Foo.html '//span[@class="since"]' + //@ has - '//div[@class="stab unstable"]' 'experimental' + #[stable(feature = "rust1", since = "1.0.0")] + pub struct Foo; +} + +#[stable(feature = "rust2", since = "2.2.2")] +pub mod stable_later { + //@ has stability/stable_later/struct.Bar.html '//span[@class="since"]' '2.2.2' + #[stable(feature = "rust1", since = "1.0.0")] + pub struct Bar; +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod stable_earlier { + //@ has stability/stable_earlier/struct.Foo.html '//span[@class="since"]' '1.0.0' + #[doc(inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::unstable::Foo; + + //@ has stability/stable_earlier/struct.Bar.html '//span[@class="since"]' '1.0.0' + #[doc(inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::stable_later::Bar; +} diff --git a/tests/rustdoc/strip-enum-variant.no-not-shown.html b/tests/rustdoc/strip-enum-variant.no-not-shown.html index e072335297d6b..d7a36cc631ac6 100644 --- a/tests/rustdoc/strip-enum-variant.no-not-shown.html +++ b/tests/rustdoc/strip-enum-variant.no-not-shown.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/tests/rustdoc/titles.rs b/tests/rustdoc/titles.rs index bdf950b0a6225..922068adc5927 100644 --- a/tests/rustdoc/titles.rs +++ b/tests/rustdoc/titles.rs @@ -5,53 +5,65 @@ //@ matches 'foo/index.html' '//div[@class="sidebar-crate"]/h2/a' 'foo' //@ count 'foo/index.html' '//h2[@class="location"]' 0 -//@ matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod' -//@ matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod' +//@ matches 'foo/foo_mod/index.html' '//h1' 'Module foo_mod' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' +//@ matches - '//h2[@class="location"]' 'Module foo_mod' pub mod foo_mod { pub struct __Thing {} } extern "C" { - //@ matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo::foo_ffn' + //@ matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo_ffn' + //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' pub fn foo_ffn(); } -//@ matches 'foo/fn.foo_fn.html' '//h1' 'Function foo::foo_fn' +//@ matches 'foo/fn.foo_fn.html' '//h1' 'Function foo_fn' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' pub fn foo_fn() {} -//@ matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait' -//@ matches 'foo/trait.FooTrait.html' '//h2[@class="location"]' 'FooTrait' +//@ matches 'foo/trait.FooTrait.html' '//h1' 'Trait FooTrait' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' +//@ matches - '//h2[@class="location"]' 'FooTrait' pub trait FooTrait {} -//@ matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct' -//@ matches 'foo/struct.FooStruct.html' '//h2[@class="location"]' 'FooStruct' +//@ matches 'foo/struct.FooStruct.html' '//h1' 'Struct FooStruct' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' +//@ matches - '//h2[@class="location"]' 'FooStruct' pub struct FooStruct; -//@ matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum' -//@ matches 'foo/enum.FooEnum.html' '//h2[@class="location"]' 'FooEnum' +//@ matches 'foo/enum.FooEnum.html' '//h1' 'Enum FooEnum' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' +//@ matches - '//h2[@class="location"]' 'FooEnum' pub enum FooEnum {} -//@ matches 'foo/type.FooType.html' '//h1' 'Type Alias foo::FooType' -//@ matches 'foo/type.FooType.html' '//h2[@class="location"]' 'FooType' +//@ matches 'foo/type.FooType.html' '//h1' 'Type Alias FooType' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' +//@ matches - '//h2[@class="location"]' 'FooType' pub type FooType = FooStruct; -//@ matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro' +//@ matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo_macro' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' #[macro_export] macro_rules! foo_macro { () => {}; } //@ matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool' +//@ count - '//*[@class="rustdoc-breadcrumbs"]' 0 #[rustc_doc_primitive = "bool"] mod bool {} -//@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC' +//@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static FOO_STATIC' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' pub static FOO_STATIC: FooStruct = FooStruct; extern "C" { - //@ matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static foo::FOO_FSTATIC' + //@ matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static FOO_FSTATIC' + //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' pub static FOO_FSTATIC: FooStruct; } -//@ matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant foo::FOO_CONSTANT' +//@ matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant FOO_CONSTANT' +//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' pub const FOO_CONSTANT: FooStruct = FooStruct; diff --git a/tests/rustdoc/version-separator-without-source.rs b/tests/rustdoc/version-separator-without-source.rs index e439681484c36..7cd1780f1d30e 100644 --- a/tests/rustdoc/version-separator-without-source.rs +++ b/tests/rustdoc/version-separator-without-source.rs @@ -4,14 +4,14 @@ #![crate_name = "foo"] //@ has foo/fn.foo.html -//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · ' -//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' +//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0' +//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source' #[stable(feature = "bar", since = "1.0")] pub fn foo() {} //@ has foo/struct.Bar.html -//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · ' -//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' +//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0' +//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source' #[stable(feature = "bar", since = "1.0")] pub struct Bar; diff --git a/tests/ui-fulldeps/fluent-messages/many-lines.ftl b/tests/ui-fulldeps/fluent-messages/many-lines.ftl new file mode 100644 index 0000000000000..43660ebeacdc5 --- /dev/null +++ b/tests/ui-fulldeps/fluent-messages/many-lines.ftl @@ -0,0 +1,11 @@ +no_crate_foo = foo + +# This file tests error reporting for +# fluent files with many lines. +# The error message should point to the correct line number +# and include no more context than necessary. + +no_crate_bar = + +no_crate_baz = + baz diff --git a/tests/ui-fulldeps/fluent-messages/test.rs b/tests/ui-fulldeps/fluent-messages/test.rs index 7bf1252ccf602..3361ebcef018d 100644 --- a/tests/ui-fulldeps/fluent-messages/test.rs +++ b/tests/ui-fulldeps/fluent-messages/test.rs @@ -80,3 +80,8 @@ mod bad_escape { //~| ERROR invalid escape `\"` //~| ERROR invalid escape `\'` } + +mod many_lines { + rustc_fluent_macro::fluent_messages! { "./many-lines.ftl" } + //~^ ERROR could not parse Fluent resource +} diff --git a/tests/ui-fulldeps/fluent-messages/test.stderr b/tests/ui-fulldeps/fluent-messages/test.stderr index 09d4a38473204..0b3bb14ce513b 100644 --- a/tests/ui-fulldeps/fluent-messages/test.stderr +++ b/tests/ui-fulldeps/fluent-messages/test.stderr @@ -103,5 +103,20 @@ LL | rustc_fluent_macro::fluent_messages! { "./invalid-escape.ftl" } | = note: Fluent does not interpret these escape sequences () -error: aborting due to 13 previous errors +error: could not parse Fluent resource + --> $DIR/test.rs:85:44 + | +LL | rustc_fluent_macro::fluent_messages! { "./many-lines.ftl" } + | ^^^^^^^^^^^^^^^^^^ + | + = help: see additional errors emitted + +error: expected a message field for "no_crate_bar" + --> ./many-lines.ftl:8:1 + | +8 | no_crate_bar = + | ^^^^^^^^^^^^^^ + | + +error: aborting due to 14 previous errors diff --git a/tests/ui-fulldeps/internal-lints/import-of-type-ir-inherent.rs b/tests/ui-fulldeps/internal-lints/import-of-type-ir-inherent.rs new file mode 100644 index 0000000000000..08d86606a6bab --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/import-of-type-ir-inherent.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -Z unstable-options + +// #[cfg(bootstrap)]: We can stop ignoring next beta bump; afterward this ALWAYS should run. +//@ ignore-stage1 + +#![feature(rustc_private)] +#![deny(rustc::usage_of_type_ir_inherent)] + +extern crate rustc_type_ir; + +use rustc_type_ir::inherent::*; +//~^ ERROR do not use `rustc_type_ir::inherent` unless you're inside of the trait solver +use rustc_type_ir::inherent; +//~^ ERROR do not use `rustc_type_ir::inherent` unless you're inside of the trait solver +use rustc_type_ir::inherent::Predicate; +//~^ ERROR do not use `rustc_type_ir::inherent` unless you're inside of the trait solver + +fn main() {} diff --git a/tests/ui-fulldeps/internal-lints/import-of-type-ir-inherent.stderr b/tests/ui-fulldeps/internal-lints/import-of-type-ir-inherent.stderr new file mode 100644 index 0000000000000..cc6cb9170c0d4 --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/import-of-type-ir-inherent.stderr @@ -0,0 +1,31 @@ +error: do not use `rustc_type_ir::inherent` unless you're inside of the trait solver + --> $DIR/import-of-type-ir-inherent.rs:11:20 + | +LL | use rustc_type_ir::inherent::*; + | ^^^^^^^^ + | + = note: the method or struct you're looking for is likely defined somewhere else downstream in the compiler +note: the lint level is defined here + --> $DIR/import-of-type-ir-inherent.rs:7:9 + | +LL | #![deny(rustc::usage_of_type_ir_inherent)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not use `rustc_type_ir::inherent` unless you're inside of the trait solver + --> $DIR/import-of-type-ir-inherent.rs:13:20 + | +LL | use rustc_type_ir::inherent; + | ^^^^^^^^ + | + = note: the method or struct you're looking for is likely defined somewhere else downstream in the compiler + +error: do not use `rustc_type_ir::inherent` unless you're inside of the trait solver + --> $DIR/import-of-type-ir-inherent.rs:15:20 + | +LL | use rustc_type_ir::inherent::Predicate; + | ^^^^^^^^ + | + = note: the method or struct you're looking for is likely defined somewhere else downstream in the compiler + +error: aborting due to 3 previous errors + diff --git a/tests/ui-fulldeps/internal-lints/query_completeness.rs b/tests/ui-fulldeps/internal-lints/query_completeness.rs new file mode 100644 index 0000000000000..50b0fb4c3fc02 --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/query_completeness.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Z unstable-options +// #[cfg(bootstrap)]: We can stop ignoring next beta bump; afterward this ALWAYS should run. +//@ ignore-stage1 (requires matching sysroot built with in-tree compiler) +#![feature(rustc_private)] +#![deny(rustc::untracked_query_information)] + +extern crate rustc_data_structures; + +use rustc_data_structures::steal::Steal; + +fn use_steal(x: Steal<()>) { + let _ = x.is_stolen(); + //~^ ERROR `is_stolen` accesses information that is not tracked by the query system +} + +fn main() {} diff --git a/tests/ui-fulldeps/internal-lints/query_completeness.stderr b/tests/ui-fulldeps/internal-lints/query_completeness.stderr new file mode 100644 index 0000000000000..35bb867f40e8f --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/query_completeness.stderr @@ -0,0 +1,15 @@ +error: `is_stolen` accesses information that is not tracked by the query system + --> $DIR/query_completeness.rs:12:15 + | +LL | let _ = x.is_stolen(); + | ^^^^^^^^^ + | + = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale +note: the lint level is defined here + --> $DIR/query_completeness.rs:5:9 + | +LL | #![deny(rustc::untracked_query_information)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index 720fc42cc5700..cce4eac0d7c15 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -65,7 +65,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path output_dir: None, ice_file: None, file_loader: None, - locale_resources: &[], + locale_resources: Vec::new(), lint_caps: Default::default(), psess_created: None, hash_untracked_state: None, diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 5449c09d35ab6..68eb3c54593ea 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -35,7 +35,7 @@ fn test_stable_mir() -> ControlFlow<()> { // Get all items and split generic vs monomorphic items. let (generic, mono): (Vec<_>, Vec<_>) = items.into_iter().partition(|item| item.requires_monomorphization()); - assert_eq!(mono.len(), 4, "Expected 3 mono functions"); + assert_eq!(mono.len(), 3, "Expected 3 mono functions"); assert_eq!(generic.len(), 2, "Expected 2 generic functions"); // For all monomorphic items, get the correspondent instances. diff --git a/tests/ui/abi/arm-unadjusted-intrinsic.rs b/tests/ui/abi/arm-unadjusted-intrinsic.rs index 7a728d4b241d9..533cd40b30a5c 100644 --- a/tests/ui/abi/arm-unadjusted-intrinsic.rs +++ b/tests/ui/abi/arm-unadjusted-intrinsic.rs @@ -25,16 +25,13 @@ impl Copy for i8 {} impl Copy for *const T {} impl Copy for *mut T {} +// I hate no_core tests! +impl Copy for [T; N] {} // Regression test for https://github.com/rust-lang/rust/issues/118124. #[repr(simd)] -pub struct int8x16_t( - pub(crate) i8, pub(crate) i8, pub(crate) i8, pub(crate) i8, - pub(crate) i8, pub(crate) i8, pub(crate) i8, pub(crate) i8, - pub(crate) i8, pub(crate) i8, pub(crate) i8, pub(crate) i8, - pub(crate) i8, pub(crate) i8, pub(crate) i8, pub(crate) i8, -); +pub struct int8x16_t(pub(crate) [i8; 16]); impl Copy for int8x16_t {} #[repr(C)] diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index d37e793d9892d..b439a4bcf867b 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -39,7 +39,6 @@ //@ revisions: loongarch64 //@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64] needs-llvm-components: loongarch -//@[loongarch64] min-llvm-version: 18 //FIXME: wasm is disabled due to . //FIXME @ revisions: wasm //FIXME @[wasm] compile-flags: --target wasm32-unknown-unknown @@ -189,7 +188,7 @@ mod prelude { #[cfg(not(host))] use prelude::*; -macro_rules! assert_abi_compatible { +macro_rules! test_abi_compatible { ($name:ident, $t1:ty, $t2:ty) => { mod $name { use super::*; @@ -212,16 +211,6 @@ impl Clone for Zst { } } -#[repr(C)] -struct ReprC1(T); -#[repr(C)] -struct ReprC2Int(i32, T); -#[repr(C)] -struct ReprC2Float(f32, T); -#[repr(C)] -struct ReprC4(T, Vec, Zst, T); -#[repr(C)] -struct ReprC4Mixed(T, f32, i32, T); #[repr(C)] enum ReprCEnum { Variant1, @@ -233,23 +222,6 @@ union ReprCUnion { something: ManuallyDrop, } -macro_rules! test_abi_compatible { - ($name:ident, $t1:ty, $t2:ty) => { - mod $name { - use super::*; - assert_abi_compatible!(plain, $t1, $t2); - // We also do some tests with differences in fields of `repr(C)` types. - assert_abi_compatible!(repr_c_1, ReprC1<$t1>, ReprC1<$t2>); - assert_abi_compatible!(repr_c_2_int, ReprC2Int<$t1>, ReprC2Int<$t2>); - assert_abi_compatible!(repr_c_2_float, ReprC2Float<$t1>, ReprC2Float<$t2>); - assert_abi_compatible!(repr_c_4, ReprC4<$t1>, ReprC4<$t2>); - assert_abi_compatible!(repr_c_4mixed, ReprC4Mixed<$t1>, ReprC4Mixed<$t2>); - assert_abi_compatible!(repr_c_enum, ReprCEnum<$t1>, ReprCEnum<$t2>); - assert_abi_compatible!(repr_c_union, ReprCUnion<$t1>, ReprCUnion<$t2>); - } - }; -} - // Compatibility of pointers. test_abi_compatible!(ptr_mut, *const i32, *mut i32); test_abi_compatible!(ptr_pointee, *const i32, *const Vec); @@ -268,7 +240,6 @@ test_abi_compatible!(isize_int, isize, i64); // Compatibility of 1-ZST. test_abi_compatible!(zst_unit, Zst, ()); -#[cfg(not(any(target_arch = "sparc64")))] test_abi_compatible!(zst_array, Zst, [u8; 0]); test_abi_compatible!(nonzero_int, NonZero, i32); @@ -285,13 +256,13 @@ test_abi_compatible!(arc, Arc, *mut i32); // `repr(transparent)` compatibility. #[repr(transparent)] -struct Wrapper1(T); +struct TransparentWrapper1(T); #[repr(transparent)] -struct Wrapper2((), Zst, T); +struct TransparentWrapper2((), Zst, T); #[repr(transparent)] -struct Wrapper3(T, [u8; 0], PhantomData); +struct TransparentWrapper3(T, [u8; 0], PhantomData); #[repr(transparent)] -union WrapperUnion { +union TransparentWrapperUnion { nothing: (), something: ManuallyDrop, } @@ -300,10 +271,10 @@ macro_rules! test_transparent { ($name:ident, $t:ty) => { mod $name { use super::*; - test_abi_compatible!(wrap1, $t, Wrapper1<$t>); - test_abi_compatible!(wrap2, $t, Wrapper2<$t>); - test_abi_compatible!(wrap3, $t, Wrapper3<$t>); - test_abi_compatible!(wrap4, $t, WrapperUnion<$t>); + test_abi_compatible!(wrap1, $t, TransparentWrapper1<$t>); + test_abi_compatible!(wrap2, $t, TransparentWrapper2<$t>); + test_abi_compatible!(wrap3, $t, TransparentWrapper3<$t>); + test_abi_compatible!(wrap4, $t, TransparentWrapperUnion<$t>); } }; } @@ -342,10 +313,8 @@ macro_rules! test_transparent_unsized { ($name:ident, $t:ty) => { mod $name { use super::*; - assert_abi_compatible!(wrap1, $t, Wrapper1<$t>); - assert_abi_compatible!(wrap1_reprc, ReprC1<$t>, ReprC1>); - assert_abi_compatible!(wrap2, $t, Wrapper2<$t>); - assert_abi_compatible!(wrap2_reprc, ReprC1<$t>, ReprC1>); + test_abi_compatible!(wrap1, $t, TransparentWrapper1<$t>); + test_abi_compatible!(wrap2, $t, TransparentWrapper2<$t>); } }; } diff --git a/tests/ui/abi/homogenous-floats-target-feature-mixup.rs b/tests/ui/abi/homogenous-floats-target-feature-mixup.rs index 3a8540a825ca2..4afb710b193eb 100644 --- a/tests/ui/abi/homogenous-floats-target-feature-mixup.rs +++ b/tests/ui/abi/homogenous-floats-target-feature-mixup.rs @@ -65,13 +65,13 @@ fn is_sigill(status: ExitStatus) -> bool { #[allow(nonstandard_style)] mod test { #[derive(PartialEq, Debug, Clone, Copy)] - struct f32x2(f32, f32); + struct f32x2([f32; 2]); #[derive(PartialEq, Debug, Clone, Copy)] - struct f32x4(f32, f32, f32, f32); + struct f32x4([f32; 4]); #[derive(PartialEq, Debug, Clone, Copy)] - struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); + struct f32x8([f32; 8]); pub fn main(level: &str) { unsafe { @@ -97,9 +97,9 @@ mod test { )*) => ($( $(#[$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.); + 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); @@ -133,55 +133,55 @@ mod test { #[target_feature(enable = "sse2")] unsafe fn id_sse_128(a: f32x2) -> f32x2 { - assert_eq!(a, f32x2(1., 2.)); + 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.)); + 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.)); + 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.)); + 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.)); + 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.)); + 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.)); + 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.)); + 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.)); + assert_eq!(a, f32x8([7., 8., 9., 10., 11., 12., 13., 14.])); a.clone() } } diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs index 70343b0599ac3..e6c26c5c4de85 100644 --- a/tests/ui/abi/stack-probes-lto.rs +++ b/tests/ui/abi/stack-probes-lto.rs @@ -1,7 +1,6 @@ //@ revisions: aarch64 x32 x64 //@ run-pass //@[aarch64] only-aarch64 -//@[aarch64] min-llvm-version: 18 //@[x32] only-x86 //@[x64] only-x86_64 //@ ignore-sgx no processes diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs index 22304257593fe..1c0e50250d768 100644 --- a/tests/ui/abi/stack-probes.rs +++ b/tests/ui/abi/stack-probes.rs @@ -1,7 +1,6 @@ //@ revisions: aarch64 x32 x64 //@ run-pass //@[aarch64] only-aarch64 -//@[aarch64] min-llvm-version: 18 //@[x32] only-x86 //@[x64] only-x86_64 //@ ignore-emscripten no processes diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs index 167b7a4e36e9e..40cd57637e6cd 100644 --- a/tests/ui/abi/statics/static-mut-foreign.rs +++ b/tests/ui/abi/statics/static-mut-foreign.rs @@ -3,6 +3,9 @@ // statics cannot. This ensures that there's some form of error if this is // attempted. +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use std::ffi::c_int; #[link(name = "rust_test_helpers", kind = "static")] @@ -29,9 +32,7 @@ unsafe fn run() { rust_dbg_static_mut = -3; assert_eq!(rust_dbg_static_mut, -3); static_bound(&rust_dbg_static_mut); - //~^ WARN shared reference to mutable static is discouraged [static_mut_refs] static_bound_set(&mut rust_dbg_static_mut); - //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs] } pub fn main() { diff --git a/tests/ui/abi/statics/static-mut-foreign.stderr b/tests/ui/abi/statics/static-mut-foreign.stderr deleted file mode 100644 index 0c4bd5382a1f0..0000000000000 --- a/tests/ui/abi/statics/static-mut-foreign.stderr +++ /dev/null @@ -1,31 +0,0 @@ -warning: creating a shared reference to mutable static is discouraged - --> $DIR/static-mut-foreign.rs:31:18 - | -LL | static_bound(&rust_dbg_static_mut); - | ^^^^^^^^^^^^^^^^^^^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer - | -LL | static_bound(addr_of!(rust_dbg_static_mut)); - | ~~~~~~~~~ + - -warning: creating a mutable reference to mutable static is discouraged - --> $DIR/static-mut-foreign.rs:33:22 - | -LL | static_bound_set(&mut rust_dbg_static_mut); - | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | static_bound_set(addr_of_mut!(rust_dbg_static_mut)); - | ~~~~~~~~~~~~~ + - -warning: 2 warnings emitted - diff --git a/tests/ui/array-slice-vec/slice-panic-1.rs b/tests/ui/array-slice-vec/slice-panic-1.rs index 4436b63385641..d4f584c163222 100644 --- a/tests/ui/array-slice-vec/slice-panic-1.rs +++ b/tests/ui/array-slice-vec/slice-panic-1.rs @@ -5,6 +5,8 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] use std::thread; diff --git a/tests/ui/array-slice-vec/slice-panic-2.rs b/tests/ui/array-slice-vec/slice-panic-2.rs index 4bd139884244e..b3d1dc455735a 100644 --- a/tests/ui/array-slice-vec/slice-panic-2.rs +++ b/tests/ui/array-slice-vec/slice-panic-2.rs @@ -5,6 +5,8 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] use std::thread; diff --git a/tests/ui/array-slice-vec/slice.rs b/tests/ui/array-slice-vec/slice.rs index 2adcd96f5984a..ad5db7a2102b4 100644 --- a/tests/ui/array-slice-vec/slice.rs +++ b/tests/ui/array-slice-vec/slice.rs @@ -3,6 +3,9 @@ // Test slicing sugar. +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] + extern crate core; use core::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull}; diff --git a/tests/ui/asm/aarch64/type-check-2-2.rs b/tests/ui/asm/aarch64/type-check-2-2.rs index f442ce81476ed..4b8ee1d922986 100644 --- a/tests/ui/asm/aarch64/type-check-2-2.rs +++ b/tests/ui/asm/aarch64/type-check-2-2.rs @@ -6,10 +6,10 @@ use std::arch::{asm, global_asm}; #[repr(simd)] #[derive(Clone, Copy)] -struct SimdType(f32, f32, f32, f32); +struct SimdType([f32; 4]); #[repr(simd)] -struct SimdNonCopy(f32, f32, f32, f32); +struct SimdNonCopy([f32; 4]); fn main() { unsafe { diff --git a/tests/ui/asm/aarch64/type-check-2.rs b/tests/ui/asm/aarch64/type-check-2.rs index 46667ae3a6565..ad223b799b786 100644 --- a/tests/ui/asm/aarch64/type-check-2.rs +++ b/tests/ui/asm/aarch64/type-check-2.rs @@ -6,10 +6,10 @@ use std::arch::{asm, global_asm}; #[repr(simd)] #[derive(Clone, Copy)] -struct SimdType(f32, f32, f32, f32); +struct SimdType([f32; 4]); #[repr(simd)] -struct SimdNonCopy(f32, f32, f32, f32); +struct SimdNonCopy([f32; 4]); fn main() { unsafe { @@ -17,7 +17,7 @@ fn main() { // Register operands must be Copy - asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + asm!("{:v}", in(vreg) SimdNonCopy([0.0, 0.0, 0.0, 0.0])); //~^ ERROR arguments for inline assembly must be copyable // Register operands must be integers, floats, SIMD vectors, pointers or @@ -25,7 +25,7 @@ fn main() { asm!("{}", in(reg) 0i64); asm!("{}", in(reg) 0f64); - asm!("{:v}", in(vreg) SimdType(0.0, 0.0, 0.0, 0.0)); + asm!("{:v}", in(vreg) SimdType([0.0, 0.0, 0.0, 0.0])); asm!("{}", in(reg) 0 as *const u8); asm!("{}", in(reg) 0 as *mut u8); asm!("{}", in(reg) main as fn()); diff --git a/tests/ui/asm/aarch64/type-check-2.stderr b/tests/ui/asm/aarch64/type-check-2.stderr index b7723fc74d4b6..84bc5f08b4ed1 100644 --- a/tests/ui/asm/aarch64/type-check-2.stderr +++ b/tests/ui/asm/aarch64/type-check-2.stderr @@ -1,8 +1,8 @@ error: arguments for inline assembly must be copyable --> $DIR/type-check-2.rs:20:31 | -LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | asm!("{:v}", in(vreg) SimdNonCopy([0.0, 0.0, 0.0, 0.0])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `SimdNonCopy` does not implement the Copy trait diff --git a/tests/ui/asm/aarch64/type-check-3.rs b/tests/ui/asm/aarch64/type-check-3.rs index b64473f98c090..2f8439d0a0f9e 100644 --- a/tests/ui/asm/aarch64/type-check-3.rs +++ b/tests/ui/asm/aarch64/type-check-3.rs @@ -8,11 +8,11 @@ use std::arch::{asm, global_asm}; #[repr(simd)] #[derive(Copy, Clone)] -struct Simd256bit(f64, f64, f64, f64); +struct Simd256bit([f64; 4]); fn main() { let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) }; - let f64x4 = Simd256bit(0.0, 0.0, 0.0, 0.0); + let f64x4 = Simd256bit([0.0, 0.0, 0.0, 0.0]); unsafe { // Types must be listed in the register class. diff --git a/tests/ui/asm/aarch64/type-check-4.rs b/tests/ui/asm/aarch64/type-check-4.rs index 41eb9de5669f6..1169c3dcfa843 100644 --- a/tests/ui/asm/aarch64/type-check-4.rs +++ b/tests/ui/asm/aarch64/type-check-4.rs @@ -8,7 +8,7 @@ use std::arch::{asm, global_asm}; #[repr(simd)] #[derive(Copy, Clone)] -struct Simd256bit(f64, f64, f64, f64); +struct Simd256bit([f64; 4]); fn main() {} diff --git a/tests/ui/asm/const-refs-to-static.rs b/tests/ui/asm/const-refs-to-static.rs new file mode 100644 index 0000000000000..9fc010b576309 --- /dev/null +++ b/tests/ui/asm/const-refs-to-static.rs @@ -0,0 +1,21 @@ +//@ needs-asm-support +//@ ignore-nvptx64 +//@ ignore-spirv + +#![feature(const_refs_to_static)] + +use std::arch::{asm, global_asm}; +use std::ptr::addr_of; + +static FOO: u8 = 42; + +global_asm!("{}", const addr_of!(FOO)); +//~^ ERROR invalid type for `const` operand + +#[no_mangle] +fn inline() { + unsafe { asm!("{}", const addr_of!(FOO)) }; + //~^ ERROR invalid type for `const` operand +} + +fn main() {} diff --git a/tests/ui/asm/const-refs-to-static.stderr b/tests/ui/asm/const-refs-to-static.stderr new file mode 100644 index 0000000000000..8fd69da0d1e92 --- /dev/null +++ b/tests/ui/asm/const-refs-to-static.stderr @@ -0,0 +1,22 @@ +error: invalid type for `const` operand + --> $DIR/const-refs-to-static.rs:12:19 + | +LL | global_asm!("{}", const addr_of!(FOO)); + | ^^^^^^------------- + | | + | is a `*const u8` + | + = help: `const` operands must be of an integer type + +error: invalid type for `const` operand + --> $DIR/const-refs-to-static.rs:17:25 + | +LL | unsafe { asm!("{}", const addr_of!(FOO)) }; + | ^^^^^^------------- + | | + | is a `*const u8` + | + = help: `const` operands must be of an integer type + +error: aborting due to 2 previous errors + diff --git a/tests/ui/asm/inline-syntax.arm.stderr b/tests/ui/asm/inline-syntax.arm.stderr index 4a50ec8d0d5ac..61e5078d6d9b4 100644 --- a/tests/ui/asm/inline-syntax.arm.stderr +++ b/tests/ui/asm/inline-syntax.arm.stderr @@ -1,9 +1,11 @@ error: unknown directive -.intel_syntax noprefix -^ -error: unknown directive -.intel_syntax noprefix -^ + | +note: instantiated into assembly here + --> :1:1 + | +LL | .intel_syntax noprefix + | ^ + error: unknown directive | note: instantiated into assembly here @@ -13,7 +15,7 @@ LL | .intel_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:35:15 + --> $DIR/inline-syntax.rs:29:15 | LL | asm!(".intel_syntax noprefix", "nop"); | ^ @@ -25,7 +27,7 @@ LL | .intel_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:39:15 + --> $DIR/inline-syntax.rs:32:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); | ^ @@ -37,7 +39,7 @@ LL | .intel_syntax aaa noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:43:15 + --> $DIR/inline-syntax.rs:35:15 | LL | asm!(".att_syntax noprefix", "nop"); | ^ @@ -49,7 +51,7 @@ LL | .att_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:47:15 + --> $DIR/inline-syntax.rs:38:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); | ^ @@ -61,7 +63,7 @@ LL | .att_syntax bbb noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:51:15 + --> $DIR/inline-syntax.rs:41:15 | LL | asm!(".intel_syntax noprefix; nop"); | ^ @@ -73,7 +75,7 @@ LL | .intel_syntax noprefix; nop | ^ error: unknown directive - --> $DIR/inline-syntax.rs:58:13 + --> $DIR/inline-syntax.rs:47:13 | LL | .intel_syntax noprefix | ^ @@ -84,5 +86,5 @@ note: instantiated into assembly here LL | .intel_syntax noprefix | ^ -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/asm/inline-syntax.arm_llvm_18.stderr b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr deleted file mode 100644 index ada3f4891d3ac..0000000000000 --- a/tests/ui/asm/inline-syntax.arm_llvm_18.stderr +++ /dev/null @@ -1,90 +0,0 @@ -error: unknown directive - | -note: instantiated into assembly here - --> :1:1 - | -LL | .intel_syntax noprefix - | ^ - -error: unknown directive - | -note: instantiated into assembly here - --> :1:1 - | -LL | .intel_syntax noprefix - | ^ - -error: unknown directive - --> $DIR/inline-syntax.rs:35:15 - | -LL | asm!(".intel_syntax noprefix", "nop"); - | ^ - | -note: instantiated into assembly here - --> :1:2 - | -LL | .intel_syntax noprefix - | ^ - -error: unknown directive - --> $DIR/inline-syntax.rs:39:15 - | -LL | asm!(".intel_syntax aaa noprefix", "nop"); - | ^ - | -note: instantiated into assembly here - --> :1:2 - | -LL | .intel_syntax aaa noprefix - | ^ - -error: unknown directive - --> $DIR/inline-syntax.rs:43:15 - | -LL | asm!(".att_syntax noprefix", "nop"); - | ^ - | -note: instantiated into assembly here - --> :1:2 - | -LL | .att_syntax noprefix - | ^ - -error: unknown directive - --> $DIR/inline-syntax.rs:47:15 - | -LL | asm!(".att_syntax bbb noprefix", "nop"); - | ^ - | -note: instantiated into assembly here - --> :1:2 - | -LL | .att_syntax bbb noprefix - | ^ - -error: unknown directive - --> $DIR/inline-syntax.rs:51:15 - | -LL | asm!(".intel_syntax noprefix; nop"); - | ^ - | -note: instantiated into assembly here - --> :1:2 - | -LL | .intel_syntax noprefix; nop - | ^ - -error: unknown directive - --> $DIR/inline-syntax.rs:58:13 - | -LL | .intel_syntax noprefix - | ^ - | -note: instantiated into assembly here - --> :2:13 - | -LL | .intel_syntax noprefix - | ^ - -error: aborting due to 8 previous errors - diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index 4a98d37aca09a..b8486527e6fd6 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -1,16 +1,10 @@ -//@ revisions: x86_64 arm arm_llvm_18 +//@ revisions: x86_64 arm //@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu //@[x86_64] check-pass //@[x86_64] needs-llvm-components: x86 //@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf //@[arm] build-fail //@[arm] needs-llvm-components: arm -//@[arm] ignore-llvm-version: 18 - 99 -//Newer LLVM produces extra error notes. -//@[arm_llvm_18] compile-flags: --target armv7-unknown-linux-gnueabihf -//@[arm_llvm_18] build-fail -//@[arm_llvm_18] needs-llvm-components: arm -//@[arm_llvm_18] min-llvm-version: 18 //@ needs-asm-support #![feature(no_core, lang_items, rustc_attrs)] @@ -35,23 +29,18 @@ pub fn main() { asm!(".intel_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive - //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".intel_syntax aaa noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive - //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".att_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.att_syntax` //[arm]~^^ ERROR unknown directive - //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".att_syntax bbb noprefix", "nop"); //[x86_64]~^ WARN avoid using `.att_syntax` //[arm]~^^ ERROR unknown directive - //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".intel_syntax noprefix; nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive - //[arm_llvm_18]~^^^ ERROR unknown directive asm!( r" @@ -60,7 +49,6 @@ pub fn main() { ); //[x86_64]~^^^ WARN avoid using `.intel_syntax` //[arm]~^^^^ ERROR unknown directive - //[arm_llvm_18]~^^^^^ ERROR unknown directive } } diff --git a/tests/ui/asm/inline-syntax.x86_64.stderr b/tests/ui/asm/inline-syntax.x86_64.stderr index 66dc37f3089e1..59c95194322aa 100644 --- a/tests/ui/asm/inline-syntax.x86_64.stderr +++ b/tests/ui/asm/inline-syntax.x86_64.stderr @@ -1,5 +1,5 @@ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:67:14 + --> $DIR/inline-syntax.rs:55:14 | LL | global_asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | global_asm!(".intel_syntax noprefix", "nop"); = note: `#[warn(bad_asm_style)]` on by default warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:35:15 + --> $DIR/inline-syntax.rs:29:15 | LL | asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:39:15 + --> $DIR/inline-syntax.rs:32:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - --> $DIR/inline-syntax.rs:43:15 + --> $DIR/inline-syntax.rs:35:15 | LL | asm!(".att_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - --> $DIR/inline-syntax.rs:47:15 + --> $DIR/inline-syntax.rs:38:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:51:15 + --> $DIR/inline-syntax.rs:41:15 | LL | asm!(".intel_syntax noprefix; nop"); | ^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:58:13 + --> $DIR/inline-syntax.rs:47:13 | LL | .intel_syntax noprefix | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/naked-asm-outside-naked-fn.rs b/tests/ui/asm/naked-asm-outside-naked-fn.rs new file mode 100644 index 0000000000000..1696008f3397d --- /dev/null +++ b/tests/ui/asm/naked-asm-outside-naked-fn.rs @@ -0,0 +1,35 @@ +//@ edition: 2021 +//@ needs-asm-support +//@ ignore-nvptx64 +//@ ignore-spirv + +#![feature(naked_functions)] +#![crate_type = "lib"] + +use std::arch::naked_asm; + +fn main() { + test1(); +} + +#[naked] +extern "C" fn test1() { + unsafe { naked_asm!("") } +} + +extern "C" fn test2() { + unsafe { naked_asm!("") } + //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` +} + +extern "C" fn test3() { + unsafe { (|| naked_asm!(""))() } + //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` +} + +fn test4() { + async move { + unsafe { naked_asm!("") } ; + //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` + }; +} diff --git a/tests/ui/asm/naked-asm-outside-naked-fn.stderr b/tests/ui/asm/naked-asm-outside-naked-fn.stderr new file mode 100644 index 0000000000000..6e91359669ca2 --- /dev/null +++ b/tests/ui/asm/naked-asm-outside-naked-fn.stderr @@ -0,0 +1,20 @@ +error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` + --> $DIR/naked-asm-outside-naked-fn.rs:21:14 + | +LL | unsafe { naked_asm!("") } + | ^^^^^^^^^^^^^^ + +error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` + --> $DIR/naked-asm-outside-naked-fn.rs:26:18 + | +LL | unsafe { (|| naked_asm!(""))() } + | ^^^^^^^^^^^^^^ + +error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` + --> $DIR/naked-asm-outside-naked-fn.rs:32:19 + | +LL | unsafe { naked_asm!("") } ; + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index cfb38f2e73848..74049e8ecbc7c 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -2,37 +2,37 @@ #![feature(naked_functions)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::naked_asm; #[naked] pub unsafe extern "C" fn inline_none() { - asm!("", options(noreturn)); + naked_asm!(""); } #[naked] #[inline] //~^ ERROR [E0736] pub unsafe extern "C" fn inline_hint() { - asm!("", options(noreturn)); + naked_asm!(""); } #[naked] #[inline(always)] //~^ ERROR [E0736] pub unsafe extern "C" fn inline_always() { - asm!("", options(noreturn)); + naked_asm!(""); } #[naked] #[inline(never)] //~^ ERROR [E0736] pub unsafe extern "C" fn inline_never() { - asm!("", options(noreturn)); + naked_asm!(""); } #[naked] #[cfg_attr(all(), inline(never))] //~^ ERROR [E0736] pub unsafe extern "C" fn conditional_inline_never() { - asm!("", options(noreturn)); + naked_asm!(""); } diff --git a/tests/ui/asm/x86_64/type-check-2.rs b/tests/ui/asm/x86_64/type-check-2.rs index ff811961462df..1650c595faebb 100644 --- a/tests/ui/asm/x86_64/type-check-2.rs +++ b/tests/ui/asm/x86_64/type-check-2.rs @@ -5,7 +5,7 @@ use std::arch::{asm, global_asm}; #[repr(simd)] -struct SimdNonCopy(f32, f32, f32, f32); +struct SimdNonCopy([f32; 4]); fn main() { unsafe { @@ -29,7 +29,7 @@ fn main() { // Register operands must be Copy - asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + asm!("{}", in(xmm_reg) SimdNonCopy([0.0, 0.0, 0.0, 0.0])); //~^ ERROR arguments for inline assembly must be copyable // Register operands must be integers, floats, SIMD vectors, pointers or diff --git a/tests/ui/asm/x86_64/type-check-2.stderr b/tests/ui/asm/x86_64/type-check-2.stderr index c72e695aefb83..8b1bfa85fa2c4 100644 --- a/tests/ui/asm/x86_64/type-check-2.stderr +++ b/tests/ui/asm/x86_64/type-check-2.stderr @@ -1,8 +1,8 @@ error: arguments for inline assembly must be copyable --> $DIR/type-check-2.rs:32:32 | -LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | asm!("{}", in(xmm_reg) SimdNonCopy([0.0, 0.0, 0.0, 0.0])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `SimdNonCopy` does not implement the Copy trait diff --git a/tests/ui/asm/x86_64/type-check-5.rs b/tests/ui/asm/x86_64/type-check-5.rs index b5b51f6116890..81e096a72300a 100644 --- a/tests/ui/asm/x86_64/type-check-5.rs +++ b/tests/ui/asm/x86_64/type-check-5.rs @@ -1,12 +1,9 @@ //@ only-x86_64 -#![feature(repr_simd, never_type)] +#![feature(never_type)] use std::arch::asm; -#[repr(simd)] -struct SimdNonCopy(f32, f32, f32, f32); - fn main() { unsafe { // Inputs must be initialized diff --git a/tests/ui/asm/x86_64/type-check-5.stderr b/tests/ui/asm/x86_64/type-check-5.stderr index 4fb759934636d..377e1d19f6c5c 100644 --- a/tests/ui/asm/x86_64/type-check-5.stderr +++ b/tests/ui/asm/x86_64/type-check-5.stderr @@ -1,5 +1,5 @@ error[E0381]: used binding `x` isn't initialized - --> $DIR/type-check-5.rs:15:28 + --> $DIR/type-check-5.rs:12:28 | LL | let x: u64; | - binding declared here but left uninitialized @@ -12,7 +12,7 @@ LL | let x: u64 = 42; | ++++ error[E0381]: used binding `y` isn't initialized - --> $DIR/type-check-5.rs:18:9 + --> $DIR/type-check-5.rs:15:9 | LL | let mut y: u64; | ----- binding declared here but left uninitialized @@ -25,7 +25,7 @@ LL | let mut y: u64 = 42; | ++++ error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/type-check-5.rs:24:13 + --> $DIR/type-check-5.rs:21:13 | LL | let v: Vec = vec![0, 1, 2]; | ^ not mutable diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs index e2fc2961a448d..a33d4928f0145 100644 --- a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs @@ -7,4 +7,5 @@ impl Fail { fn main() { Fail::<()>::C + //~^ ERROR no associated item named `C` found for struct `Fail<()>` in the current scope } diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr index f0a6ccf243a9e..c581639310711 100644 --- a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr @@ -7,6 +7,19 @@ LL | struct Fail; = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error: aborting due to 1 previous error +error[E0599]: no associated item named `C` found for struct `Fail<()>` in the current scope + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg.rs:9:17 + | +LL | struct Fail; + | -------------- associated item `C` not found for this struct +... +LL | Fail::<()>::C + | ^ associated item not found in `Fail<()>` + | + = note: the associated item was found for + - `Fail` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0392`. +Some errors have detailed explanations: E0392, E0599. +For more information about an error, try `rustc --explain E0392`. diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs index cb53d902ba18a..d891b7bd62b4a 100644 --- a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs @@ -14,4 +14,5 @@ impl Fail { fn main() { Fail::::C //~^ ERROR: type mismatch + //~| ERROR no associated item named `C` found for struct `Fail` in the current scope } diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr index 0d63b7f5b2934..18d458aea809b 100644 --- a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr @@ -1,3 +1,15 @@ +error[E0599]: no associated item named `C` found for struct `Fail` in the current scope + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:23 + | +LL | struct Fail, U>(T); + | ---------------------------------- associated item `C` not found for this struct +... +LL | Fail::::C + | ^ associated item not found in `Fail` + | + = note: the associated item was found for + - `Fail` + error[E0271]: type mismatch resolving `::Assoc == u32` --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:5 | @@ -15,6 +27,7 @@ note: required by a bound in `Fail` LL | struct Fail, U>(T); | ^^^^^^^^^ required by this bound in `Fail` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +Some errors have detailed explanations: E0271, E0599. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.rs b/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.rs new file mode 100644 index 0000000000000..eb616631d1dc8 --- /dev/null +++ b/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.rs @@ -0,0 +1,28 @@ +// Demonstrates a mostly-theoretical inference guidance now that we turn the where +// clause on `Trait` into an item bound, given that we prefer item bounds somewhat +// greedily in trait selection. + +trait Bound {} +impl Bound for U {} + +trait Trait +where + <::Assoc as Other>::Assoc: Bound, +{ + type Assoc: Other; +} + +trait Other { + type Assoc; +} + +fn impls_trait, U>() -> Vec { vec![] } + +fn foo() { + let mut vec_u = impls_trait::<<::Assoc as Other>::Assoc, _>(); + vec_u.sort(); + drop::>(vec_u); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.stderr b/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.stderr new file mode 100644 index 0000000000000..c77400f382280 --- /dev/null +++ b/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/nested-associated-type-bound-incompleteness.rs:24:21 + | +LL | drop::>(vec_u); + | --------------- ^^^^^ expected `Vec`, found `Vec` + | | + | arguments to this function are incorrect + | + = note: expected struct `Vec` + found struct `Vec` +note: function defined here + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-type-bounds/nested-gat-projection.rs b/tests/ui/associated-type-bounds/nested-gat-projection.rs new file mode 100644 index 0000000000000..ad37da9ed1948 --- /dev/null +++ b/tests/ui/associated-type-bounds/nested-gat-projection.rs @@ -0,0 +1,31 @@ +//@ check-pass + +trait Trait +where + for<'a> Self::Gat<'a>: OtherTrait, + for<'a, 'b, 'c> as OtherTrait>::OtherGat<'b>: HigherRanked<'c>, +{ + type Gat<'a>; +} + +trait OtherTrait { + type OtherGat<'b>; +} + +trait HigherRanked<'c> {} + +fn lower_ranked OtherTrait: HigherRanked<'c>>>() {} + +fn higher_ranked() +where + for<'a> T::Gat<'a>: OtherTrait, + for<'a, 'b, 'c> as OtherTrait>::OtherGat<'b>: HigherRanked<'c>, +{ +} + +fn test() { + lower_ranked::>(); + higher_ranked::(); +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index a8c8a85c5aa68..f00aaec1a8c2c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -1,7 +1,6 @@ //@ edition: 2021 #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Trait { async fn method() {} @@ -16,4 +15,22 @@ fn bar (): Send>>() {} fn baz>() {} //~^ ERROR return type notation arguments must be elided with `..` +fn foo_path() where T::method(i32): Send {} +//~^ ERROR argument types not allowed with return type notation + +fn bar_path() where T::method() -> (): Send {} +//~^ ERROR return type not allowed with return type notation + +fn baz_path() where T::method(): Send {} +//~^ ERROR return type notation arguments must be elided with `..` + +fn foo_qualified() where ::method(i32): Send {} +//~^ ERROR expected associated type + +fn bar_qualified() where ::method() -> (): Send {} +//~^ ERROR expected associated type + +fn baz_qualified() where ::method(): Send {} +//~^ ERROR expected associated type + fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index 7e1695984f1c3..c6b9f3eff90ec 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -1,29 +1,57 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-inputs-and-output.rs:3:12 +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:27:36 | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn foo_qualified() where ::method(i32): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:30:36 + | +LL | fn bar_qualified() where ::method() -> (): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:33:36 | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default +LL | fn baz_qualified() where ::method(): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^ not a associated type error: argument types not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:10:23 + --> $DIR/bad-inputs-and-output.rs:9:23 | LL | fn foo>() {} | ^^^^^ help: remove the input types: `()` error: return type not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:13:25 + --> $DIR/bad-inputs-and-output.rs:12:25 | LL | fn bar (): Send>>() {} | ^^^^^^ help: remove the return type error: return type notation arguments must be elided with `..` - --> $DIR/bad-inputs-and-output.rs:16:23 + --> $DIR/bad-inputs-and-output.rs:15:23 | LL | fn baz>() {} | ^^ help: add `..`: `(..)` -error: aborting due to 3 previous errors; 1 warning emitted +error: argument types not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:18:40 + | +LL | fn foo_path() where T::method(i32): Send {} + | ^^^^^ help: remove the input types: `()` + +error: return type not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:21:42 + | +LL | fn bar_path() where T::method() -> (): Send {} + | ^^^^^^ help: remove the return type + +error: return type notation arguments must be elided with `..` + --> $DIR/bad-inputs-and-output.rs:24:40 + | +LL | fn baz_path() where T::method(): Send {} + | ^^ help: add `..`: `(..)` + +error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0575`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs index f507d82afec2f..2bbeb62b922cb 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs @@ -1,5 +1,4 @@ #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Tr { const CONST: usize; @@ -10,17 +9,12 @@ trait Tr { fn foo() where T::method(..): Send, - //~^ ERROR return type notation not allowed in this position yet - //~| ERROR expected type, found function ::method(..): Send, - //~^ ERROR return type notation not allowed in this position yet - //~| ERROR expected associated type, found associated function `Tr::method` { let _ = T::CONST::(..); //~^ ERROR return type notation not allowed in this position yet let _: T::method(..); //~^ ERROR return type notation not allowed in this position yet - //~| ERROR expected type, found function } fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr index cb45de59c7e23..913f84b924c28 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr @@ -1,66 +1,14 @@ -error[E0575]: expected associated type, found associated function `Tr::method` - --> $DIR/bare-path.rs:15:5 - | -LL | ::method(..): Send, - | ^^^^^^^^^^^^^^^^^^^^^ not a associated type - -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bare-path.rs:1:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:19:23 + --> $DIR/bare-path.rs:14:23 | LL | let _ = T::CONST::(..); | ^^^^ error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:21:21 - | -LL | let _: T::method(..); - | ^^^^ - -error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:12:14 - | -LL | T::method(..): Send, - | ^^^^ - -error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:15:22 - | -LL | ::method(..): Send, - | ^^^^ - -error: expected type, found function - --> $DIR/bare-path.rs:12:8 - | -LL | T::method(..): Send, - | ^^^^^^ unexpected function - | -note: the associated function is defined here - --> $DIR/bare-path.rs:7:5 - | -LL | fn method() -> impl Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: expected type, found function - --> $DIR/bare-path.rs:21:15 + --> $DIR/bare-path.rs:16:12 | LL | let _: T::method(..); - | ^^^^^^ unexpected function - | -note: the associated function is defined here - --> $DIR/bare-path.rs:7:5 - | -LL | fn method() -> impl Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0575`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs index be489a19a7ad2..cb5872dff444c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs @@ -3,7 +3,6 @@ //@ [with] check-pass #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Foo { async fn method() -> Result<(), ()>; diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.with.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.with.stderr deleted file mode 100644 index 9d4bb356caa8b..0000000000000 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.with.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/basic.rs:5:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr index e9fd8503296e9..110d2a0058310 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr @@ -1,29 +1,20 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/basic.rs:5:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error: future cannot be sent between threads safely - --> $DIR/basic.rs:23:13 + --> $DIR/basic.rs:22:13 | LL | is_send(foo::()); | ^^^^^^^^^^ future returned by `foo` is not `Send` | = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future> { ::method(..) }`, which is required by `impl Future>: Send` note: future is not `Send` as it awaits another future which is not `Send` - --> $DIR/basic.rs:13:5 + --> $DIR/basic.rs:12:5 | LL | T::method().await?; | ^^^^^^^^^^^ await occurs here on type `impl Future> { ::method(..) }`, which is not `Send` note: required by a bound in `is_send` - --> $DIR/basic.rs:17:20 + --> $DIR/basic.rs:16:20 | LL | fn is_send(_: impl Send) {} | ^^^^ required by this bound in `is_send` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/associated-type-bounds/return-type-notation/display.rs b/tests/ui/associated-type-bounds/return-type-notation/display.rs index c5be2ca00ea1c..2d613b71c55d2 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/display.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/display.rs @@ -1,5 +1,4 @@ #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Trait {} fn needs_trait(_: impl Trait) {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/display.stderr b/tests/ui/associated-type-bounds/return-type-notation/display.stderr index 4915ec1aa8315..b895d79695272 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/display.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/display.stderr @@ -1,14 +1,5 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/display.rs:1:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `impl Sized { ::method(..) }: Trait` is not satisfied - --> $DIR/display.rs:15:17 + --> $DIR/display.rs:14:17 | LL | needs_trait(T::method()); | ----------- ^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized { ::method(..) }` @@ -16,13 +7,13 @@ LL | needs_trait(T::method()); | required by a bound introduced by this call | note: required by a bound in `needs_trait` - --> $DIR/display.rs:5:24 + --> $DIR/display.rs:4:24 | LL | fn needs_trait(_: impl Trait) {} | ^^^^^ required by this bound in `needs_trait` error[E0277]: the trait bound `impl Sized { ::method_with_lt(..) }: Trait` is not satisfied - --> $DIR/display.rs:17:17 + --> $DIR/display.rs:16:17 | LL | needs_trait(T::method_with_lt()); | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized { ::method_with_lt(..) }` @@ -30,13 +21,13 @@ LL | needs_trait(T::method_with_lt()); | required by a bound introduced by this call | note: required by a bound in `needs_trait` - --> $DIR/display.rs:5:24 + --> $DIR/display.rs:4:24 | LL | fn needs_trait(_: impl Trait) {} | ^^^^^ required by this bound in `needs_trait` error[E0277]: the trait bound `impl Sized: Trait` is not satisfied - --> $DIR/display.rs:19:17 + --> $DIR/display.rs:18:17 | LL | needs_trait(T::method_with_ty()); | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized` @@ -44,18 +35,18 @@ LL | needs_trait(T::method_with_ty()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/display.rs:4:1 + --> $DIR/display.rs:3:1 | LL | trait Trait {} | ^^^^^^^^^^^ note: required by a bound in `needs_trait` - --> $DIR/display.rs:5:24 + --> $DIR/display.rs:4:24 | LL | fn needs_trait(_: impl Trait) {} | ^^^^^ required by this bound in `needs_trait` error[E0277]: the trait bound `impl Sized: Trait` is not satisfied - --> $DIR/display.rs:21:17 + --> $DIR/display.rs:20:17 | LL | needs_trait(T::method_with_ct()); | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized` @@ -63,16 +54,16 @@ LL | needs_trait(T::method_with_ct()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/display.rs:4:1 + --> $DIR/display.rs:3:1 | LL | trait Trait {} | ^^^^^^^^^^^ note: required by a bound in `needs_trait` - --> $DIR/display.rs:5:24 + --> $DIR/display.rs:4:24 | LL | fn needs_trait(_: impl Trait) {} | ^^^^^ required by this bound in `needs_trait` -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs index 95c16fa1e3f84..cff0df58b7496 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs @@ -1,7 +1,6 @@ //@ edition: 2021 #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete use std::future::Future; diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr index d76b1bd1c0510..870f17ee70d2e 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr @@ -1,17 +1,8 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/equality.rs:3:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error: return type notation is not allowed to use type equality - --> $DIR/equality.rs:12:18 + --> $DIR/equality.rs:11:18 | LL | fn test>>>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs new file mode 100644 index 0000000000000..c6ae6690c72f5 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs @@ -0,0 +1,51 @@ +//@ check-pass + +#![feature(return_type_notation)] + +trait Trait<'a> { + fn late<'b>(&'b self, _: &'a ()) -> impl Sized; + fn early<'b: 'b>(&'b self, _: &'a ()) -> impl Sized; +} + +#[allow(refining_impl_trait_internal)] +impl<'a> Trait<'a> for () { + fn late<'b>(&'b self, _: &'a ()) -> i32 { 1 } + fn early<'b: 'b>(&'b self, _: &'a ()) -> i32 { 1 } +} + +trait Other<'c> {} +impl Other<'_> for i32 {} + +fn test(t: &T) +where + T: for<'a, 'c> Trait<'a, late(..): Other<'c>>, + // which is basically: + // for<'a, 'c> Trait<'a, for<'b> method<'b>: Other<'c>>, + T: for<'a, 'c> Trait<'a, early(..): Other<'c>>, + // which is basically: + // for<'a, 'c> Trait<'a, for<'b> method<'b>: Other<'c>>, +{ + is_other_impl(t.late(&())); + is_other_impl(t.early(&())); +} + +fn test_path(t: &T) +where +T: for<'a> Trait<'a>, + for<'a, 'c> >::late(..): Other<'c>, + // which is basically: + // for<'a, 'b, 'c> >::method::<'b>: Other<'c> + for<'a, 'c> >::early(..): Other<'c>, + // which is basically: + // for<'a, 'b, 'c> >::method::<'b>: Other<'c> +{ + is_other_impl(t.late(&())); + is_other_impl(t.early(&())); +} + +fn is_other_impl(_: impl for<'c> Other<'c>) {} + +fn main() { + test(&()); + test(&()); +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs index 4d026b7d1d859..69d0b4b1f8ac4 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs @@ -1,7 +1,6 @@ //@ edition: 2021 #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait HealthCheck { async fn check() -> bool; diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr index 12f32a75eda32..2abf47f002672 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr @@ -1,14 +1,5 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-120208-higher-ranked-const.rs:3:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error: return type notation is not allowed for functions that have const parameters - --> $DIR/issue-120208-higher-ranked-const.rs:12:21 + --> $DIR/issue-120208-higher-ranked-const.rs:11:21 | LL | async fn check() -> bool; | -------------- const parameter declared here @@ -16,5 +7,5 @@ LL | async fn check() -> bool; LL | HC: HealthCheck + Send + 'static, | ^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.rs b/tests/ui/associated-type-bounds/return-type-notation/missing.rs index 3a04a56339ba5..e116ae0ca3bb4 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.rs @@ -1,7 +1,6 @@ //@ edition: 2021 #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Trait { async fn method() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr index 5cb8e2642f51c..0eb965603439c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr @@ -1,18 +1,9 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/missing.rs:3:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0220]: associated function `methid` not found for `Trait` - --> $DIR/missing.rs:10:17 + --> $DIR/missing.rs:9:17 | LL | fn bar>() {} | ^^^^^^ help: there is an associated function with a similar name: `method` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs new file mode 100644 index 0000000000000..8dfc2376fbd4e --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs @@ -0,0 +1,41 @@ +//@ check-pass + +#![allow(non_camel_case_types)] +#![feature(return_type_notation)] + +trait Foo { + type test; + + fn test() -> impl Bar; +} + +fn call_path() +where + T::test(..): Bar, +{ +} + +fn call_bound>() {} + +trait Bar {} +struct NotBar; +struct YesBar; +impl Bar for YesBar {} + +impl Foo for () { + type test = NotBar; + + // Use refinement here so we can observe `YesBar: Bar`. + #[allow(refining_impl_trait_internal)] + fn test() -> YesBar { + YesBar + } +} + +fn main() { + // If `T::test(..)` resolved to the GAT (erroneously), then this would be + // an error since `<() as Foo>::bar` -- the associated type -- does not + // implement `Bar`, but the return type of the method does. + call_path::<()>(); + call_bound::<()>(); +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs index d283c6eab370d..0e9dd90095286 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs @@ -1,11 +1,13 @@ #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Trait { fn method() {} } -fn test>() {} -//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` +fn bound>() {} +//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` + +fn path() where T: Trait, T::method(..): Send {} +//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr index 79ced3c96ed5c..4d3dac2d168f7 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr @@ -1,22 +1,24 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/non-rpitit.rs:1:12 +error: return type notation used on function that is not `async` and does not return `impl Trait` + --> $DIR/non-rpitit.rs:7:19 | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn method() {} + | ----------- this function must be `async` or return `impl Trait` +... +LL | fn bound>() {} + | ^^^^^^^^^^^^^^^^ | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default + = note: function returns `()`, which is not compatible with associated type return bounds error: return type notation used on function that is not `async` and does not return `impl Trait` - --> $DIR/non-rpitit.rs:8:18 + --> $DIR/non-rpitit.rs:10:30 | LL | fn method() {} | ----------- this function must be `async` or return `impl Trait` ... -LL | fn test>() {} - | ^^^^^^^^^^^^^^^^ +LL | fn path() where T: Trait, T::method(..): Send {} + | ^^^^^^^^^^^^^ | = note: function returns `()`, which is not compatible with associated type return bounds -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs new file mode 100644 index 0000000000000..89a414a3bc863 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs @@ -0,0 +1,41 @@ +#![feature(return_type_notation)] + +fn function() {} + +fn not_a_method() +where + function(..): Send, + //~^ ERROR expected function, found function `function` + //~| ERROR return type notation not allowed in this position yet +{ +} + +fn not_a_method_and_typoed() +where + function(): Send, + //~^ ERROR expected type, found function `function` +{ +} + +trait Tr { + fn method(); +} + +// Forgot the `T::` +fn maybe_method_overlaps() +where + method(..): Send, + //~^ ERROR cannot find function `method` in this scope + //~| ERROR return type notation not allowed in this position yet +{ +} + +// Forgot the `T::`, AND typoed `(..)` to `()` +fn maybe_method_overlaps_and_typoed() +where + method(): Send, + //~^ ERROR cannot find type `method` in this scope +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr new file mode 100644 index 0000000000000..ab987ee48e6c8 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr @@ -0,0 +1,40 @@ +error[E0575]: expected function, found function `function` + --> $DIR/not-a-method.rs:7:5 + | +LL | function(..): Send, + | ^^^^^^^^^^^^ not a function + +error[E0573]: expected type, found function `function` + --> $DIR/not-a-method.rs:15:5 + | +LL | function(): Send, + | ^^^^^^^^^^ not a type + +error[E0576]: cannot find function `method` in this scope + --> $DIR/not-a-method.rs:27:5 + | +LL | method(..): Send, + | ^^^^^^ not found in this scope + +error[E0412]: cannot find type `method` in this scope + --> $DIR/not-a-method.rs:36:5 + | +LL | method(): Send, + | ^^^^^^ not found in this scope + +error: return type notation not allowed in this position yet + --> $DIR/not-a-method.rs:7:5 + | +LL | function(..): Send, + | ^^^^^^^^^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/not-a-method.rs:27:5 + | +LL | method(..): Send, + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0412, E0573, E0575, E0576. +For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.rs b/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.rs new file mode 100644 index 0000000000000..f9aba1754653a --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.rs @@ -0,0 +1,26 @@ +#![feature(return_type_notation)] + +trait A { + fn method() -> impl Sized; +} +trait B { + fn method() -> impl Sized; +} + +fn ambiguous() +where + T::method(..): Send, + //~^ ERROR ambiguous associated function `method` in bounds of `T` +{ +} + +trait Sub: A + B {} + +fn ambiguous_via_supertrait() +where + T::method(..): Send, + //~^ ERROR ambiguous associated function `method` in bounds of `T` +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.stderr new file mode 100644 index 0000000000000..80705424035ce --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.stderr @@ -0,0 +1,45 @@ +error[E0221]: ambiguous associated function `method` in bounds of `T` + --> $DIR/path-ambiguous.rs:12:5 + | +LL | fn method() -> impl Sized; + | -------------------------- ambiguous `method` from `A` +... +LL | fn method() -> impl Sized; + | -------------------------- ambiguous `method` from `B` +... +LL | T::method(..): Send, + | ^^^^^^^^^^^^^ ambiguous associated function `method` + | +help: use fully-qualified syntax to disambiguate + | +LL | ::method(..): Send, + | ~~~~~~~~~~ +help: use fully-qualified syntax to disambiguate + | +LL | ::method(..): Send, + | ~~~~~~~~~~ + +error[E0221]: ambiguous associated function `method` in bounds of `T` + --> $DIR/path-ambiguous.rs:21:5 + | +LL | fn method() -> impl Sized; + | -------------------------- ambiguous `method` from `A` +... +LL | fn method() -> impl Sized; + | -------------------------- ambiguous `method` from `B` +... +LL | T::method(..): Send, + | ^^^^^^^^^^^^^ ambiguous associated function `method` + | +help: use fully-qualified syntax to disambiguate + | +LL | ::method(..): Send, + | ~~~~~~~~~~ +help: use fully-qualified syntax to disambiguate + | +LL | ::method(..): Send, + | ~~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0221`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs b/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs new file mode 100644 index 0000000000000..d8bdec0910752 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs @@ -0,0 +1,23 @@ +//@ check-pass + +#![feature(return_type_notation)] + +trait Trait { + fn method() -> impl Sized; +} + +fn is_send(_: impl Send) {} + +struct W(T); + +impl W { + fn test() + where + T: Trait, + T::method(..): Send, + { + is_send(T::method()); + } +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.rs b/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.rs new file mode 100644 index 0000000000000..8591357dd9eaa --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.rs @@ -0,0 +1,24 @@ +#![feature(return_type_notation)] + +trait A<'a> { + fn method() -> impl Sized; +} +trait B: for<'a> A<'a> {} + +fn higher_ranked() +where + T: for<'a> A<'a>, + T::method(..): Send, + //~^ ERROR cannot use the associated function of a trait with uninferred generic parameters +{ +} + +fn higher_ranked_via_supertrait() +where + T: B, + T::method(..): Send, + //~^ ERROR cannot use the associated function of a trait with uninferred generic parameters +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.stderr new file mode 100644 index 0000000000000..2a9a1a1e8994c --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.stderr @@ -0,0 +1,25 @@ +error[E0212]: cannot use the associated function of a trait with uninferred generic parameters + --> $DIR/path-higher-ranked.rs:11:5 + | +LL | T::method(..): Send, + | ^^^^^^^^^^^^^ + | +help: use a fully qualified path with inferred lifetimes + | +LL | >::method(..): Send, + | ~~~~~~~~~~~~~~ + +error[E0212]: cannot use the associated function of a trait with uninferred generic parameters + --> $DIR/path-higher-ranked.rs:19:5 + | +LL | T::method(..): Send, + | ^^^^^^^^^^^^^ + | +help: use a fully qualified path with inferred lifetimes + | +LL | >::method(..): Send, + | ~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0212`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs b/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs new file mode 100644 index 0000000000000..8cab48bd0c454 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs @@ -0,0 +1,24 @@ +#![feature(return_type_notation)] + +trait A { + #[allow(non_camel_case_types)] + type bad; +} + +fn fully_qualified() +where + ::method(..): Send, + //~^ ERROR cannot find method or associated constant `method` in trait `A` + ::bad(..): Send, + //~^ ERROR expected method or associated constant, found associated type `A::bad` +{ +} + +fn type_dependent() +where + T::method(..): Send, + //~^ associated function `method` not found for `T` +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr new file mode 100644 index 0000000000000..edac09db89dae --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr @@ -0,0 +1,24 @@ +error[E0576]: cannot find method or associated constant `method` in trait `A` + --> $DIR/path-missing.rs:10:15 + | +LL | ::method(..): Send, + | ^^^^^^ not found in `A` + +error[E0575]: expected method or associated constant, found associated type `A::bad` + --> $DIR/path-missing.rs:12:5 + | +LL | ::bad(..): Send, + | ^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0220]: associated function `method` not found for `T` + --> $DIR/path-missing.rs:19:8 + | +LL | T::method(..): Send, + | ^^^^^^ associated function `method` not found + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0575, E0576. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.rs b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.rs new file mode 100644 index 0000000000000..17a3d0f7af675 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.rs @@ -0,0 +1,14 @@ +#![feature(return_type_notation)] + +trait Trait { + fn method() -> impl Sized; +} + +fn test() +where + Trait::method(..): Send, + //~^ ERROR ambiguous associated type +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr new file mode 100644 index 0000000000000..6dbb5dabc0e43 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr @@ -0,0 +1,14 @@ +error[E0223]: ambiguous associated type + --> $DIR/path-no-qself.rs:9:5 + | +LL | Trait::method(..): Send, + | ^^^^^^^^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL | ::method: Send, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.rs b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.rs new file mode 100644 index 0000000000000..8107772f151ef --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.rs @@ -0,0 +1,20 @@ +#![feature(return_type_notation)] + +trait Trait { + fn method() -> impl Sized; +} + +struct Adt; + +fn non_param_qself() +where + <()>::method(..): Send, + //~^ ERROR ambiguous associated function + i32::method(..): Send, + //~^ ERROR ambiguous associated function + Adt::method(..): Send, + //~^ ERROR ambiguous associated function +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr new file mode 100644 index 0000000000000..38202bdbf0727 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr @@ -0,0 +1,21 @@ +error[E0223]: ambiguous associated function + --> $DIR/path-non-param-qself.rs:11:5 + | +LL | <()>::method(..): Send, + | ^^^^^^^^^^^^^^^^ + +error[E0223]: ambiguous associated function + --> $DIR/path-non-param-qself.rs:13:5 + | +LL | i32::method(..): Send, + | ^^^^^^^^^^^^^^^ + +error[E0223]: ambiguous associated function + --> $DIR/path-non-param-qself.rs:15:5 + | +LL | Adt::method(..): Send, + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs b/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs new file mode 100644 index 0000000000000..d805556f4c720 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs @@ -0,0 +1,26 @@ +//@ check-pass + +#![feature(return_type_notation)] + +trait Foo { + fn method() -> impl Sized; +} + +trait Bar: Foo { + fn other() + where + Self::method(..): Send; +} + +fn is_send(_: impl Send) {} + +impl Bar for T { + fn other() + where + Self::method(..): Send, + { + is_send(Self::method()); + } +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-type-param.rs b/tests/ui/associated-type-bounds/return-type-notation/path-type-param.rs new file mode 100644 index 0000000000000..6e2355c389b88 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-type-param.rs @@ -0,0 +1,21 @@ +#![feature(return_type_notation)] + +trait Foo { + fn method() -> impl Sized; +} + +fn test() +where + ::method(..): Send, + //~^ ERROR return type notation is not allowed for functions that have type parameters +{ +} + +fn test_type_dependent() +where + ::method(..): Send, + //~^ ERROR return type notation is not allowed for functions that have type parameters +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-type-param.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-type-param.stderr new file mode 100644 index 0000000000000..67e83060a76b2 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-type-param.stderr @@ -0,0 +1,20 @@ +error: return type notation is not allowed for functions that have type parameters + --> $DIR/path-type-param.rs:9:5 + | +LL | fn method() -> impl Sized; + | - type parameter declared here +... +LL | ::method(..): Send, + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: return type notation is not allowed for functions that have type parameters + --> $DIR/path-type-param.rs:16:5 + | +LL | fn method() -> impl Sized; + | - type parameter declared here +... +LL | ::method(..): Send, + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.rs b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.rs new file mode 100644 index 0000000000000..c9cb0f953e26b --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.rs @@ -0,0 +1,24 @@ +#![feature(return_type_notation)] + +trait Trait { + fn method() -> impl Sized; +} + +struct DoesntWork; +impl Trait for DoesntWork { + fn method() -> impl Sized { + std::ptr::null_mut::<()>() + // This isn't `Send`. + } +} + +fn test() +where + T::method(..): Send, +{ +} + +fn main() { + test::(); + //~^ ERROR `*mut ()` cannot be sent between threads safely +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr new file mode 100644 index 0000000000000..95810342d5ae2 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr @@ -0,0 +1,27 @@ +error[E0277]: `*mut ()` cannot be sent between threads safely + --> $DIR/path-unsatisfied.rs:22:12 + | +LL | fn method() -> impl Sized { + | ---------- within this `impl Sized` +... +LL | test::(); + | ^^^^^^^^^^ `*mut ()` cannot be sent between threads safely + | + = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`, which is required by `impl Sized: Send` +note: required because it appears within the type `impl Sized` + --> $DIR/path-unsatisfied.rs:9:20 + | +LL | fn method() -> impl Sized { + | ^^^^^^^^^^ +note: required by a bound in `test` + --> $DIR/path-unsatisfied.rs:17:20 + | +LL | fn test() + | ---- required by a bound in this function +LL | where +LL | T::method(..): Send, + | ^^^^ required by this bound in `test` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-works.rs b/tests/ui/associated-type-bounds/return-type-notation/path-works.rs new file mode 100644 index 0000000000000..87abfc07ee9f2 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-works.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(return_type_notation)] + +trait Trait { + fn method() -> impl Sized; +} + +struct Works; +impl Trait for Works { + fn method() -> impl Sized {} +} + +fn test() +where + T::method(..): Send, +{ +} + +fn main() { + test::(); +} diff --git a/tests/ui/associated-types/imply-relevant-nested-item-bounds-2.rs b/tests/ui/associated-types/imply-relevant-nested-item-bounds-2.rs new file mode 100644 index 0000000000000..864c31893504f --- /dev/null +++ b/tests/ui/associated-types/imply-relevant-nested-item-bounds-2.rs @@ -0,0 +1,28 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait Trait +where + Self::Assoc: Clone, +{ + type Assoc; +} + +fn foo(x: &T::Assoc) -> T::Assoc { + x.clone() +} + +trait Trait2 +where + Self::Assoc: Iterator, + ::Item: Clone, +{ + type Assoc; +} + +fn foo2(x: &::Item) -> ::Item { + x.clone() +} + +fn main() {} diff --git a/tests/ui/associated-types/imply-relevant-nested-item-bounds-for-gat.rs b/tests/ui/associated-types/imply-relevant-nested-item-bounds-for-gat.rs new file mode 100644 index 0000000000000..4e3b0b3b148a3 --- /dev/null +++ b/tests/ui/associated-types/imply-relevant-nested-item-bounds-for-gat.rs @@ -0,0 +1,19 @@ +//@ check-pass + +// Test that `for<'a> Self::Gat<'a>: Debug` is implied in the definition of `Foo`, +// just as it would be if it weren't a GAT but just a regular associated type. + +use std::fmt::Debug; + +trait Foo +where + for<'a> Self::Gat<'a>: Debug, +{ + type Gat<'a>; +} + +fn test(x: T::Gat<'static>) { + println!("{:?}", x); +} + +fn main() {} diff --git a/tests/ui/associated-types/imply-relevant-nested-item-bounds.rs b/tests/ui/associated-types/imply-relevant-nested-item-bounds.rs new file mode 100644 index 0000000000000..5a477a5b34941 --- /dev/null +++ b/tests/ui/associated-types/imply-relevant-nested-item-bounds.rs @@ -0,0 +1,23 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait Foo +where + Self::Iterator: Iterator, + ::Item: Bar, +{ + type Iterator; + + fn iter() -> Self::Iterator; +} + +trait Bar { + fn bar(&self); +} + +fn x() { + T::iter().next().unwrap().bar(); +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/body-check-on-non-fnmut.rs b/tests/ui/async-await/async-closures/body-check-on-non-fnmut.rs new file mode 100644 index 0000000000000..4382a689e7564 --- /dev/null +++ b/tests/ui/async-await/async-closures/body-check-on-non-fnmut.rs @@ -0,0 +1,20 @@ +//@ aux-build:block-on.rs +//@ edition:2021 +//@ build-pass + +#![feature(async_closure)] + +extern crate block_on; + +// Make sure that we don't call `coroutine_by_move_body_def_id` query +// on async closures that are `FnOnce`. See issue: #130167. + +async fn empty() {} + +pub async fn call_once(f: F) { + f().await; +} + +fn main() { + block_on::block_on(call_once(async || empty().await)); +} diff --git a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs new file mode 100644 index 0000000000000..4cbbefb0f5298 --- /dev/null +++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Zvalidate-mir --edition=2018 --crate-type=lib -Copt-level=3 + +#![feature(async_closure)] + +fn main() {} + +fn needs_fn_mut(mut x: impl FnMut() -> T) { + x(); +} + +fn hello(x: Ty) { + needs_fn_mut(async || { + //~^ ERROR cannot move out of `x` + x.hello(); + }); +} + +struct Ty; +impl Ty { + fn hello(self) {} +} diff --git a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr new file mode 100644 index 0000000000000..bab26c1948217 --- /dev/null +++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr @@ -0,0 +1,24 @@ +error[E0507]: cannot move out of `x` which is behind a mutable reference + --> $DIR/closure-shim-borrowck-error.rs:12:18 + | +LL | needs_fn_mut(async || { + | ^^^^^^^^ `x` is moved here +LL | +LL | x.hello(); + | - + | | + | variable moved due to use in coroutine + | move occurs because `x` has type `Ty`, which does not implement the `Copy` trait + | +note: if `Ty` implemented `Clone`, you could clone the value + --> $DIR/closure-shim-borrowck-error.rs:18:1 + | +LL | x.hello(); + | - you could clone this value +... +LL | struct Ty; + | ^^^^^^^^^ consider implementing `Clone` for this type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/async-await/async-closures/debuginfo-by-move-body.rs b/tests/ui/async-await/async-closures/debuginfo-by-move-body.rs new file mode 100644 index 0000000000000..6f339f0c8ef12 --- /dev/null +++ b/tests/ui/async-await/async-closures/debuginfo-by-move-body.rs @@ -0,0 +1,19 @@ +//@ aux-build:block-on.rs +//@ edition: 2021 +//@ build-pass +//@ compile-flags: -Cdebuginfo=2 + +#![feature(async_closure)] + +extern crate block_on; + +async fn call_once(f: impl async FnOnce()) { + f().await; +} + +pub fn main() { + block_on::block_on(async { + let async_closure = async move || {}; + call_once(async_closure).await; + }); +} diff --git a/tests/ui/async-await/async-closures/foreign.rs b/tests/ui/async-await/async-closures/foreign.rs index 50bef9cf11d5f..ab6fe06a3f4bd 100644 --- a/tests/ui/async-await/async-closures/foreign.rs +++ b/tests/ui/async-await/async-closures/foreign.rs @@ -12,8 +12,13 @@ extern crate foreign; struct NoCopy; +async fn call_once(f: impl async FnOnce()) { + f().await; +} + fn main() { block_on::block_on(async { foreign::closure()().await; + call_once(foreign::closure()).await; }); } diff --git a/tests/ui/async-await/async-closures/inline-body.rs b/tests/ui/async-await/async-closures/inline-body.rs new file mode 100644 index 0000000000000..a842d98d1de4c --- /dev/null +++ b/tests/ui/async-await/async-closures/inline-body.rs @@ -0,0 +1,34 @@ +//@ edition: 2021 +//@ compile-flags: -Zinline-mir +//@ build-pass + +// Ensure that we don't hit a Steal ICE because we forgot to ensure +// `mir_inliner_callees` for the synthetic by-move coroutine body since +// its def-id wasn't previously being considered. + +#![feature(async_closure, noop_waker)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match fut.as_mut().poll(ctx) { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} + +async fn call_once(f: impl async FnOnce() -> T) -> T { + f().await +} + +fn main() { + let c = async || {}; + block_on(call_once(c)); +} diff --git a/tests/ui/async-await/async-closures/mac-body.rs b/tests/ui/async-await/async-closures/mac-body.rs new file mode 100644 index 0000000000000..a416227c3904f --- /dev/null +++ b/tests/ui/async-await/async-closures/mac-body.rs @@ -0,0 +1,12 @@ +//@ edition: 2021 +//@ check-pass + +#![feature(async_closure)] + +// Make sure we don't ICE if an async closure has a macro body. +// This happened because we were calling walk instead of visit +// in the def collector, oops! + +fn main() { + let _ = async || println!(); +} diff --git a/tests/ui/async-await/async-closures/tainted-body-2.rs b/tests/ui/async-await/async-closures/tainted-body-2.rs new file mode 100644 index 0000000000000..73c6bdc30a02f --- /dev/null +++ b/tests/ui/async-await/async-closures/tainted-body-2.rs @@ -0,0 +1,18 @@ +//@ edition: 2021 + +#![feature(async_closure)] + +// Ensure that building a by-ref async closure body doesn't ICE when the parent +// body is tainted. + +fn main() { + missing; + //~^ ERROR cannot find value `missing` in this scope + + // We don't do numerical inference fallback when the body is tainted. + // This leads to writeback folding the type of the coroutine-closure + // into an error type, since its signature contains that numerical + // infer var. + let c = async |_| {}; + c(1); +} diff --git a/tests/ui/async-await/async-closures/tainted-body-2.stderr b/tests/ui/async-await/async-closures/tainted-body-2.stderr new file mode 100644 index 0000000000000..798d47064d990 --- /dev/null +++ b/tests/ui/async-await/async-closures/tainted-body-2.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `missing` in this scope + --> $DIR/tainted-body-2.rs:9:5 + | +LL | missing; + | ^^^^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/async-await/async-closures/validate-synthetic-body.rs b/tests/ui/async-await/async-closures/validate-synthetic-body.rs new file mode 100644 index 0000000000000..67e683ac08a22 --- /dev/null +++ b/tests/ui/async-await/async-closures/validate-synthetic-body.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ edition: 2021 + +#![feature(async_closure)] + +// Make sure that we don't hit a query cycle when validating +// the by-move coroutine body for an async closure. + +use std::future::Future; + +async fn test(operation: impl Fn() -> Fut) { + operation().await; +} + +pub async fn orchestrate_simple_crud() { + test(async || async {}.await).await; +} + +fn main() {} diff --git a/tests/ui/async-await/async-drop.rs b/tests/ui/async-await/async-drop.rs index 12f120a0b1216..4e60598661faf 100644 --- a/tests/ui/async-await/async-drop.rs +++ b/tests/ui/async-await/async-drop.rs @@ -53,18 +53,20 @@ fn main() { let i = 13; let fut = pin!(async { test_async_drop(Int(0), 0).await; - test_async_drop(AsyncInt(0), 104).await; - test_async_drop([AsyncInt(1), AsyncInt(2)], 152).await; - test_async_drop((AsyncInt(3), AsyncInt(4)), 488).await; + // FIXME(#63818): niches in coroutines are disabled. + // Some of these sizes should be smaller, as indicated in comments. + test_async_drop(AsyncInt(0), /*104*/ 112).await; + test_async_drop([AsyncInt(1), AsyncInt(2)], /*152*/ 168).await; + test_async_drop((AsyncInt(3), AsyncInt(4)), /*488*/ 528).await; test_async_drop(5, 0).await; let j = 42; test_async_drop(&i, 0).await; test_async_drop(&j, 0).await; - test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }, 1688).await; + test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }, /*1688*/ 1792).await; test_async_drop(ManuallyDrop::new(AsyncInt(9)), 0).await; let foo = AsyncInt(10); - test_async_drop(AsyncReference { foo: &foo }, 104).await; + test_async_drop(AsyncReference { foo: &foo }, /*104*/ 112).await; let foo = AsyncInt(11); test_async_drop( @@ -73,17 +75,17 @@ fn main() { let foo = AsyncInt(10); foo }, - 120, + /*120*/ 136, ) .await; - test_async_drop(AsyncEnum::A(AsyncInt(12)), 680).await; - test_async_drop(AsyncEnum::B(SyncInt(13)), 680).await; + test_async_drop(AsyncEnum::A(AsyncInt(12)), /*680*/ 736).await; + test_async_drop(AsyncEnum::B(SyncInt(13)), /*680*/ 736).await; - test_async_drop(SyncInt(14), 16).await; + test_async_drop(SyncInt(14), /*16*/ 24).await; test_async_drop( SyncThenAsync { i: 15, a: AsyncInt(16), b: SyncInt(17), c: AsyncInt(18) }, - 3064, + /*3064*/ 3296, ) .await; @@ -99,11 +101,11 @@ fn main() { black_box(core::future::ready(())).await; foo }, - 120, + /*120*/ 136, ) .await; - test_async_drop(AsyncUnion { signed: 21 }, 32).await; + test_async_drop(AsyncUnion { signed: 21 }, /*32*/ 40).await; }); let res = fut.poll(&mut cx); assert_eq!(res, Poll::Ready(())); diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout index def967ba195ef..642e27b2a57d6 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout @@ -14,28 +14,26 @@ print-type-size field `.value`: 3077 bytes print-type-size type: `{async fn body of calls_fut<{async fn body of big_fut()}>()}`: 3077 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1025 bytes -print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size upvar `.fut`: 1025 bytes print-type-size variant `Suspend0`: 2052 bytes -print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes -print-type-size padding: 1 bytes -print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes +print-type-size upvar `.fut`: 1025 bytes +print-type-size local `.fut`: 1025 bytes print-type-size local `..coroutine_field4`: 1 bytes, type: bool print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()} print-type-size variant `Suspend1`: 3076 bytes -print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes -print-type-size padding: 1026 bytes +print-type-size upvar `.fut`: 1025 bytes +print-type-size padding: 1025 bytes print-type-size local `..coroutine_field4`: 1 bytes, alignment: 1 bytes, type: bool print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body of big_fut()} print-type-size variant `Suspend2`: 2052 bytes -print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes -print-type-size padding: 1 bytes -print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes +print-type-size upvar `.fut`: 1025 bytes +print-type-size local `.fut`: 1025 bytes print-type-size local `..coroutine_field4`: 1 bytes, type: bool print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()} print-type-size variant `Returned`: 1025 bytes -print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size upvar `.fut`: 1025 bytes print-type-size variant `Panicked`: 1025 bytes -print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size upvar `.fut`: 1025 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes diff --git a/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs b/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs index 51e85931dbf20..547c7414526c2 100644 --- a/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs +++ b/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs @@ -2,6 +2,8 @@ //@ edition:2018 #![feature(if_let_guard)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; diff --git a/tests/ui/async-await/pin-reborrow-arg.rs b/tests/ui/async-await/pin-reborrow-arg.rs new file mode 100644 index 0000000000000..2008bd1f52dd9 --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-arg.rs @@ -0,0 +1,36 @@ +//@ check-pass + +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn baz(self: Pin<&mut Self>) { + } +} + +fn foo(_: Pin<&mut Foo>) { +} + +fn foo_const(_: Pin<&Foo>) { +} + +fn bar(x: Pin<&mut Foo>) { + foo(x); + foo(x); // for this to work we need to automatically reborrow, + // as if the user had written `foo(x.as_mut())`. + + Foo::baz(x); + Foo::baz(x); + + foo_const(x); // make sure we can reborrow &mut as &. + + let x: Pin<&Foo> = Pin::new(&Foo); + + foo_const(x); // make sure reborrowing from & to & works. +} + +fn main() {} diff --git a/tests/ui/async-await/pin-reborrow-const-as-mut.rs b/tests/ui/async-await/pin-reborrow-const-as-mut.rs new file mode 100644 index 0000000000000..27c70a7b4dfae --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-const-as-mut.rs @@ -0,0 +1,18 @@ +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// make sure we can't accidentally reborrow Pin<&T> as Pin<&mut T> + +use std::pin::Pin; + +struct Foo; + +fn foo(_: Pin<&mut Foo>) { +} + +fn bar(x: Pin<&Foo>) { + foo(x); //~ ERROR mismatched types + //| ERROR types differ in mutability +} + +fn main() {} diff --git a/tests/ui/async-await/pin-reborrow-const-as-mut.stderr b/tests/ui/async-await/pin-reborrow-const-as-mut.stderr new file mode 100644 index 0000000000000..2c2d9ec271742 --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-const-as-mut.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/pin-reborrow-const-as-mut.rs:14:9 + | +LL | foo(x); + | --- ^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected struct `Pin<&mut Foo>` + found struct `Pin<&Foo>` +note: function defined here + --> $DIR/pin-reborrow-const-as-mut.rs:10:4 + | +LL | fn foo(_: Pin<&mut Foo>) { + | ^^^ ---------------- + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/pin-reborrow-once.rs b/tests/ui/async-await/pin-reborrow-once.rs new file mode 100644 index 0000000000000..241efadef7d57 --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-once.rs @@ -0,0 +1,13 @@ +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// Make sure with pin reborrowing that we can only get one mutable reborrow of a pinned reference. + +use std::pin::{pin, Pin}; + +fn twice(_: Pin<&mut i32>, _: Pin<&mut i32>) {} + +fn main() { + let x = pin!(42); + twice(x, x); //~ ERROR cannot borrow +} diff --git a/tests/ui/async-await/pin-reborrow-once.stderr b/tests/ui/async-await/pin-reborrow-once.stderr new file mode 100644 index 0000000000000..b8fde8ffee898 --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-once.stderr @@ -0,0 +1,12 @@ +error[E0499]: cannot borrow `*x.__pointer` as mutable more than once at a time + --> $DIR/pin-reborrow-once.rs:12:14 + | +LL | twice(x, x); + | ----- - ^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/async-await/pin-reborrow-self.rs b/tests/ui/async-await/pin-reborrow-self.rs new file mode 100644 index 0000000000000..b60b6982bb879 --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-self.rs @@ -0,0 +1,24 @@ +//@ check-pass +//@ignore-test + +// Currently ignored due to self reborrowing not being implemented for Pin + +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn foo(self: Pin<&mut Self>) { + } +} + +fn bar(x: Pin<&mut Foo>) { + x.foo(); + x.foo(); // for this to work we need to automatically reborrow, + // as if the user had written `x.as_mut().foo()`. +} + +fn main() {} diff --git a/tests/ui/async-await/pin-reborrow-shorter.rs b/tests/ui/async-await/pin-reborrow-shorter.rs new file mode 100644 index 0000000000000..06c266e0035fb --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-shorter.rs @@ -0,0 +1,14 @@ +//@check-pass + +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +use std::pin::Pin; + +fn shorter<'b, T: 'b>(_: Pin<&'b mut T>) {} + +fn test<'a: 'b, 'b, T: 'a>(x: Pin<&'a mut T>) { + shorter::<'b>(x); +} + +fn main() {} diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr index acad8bd379170..d6c3bd12aee3b 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr @@ -1,12 +1,3 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-110963-early.rs:4:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error: implementation of `Send` is not general enough --> $DIR/issue-110963-early.rs:14:5 | @@ -36,5 +27,5 @@ LL | | }); = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs index cb9c0b97f1e99..1f56361f5e50f 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs @@ -2,7 +2,6 @@ //@ check-pass #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait HealthCheck { async fn check(&mut self) -> bool; diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.stderr b/tests/ui/async-await/return-type-notation/issue-110963-late.stderr deleted file mode 100644 index 9c6966537a73a..0000000000000 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-110963-late.rs:4:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr deleted file mode 100644 index 4837815fad4ad..0000000000000 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr deleted file mode 100644 index 4837815fad4ad..0000000000000 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs index 24041ed080752..3fbd74eddcbbf 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs @@ -5,7 +5,6 @@ //@ edition:2021 #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Foo { async fn bar(&self); diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs index 2f6e04c385384..fdbeb4f3c8758 100644 --- a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs +++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs @@ -2,7 +2,6 @@ //@ check-pass #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete use std::future::Future; diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr deleted file mode 100644 index 4a52e807bff9e..0000000000000 --- a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/rtn-implied-in-supertrait.rs:4:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs index 1e971d0aea71d..bbdfcf607318b 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs @@ -1,5 +1,4 @@ #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete // Shouldn't ICE when we have a (bad) RTN in an impl header diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr index e061587f49189..2bbf1d504747f 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -1,14 +1,5 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/rtn-in-impl-signature.rs:1:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0229]: associated item constraints are not allowed here - --> $DIR/rtn-in-impl-signature.rs:10:17 + --> $DIR/rtn-in-impl-signature.rs:9:17 | LL | impl Super1<'_, bar(..): Send> for () {} | ^^^^^^^^^^^^^ associated item constraint not allowed here @@ -20,7 +11,7 @@ LL + impl Super1<'_> for () {} | error[E0046]: not all trait items implemented, missing: `bar` - --> $DIR/rtn-in-impl-signature.rs:10:1 + --> $DIR/rtn-in-impl-signature.rs:9:1 | LL | fn bar<'b>() -> bool; | --------------------- `bar` from trait @@ -28,7 +19,7 @@ LL | fn bar<'b>() -> bool; LL | impl Super1<'_, bar(..): Send> for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0046, E0229. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs index 452568f3e4695..1db19628fa37d 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs @@ -1,7 +1,6 @@ //@ edition:2021 #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Super1<'a> { async fn test(); diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr index 9a6fdd7f2ac6b..e32b07771dc92 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr @@ -1,14 +1,5 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-method-bound-ambig.rs:3:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0221]: ambiguous associated function `test` in bounds of `Foo` - --> $DIR/super-method-bound-ambig.rs:25:12 + --> $DIR/super-method-bound-ambig.rs:24:12 | LL | async fn test(); | ---------------- ambiguous `test` from `for<'a> Super1<'a>` @@ -19,6 +10,6 @@ LL | async fn test(); LL | T: Foo, | ^^^^^^^^^^^^^^ ambiguous associated function `test` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0221`. diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.rs b/tests/ui/async-await/return-type-notation/super-method-bound.rs index 1aa8258a09b7d..a1d0307698218 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound.rs @@ -2,7 +2,6 @@ //@ check-pass #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Super<'a> { async fn test(); diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.stderr deleted file mode 100644 index 64fda71c1a1d9..0000000000000 --- a/tests/ui/async-await/return-type-notation/super-method-bound.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-method-bound.rs:4:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.rs b/tests/ui/async-await/return-type-notation/supertrait-bound.rs index 9c74c10b33319..8d73a34ac482f 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.rs +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete and may not be safe to use trait IntFactory { fn stream(&self) -> impl Iterator; diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.stderr deleted file mode 100644 index eb6917fc7d58c..0000000000000 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/supertrait-bound.rs:3:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs index 06a966df4451a..edb92d8e26588 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs @@ -1,7 +1,6 @@ //@ edition: 2021 #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Foo { async fn bar() {} diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr index 1c000bc6c3318..0e43d69bddc68 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr @@ -1,14 +1,5 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/ty-or-ct-params.rs:3:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - error: return type notation is not allowed for functions that have type parameters - --> $DIR/ty-or-ct-params.rs:14:12 + --> $DIR/ty-or-ct-params.rs:13:12 | LL | async fn bar() {} | - type parameter declared here @@ -17,7 +8,7 @@ LL | T: Foo, | ^^^^^^^^^^^^^ error: return type notation is not allowed for functions that have const parameters - --> $DIR/ty-or-ct-params.rs:14:27 + --> $DIR/ty-or-ct-params.rs:13:27 | LL | async fn baz() {} | -------------- const parameter declared here @@ -25,5 +16,5 @@ LL | async fn baz() {} LL | T: Foo, | ^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/issue-105594-invalid-attr-validation.rs b/tests/ui/attributes/issue-105594-invalid-attr-validation.rs index bea5faf7253ff..cb196471fd75e 100644 --- a/tests/ui/attributes/issue-105594-invalid-attr-validation.rs +++ b/tests/ui/attributes/issue-105594-invalid-attr-validation.rs @@ -1,13 +1,7 @@ // This checks that the attribute validation ICE in issue #105594 doesn't // recur. -// -//@ ignore-thumbv8m.base-none-eabi -#![feature(cmse_nonsecure_entry)] fn main() {} #[track_caller] //~ ERROR attribute should be applied to a function static _A: () = (); - -#[cmse_nonsecure_entry] //~ ERROR attribute should be applied to a function -static _B: () = (); //~| ERROR #[cmse_nonsecure_entry]` is only valid for targets diff --git a/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr b/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr index c6b2d6e78138e..1248967c47b19 100644 --- a/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr +++ b/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr @@ -1,26 +1,11 @@ error[E0739]: attribute should be applied to a function definition - --> $DIR/issue-105594-invalid-attr-validation.rs:9:1 + --> $DIR/issue-105594-invalid-attr-validation.rs:6:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ LL | static _A: () = (); | ------------------- not a function definition -error: attribute should be applied to a function definition - --> $DIR/issue-105594-invalid-attr-validation.rs:12:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ -LL | static _B: () = (); - | ------------------- not a function definition - -error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension - --> $DIR/issue-105594-invalid-attr-validation.rs:12:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0739, E0775. -For more information about an error, try `rustc --explain E0739`. +For more information about this error, try `rustc --explain E0739`. diff --git a/tests/ui/binding/order-drop-with-match.rs b/tests/ui/binding/order-drop-with-match.rs index c12c5e4c62779..cd0ff73cf12da 100644 --- a/tests/ui/binding/order-drop-with-match.rs +++ b/tests/ui/binding/order-drop-with-match.rs @@ -5,6 +5,8 @@ // in ORDER matching up to when it ran. // Correct order is: matched, inner, outer +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] static mut ORDER: [usize; 3] = [0, 0, 0]; static mut INDEX: usize = 0; diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index ec17074e3050f..01852fbc63308 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -303,8 +303,8 @@ LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); | = help: the trait `BitAnd` is not implemented for `i32` = help: the following other types implement trait `BitAnd`: - `&'a i32` implements `BitAnd` - `&i32` implements `BitAnd<&i32>` + `&i32` implements `BitAnd` + `&i32` implements `BitAnd` `i32` implements `BitAnd<&i32>` `i32` implements `BitAnd` diff --git a/tests/ui/binop/binop-mul-i32-f32.stderr b/tests/ui/binop/binop-mul-i32-f32.stderr index 33d8fba172ce2..dfb96a078cc6c 100644 --- a/tests/ui/binop/binop-mul-i32-f32.stderr +++ b/tests/ui/binop/binop-mul-i32-f32.stderr @@ -6,8 +6,8 @@ LL | x * y | = help: the trait `Mul` is not implemented for `i32` = help: the following other types implement trait `Mul`: - `&'a i32` implements `Mul` - `&i32` implements `Mul<&i32>` + `&i32` implements `Mul` + `&i32` implements `Mul` `i32` implements `Mul<&i32>` `i32` implements `Mul` diff --git a/tests/ui/binop/shift-various-bad-types.stderr b/tests/ui/binop/shift-various-bad-types.stderr index 7313cb3fb84f3..d7c9eb5f9df32 100644 --- a/tests/ui/binop/shift-various-bad-types.stderr +++ b/tests/ui/binop/shift-various-bad-types.stderr @@ -6,14 +6,14 @@ LL | 22 >> p.char; | = help: the trait `Shr` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` + `&i128` implements `Shr<&i16>` + `&i128` implements `Shr<&i32>` + `&i128` implements `Shr<&i64>` + `&i128` implements `Shr<&i8>` + `&i128` implements `Shr<&isize>` + `&i128` implements `Shr<&u128>` + `&i128` implements `Shr<&u16>` + `&i128` implements `Shr<&u32>` and 568 others error[E0277]: no implementation for `{integer} >> &str` @@ -24,14 +24,14 @@ LL | 22 >> p.str; | = help: the trait `Shr<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` + `&i128` implements `Shr<&i16>` + `&i128` implements `Shr<&i32>` + `&i128` implements `Shr<&i64>` + `&i128` implements `Shr<&i8>` + `&i128` implements `Shr<&isize>` + `&i128` implements `Shr<&u128>` + `&i128` implements `Shr<&u16>` + `&i128` implements `Shr<&u32>` and 568 others error[E0277]: no implementation for `{integer} >> &Panolpy` @@ -42,14 +42,14 @@ LL | 22 >> p; | = help: the trait `Shr<&Panolpy>` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` - `&'a i128` implements `Shr` + `&i128` implements `Shr<&i16>` + `&i128` implements `Shr<&i32>` + `&i128` implements `Shr<&i64>` + `&i128` implements `Shr<&i8>` + `&i128` implements `Shr<&isize>` + `&i128` implements `Shr<&u128>` + `&i128` implements `Shr<&u16>` + `&i128` implements `Shr<&u32>` and 568 others error[E0308]: mismatched types diff --git a/tests/ui/borrowck/alias-liveness/rtn-static.rs b/tests/ui/borrowck/alias-liveness/rtn-static.rs index 6aa5d8fc7a107..5b6cf5b5c7ccc 100644 --- a/tests/ui/borrowck/alias-liveness/rtn-static.rs +++ b/tests/ui/borrowck/alias-liveness/rtn-static.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(return_type_notation)] -//~^ WARN the feature `return_type_notation` is incomplete trait Foo { fn borrow(&mut self) -> impl Sized + '_; diff --git a/tests/ui/borrowck/alias-liveness/rtn-static.stderr b/tests/ui/borrowck/alias-liveness/rtn-static.stderr deleted file mode 100644 index e9202db2c7902..0000000000000 --- a/tests/ui/borrowck/alias-liveness/rtn-static.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/rtn-static.rs:3:12 - | -LL | #![feature(return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #109417 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/borrowck/borrowck-access-permissions.rs b/tests/ui/borrowck/borrowck-access-permissions.rs index be11286a523df..0e9e2bc1354a2 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.rs +++ b/tests/ui/borrowck/borrowck-access-permissions.rs @@ -16,7 +16,6 @@ fn main() { let _y1 = &mut static_x; //~ ERROR [E0596] unsafe { let _y2 = &mut static_x_mut; - //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs] } } diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr index 36e259fa6e8ee..ade10dbbfbdb9 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.stderr +++ b/tests/ui/borrowck/borrowck-access-permissions.stderr @@ -1,18 +1,3 @@ -warning: creating a mutable reference to mutable static is discouraged - --> $DIR/borrowck-access-permissions.rs:18:23 - | -LL | let _y2 = &mut static_x_mut; - | ^^^^^^^^^^^^^^^^^ mutable reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | let _y2 = addr_of_mut!(static_x_mut); - | ~~~~~~~~~~~~~ + - error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-access-permissions.rs:10:19 | @@ -31,7 +16,7 @@ LL | let _y1 = &mut static_x; | ^^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:28:19 + --> $DIR/borrowck-access-permissions.rs:27:19 | LL | let _y1 = &mut *box_x; | ^^^^^^^^^^^ cannot borrow as mutable @@ -42,7 +27,7 @@ LL | let mut box_x = Box::new(1); | +++ error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:37:19 + --> $DIR/borrowck-access-permissions.rs:36:19 | LL | let _y1 = &mut *ref_x; | ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -53,7 +38,7 @@ LL | let ref_x = &mut x; | +++ error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer - --> $DIR/borrowck-access-permissions.rs:47:23 + --> $DIR/borrowck-access-permissions.rs:46:23 | LL | let _y1 = &mut *ptr_x; | ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable @@ -64,7 +49,7 @@ LL | let ptr_x: *const _ = &mut x; | +++ error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:60:18 + --> $DIR/borrowck-access-permissions.rs:59:18 | LL | let _y = &mut *foo_ref.f; | ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -74,6 +59,6 @@ help: consider changing this to be a mutable reference LL | let foo_ref = &mut foo; | +++ -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr index a727c9414c556..e4dfa6d7fba7c 100644 --- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr @@ -4,14 +4,13 @@ warning: creating a mutable reference to mutable static is discouraged LL | let sfoo: *mut Foo = &mut SFOO; | ^^^^^^^^^ mutable reference to mutable static | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior + = note: for more information, see + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of_mut!` instead to create a raw pointer +help: use `&raw mut` instead to create a raw pointer | -LL | let sfoo: *mut Foo = addr_of_mut!(SFOO); - | ~~~~~~~~~~~~~ + +LL | let sfoo: *mut Foo = &raw mut SFOO; + | ~~~~~~~~ warning: 1 warning emitted diff --git a/tests/ui/borrowck/issue-20801.rs b/tests/ui/borrowck/issue-20801.rs index 7e3d3703dc765..c3f136f2876b6 100644 --- a/tests/ui/borrowck/issue-20801.rs +++ b/tests/ui/borrowck/issue-20801.rs @@ -12,7 +12,6 @@ fn imm_ref() -> &'static T { fn mut_ref() -> &'static mut T { unsafe { &mut GLOBAL_MUT_T } - //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs] } fn mut_ptr() -> *mut T { diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index 769b34831c120..5fda92634d8f3 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -1,20 +1,5 @@ -warning: creating a mutable reference to mutable static is discouraged - --> $DIR/issue-20801.rs:14:14 - | -LL | unsafe { &mut GLOBAL_MUT_T } - | ^^^^^^^^^^^^^^^^^ mutable reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | unsafe { addr_of_mut!(GLOBAL_MUT_T) } - | ~~~~~~~~~~~~~ + - error[E0507]: cannot move out of a mutable reference - --> $DIR/issue-20801.rs:27:22 + --> $DIR/issue-20801.rs:26:22 | LL | let a = unsafe { *mut_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -34,7 +19,7 @@ LL + let a = unsafe { mut_ref() }; | error[E0507]: cannot move out of a shared reference - --> $DIR/issue-20801.rs:30:22 + --> $DIR/issue-20801.rs:29:22 | LL | let b = unsafe { *imm_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -54,7 +39,7 @@ LL + let b = unsafe { imm_ref() }; | error[E0507]: cannot move out of a raw pointer - --> $DIR/issue-20801.rs:33:22 + --> $DIR/issue-20801.rs:32:22 | LL | let c = unsafe { *mut_ptr() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -69,7 +54,7 @@ LL | let c = unsafe { *mut_ptr() }; | ---------- you could clone this value error[E0507]: cannot move out of a raw pointer - --> $DIR/issue-20801.rs:36:22 + --> $DIR/issue-20801.rs:35:22 | LL | let d = unsafe { *const_ptr() }; | ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -83,6 +68,6 @@ LL | struct T(u8); LL | let d = unsafe { *const_ptr() }; | ------------ you could clone this value -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs index c3909d0596339..e22bf42e02142 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs @@ -10,7 +10,6 @@ mod borrowck_closures_unique { //~^ ERROR is not declared as mutable unsafe { c1(&mut Y); - //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs] } } } @@ -25,7 +24,6 @@ mod borrowck_closures_unique_grandparent { }; unsafe { c1(&mut Z); - //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs] } } } @@ -62,7 +60,6 @@ fn main() { static mut X: isize = 2; unsafe { borrowck_closures_unique::e(&mut X); - //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs] } mutability_errors::capture_assign_whole((1000,)); diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr index 72fd0d8ce161e..6fc8d3a6c35c7 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr @@ -1,46 +1,3 @@ -warning: creating a mutable reference to mutable static is discouraged - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:12:16 - | -LL | c1(&mut Y); - | ^^^^^^ mutable reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | c1(addr_of_mut!(Y)); - | ~~~~~~~~~~~~~ + - -warning: creating a mutable reference to mutable static is discouraged - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:27:16 - | -LL | c1(&mut Z); - | ^^^^^^ mutable reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | c1(addr_of_mut!(Z)); - | ~~~~~~~~~~~~~ + - -warning: creating a mutable reference to mutable static is discouraged - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:37 - | -LL | borrowck_closures_unique::e(&mut X); - | ^^^^^^ mutable reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | borrowck_closures_unique::e(addr_of_mut!(X)); - | ~~~~~~~~~~~~~ + - error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46 | @@ -53,7 +10,7 @@ LL | pub fn e(mut x: &'static mut isize) { | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:22:50 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:21:50 | LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign @@ -64,7 +21,7 @@ LL | pub fn ee(mut x: &'static mut isize) { | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:37:13 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:35:13 | LL | x = (1,); | ^^^^^^^^ cannot assign @@ -75,7 +32,7 @@ LL | pub fn capture_assign_whole(mut x: (i32,)) { | +++ error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:43:13 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:41:13 | LL | x.0 = 1; | ^^^^^^^ cannot assign @@ -86,7 +43,7 @@ LL | pub fn capture_assign_part(mut x: (i32,)) { | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:49:13 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:13 | LL | &mut x; | ^^^^^^ cannot borrow as mutable @@ -97,7 +54,7 @@ LL | pub fn capture_reborrow_whole(mut x: (i32,)) { | +++ error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:13 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:53:13 | LL | &mut x.0; | ^^^^^^^^ cannot borrow as mutable @@ -107,7 +64,7 @@ help: consider changing this to be mutable LL | pub fn capture_reborrow_part(mut x: (i32,)) { | +++ -error: aborting due to 6 previous errors; 3 warnings emitted +error: aborting due to 6 previous errors Some errors have detailed explanations: E0594, E0596. For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr index b3bf2f924fc3e..89b15a7a659dd 100644 --- a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr +++ b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr @@ -75,7 +75,7 @@ LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); | ^^^^^^^^^^^^^^^^^^-----------------------------------------^ | | | | | | | immutable borrow occurs here - | | cast requires that `reg.sess_mut` is borrowed for `'a` + | | coercion requires that `reg.sess_mut` is borrowed for `'a` | mutable borrow occurs here | = note: due to object lifetime defaults, `Box LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>` @@ -119,7 +119,7 @@ LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); | ^^^^^^^^^^^^^^^^^^-------------------------------------------------^ | | | | | | | first mutable borrow occurs here - | | cast requires that `reg.sess_mut` is borrowed for `'a` + | | coercion requires that `reg.sess_mut` is borrowed for `'a` | second mutable borrow occurs here | = note: due to object lifetime defaults, `Box LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>` diff --git a/tests/ui/cast/casts-differing-anon.stderr b/tests/ui/cast/casts-differing-anon.stderr index 8ddd97137c30d..fc4882d2d2774 100644 --- a/tests/ui/cast/casts-differing-anon.stderr +++ b/tests/ui/cast/casts-differing-anon.stderr @@ -4,7 +4,7 @@ error[E0606]: casting `*mut impl Debug + ?Sized` as `*mut impl Debug + ?Sized` i LL | b_raw = f_raw as *mut _; | ^^^^^^^^^^^^^^^ | - = note: vtable kinds may not match + = note: the pointers may have different metadata error: aborting due to 1 previous error diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.rs b/tests/ui/cast/ptr-to-trait-obj-different-args.rs index c6038cfe86401..bb103f789f55b 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-args.rs +++ b/tests/ui/cast/ptr-to-trait-obj-different-args.rs @@ -18,14 +18,14 @@ fn main() { let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid let x: *const dyn Trait = &(); - let y: *const dyn Trait = x as _; //~ error: mismatched types + let y: *const dyn Trait = x as _; //~ error: casting `*const dyn Trait` as `*const dyn Trait` is invalid _ = (b, y); } fn generic(x: *const dyn Trait, t: *const dyn Trait) { - let _: *const dyn Trait = x as _; //~ error: mismatched types - let _: *const dyn Trait = t as _; //~ error: mismatched types + let _: *const dyn Trait = x as _; //~ error: casting `*const (dyn Trait + 'static)` as `*const dyn Trait` is invalid + let _: *const dyn Trait = t as _; //~ error: casting `*const (dyn Trait + 'static)` as `*const dyn Trait` is invalid } trait Assocked { @@ -33,5 +33,5 @@ trait Assocked { } fn change_assoc(x: *mut dyn Assocked) -> *mut dyn Assocked { - x as _ //~ error: mismatched types + x as _ //~ error: casting `*mut (dyn Assocked + 'static)` as `*mut (dyn Assocked + 'static)` is invalid } diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr index 8e60ca42f0a52..e571a43959ffd 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr @@ -4,53 +4,40 @@ error[E0606]: casting `*const dyn A` as `*const dyn B` is invalid LL | let b: *const dyn B = a as _; | ^^^^^^ | - = note: vtable kinds may not match + = note: the trait objects may have different vtables -error[E0308]: mismatched types +error[E0606]: casting `*const dyn Trait` as `*const dyn Trait` is invalid --> $DIR/ptr-to-trait-obj-different-args.rs:21:34 | LL | let y: *const dyn Trait = x as _; - | ^^^^^^ expected `X`, found `Y` + | ^^^^^^ | - = note: expected trait object `dyn Trait` - found trait object `dyn Trait` - = help: `dyn Trait` implements `Trait` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well + = note: the trait objects may have different vtables -error[E0308]: mismatched types +error[E0606]: casting `*const (dyn Trait + 'static)` as `*const dyn Trait` is invalid --> $DIR/ptr-to-trait-obj-different-args.rs:27:34 | -LL | fn generic(x: *const dyn Trait, t: *const dyn Trait) { - | - found this type parameter LL | let _: *const dyn Trait = x as _; - | ^^^^^^ expected `X`, found type parameter `T` + | ^^^^^^ | - = note: expected trait object `dyn Trait` - found trait object `dyn Trait` - = help: `dyn Trait` implements `Trait` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well + = note: the trait objects may have different vtables -error[E0308]: mismatched types +error[E0606]: casting `*const (dyn Trait + 'static)` as `*const dyn Trait` is invalid --> $DIR/ptr-to-trait-obj-different-args.rs:28:34 | -LL | fn generic(x: *const dyn Trait, t: *const dyn Trait) { - | - expected this type parameter -LL | let _: *const dyn Trait = x as _; LL | let _: *const dyn Trait = t as _; - | ^^^^^^ expected type parameter `T`, found `X` + | ^^^^^^ | - = note: expected trait object `dyn Trait` - found trait object `dyn Trait` - = help: `dyn Trait` implements `Trait` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well + = note: the trait objects may have different vtables -error[E0308]: mismatched types +error[E0606]: casting `*mut (dyn Assocked + 'static)` as `*mut (dyn Assocked + 'static)` is invalid --> $DIR/ptr-to-trait-obj-different-args.rs:36:5 | LL | x as _ - | ^^^^^^ expected `u8`, found `u32` + | ^^^^^^ | - = note: expected trait object `dyn Assocked` - found trait object `dyn Assocked` + = note: the trait objects may have different vtables error: aborting due to 5 previous errors -Some errors have detailed explanations: E0308, E0606. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr index 5a5b4bfcacf43..4e43d3b93fa35 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr @@ -1,11 +1,11 @@ error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17 + --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:27 | LL | fn m<'a>() { | -- lifetime `'a` defined here LL | let unsend: *const dyn Cat<'a> = &(); LL | let _send = unsend as *const S>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` | = note: requirement occurs because of the type `S>`, which makes the generic argument `dyn Cat<'_>` invariant = note: the struct `S` is invariant over the parameter `T` diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr index 5a5b4bfcacf43..4e43d3b93fa35 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr @@ -1,11 +1,11 @@ error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17 + --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:27 | LL | fn m<'a>() { | -- lifetime `'a` defined here LL | let unsend: *const dyn Cat<'a> = &(); LL | let _send = unsend as *const S>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` | = note: requirement occurs because of the type `S>`, which makes the generic argument `dyn Cat<'_>` invariant = note: the struct `S` is invariant over the parameter `T` diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs index 96345de01c960..be2b89aab08f2 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs @@ -2,7 +2,7 @@ // // issue: -#![feature(arbitrary_self_types)] +#![feature(arbitrary_self_types_pointers)] trait Static<'a> { fn proof(self: *const Self, s: &'a str) -> &'static str; diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs index 01c347bfae5a0..d7c6c50d8bebc 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs @@ -33,5 +33,10 @@ fn change_assoc_1<'a, 'b>( //~| error: lifetime may not live long enough } +// This tests the default borrow check error, without the special casing for return values. +fn require_static(_: *const dyn Trait<'static>) {} +fn extend_to_static<'a>(ptr: *const dyn Trait<'a>) { + require_static(ptr as _) //~ error: lifetime may not live long enough +} fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr index 7044e4dec1fe5..6069f4f3b5563 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr @@ -132,5 +132,13 @@ help: `'b` and `'a` must be the same: replace one with the other | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 8 previous errors +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:39:20 + | +LL | fn extend_to_static<'a>(ptr: *const dyn Trait<'a>) { + | -- lifetime `'a` defined here +LL | require_static(ptr as _) + | ^^^^^^^^ cast requires that `'a` must outlive `'static` + +error: aborting due to 9 previous errors diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr index 38c8ba96bc5b7..5687aba625ff7 100644 --- a/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr @@ -4,7 +4,7 @@ error[E0606]: casting `*const (dyn Sub + 'static)` as `*const Wrapper LL | ptr as _ | ^^^^^^^^ | - = note: vtable kinds may not match + = note: the trait objects may have different vtables error: aborting due to 1 previous error diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs index 6645f667d7e65..716b18492c739 100644 --- a/tests/ui/cfg/cfg-false-feature.rs +++ b/tests/ui/cfg/cfg-false-feature.rs @@ -5,7 +5,7 @@ #![feature(decl_macro)] #![cfg(FALSE)] -#![feature(box_syntax)] +#![feature(box_patterns)] macro mac() {} // OK diff --git a/tests/ui/check-cfg/raw-keywords.edition2015.stderr b/tests/ui/check-cfg/raw-keywords.edition2015.stderr new file mode 100644 index 0000000000000..ab7e77686ee9e --- /dev/null +++ b/tests/ui/check-cfg/raw-keywords.edition2015.stderr @@ -0,0 +1,40 @@ +warning: unexpected `cfg` condition name: `tru` + --> $DIR/raw-keywords.rs:14:7 + | +LL | #[cfg(tru)] + | ^^^ help: there is a config with a similar name: `r#true` + | + = help: to expect this configuration use `--check-cfg=cfg(tru)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `r#false` + --> $DIR/raw-keywords.rs:19:7 + | +LL | #[cfg(r#false)] + | ^^^^^^^ + | + = help: expected names are: `async`, `clippy`, `debug_assertions`, `doc`, `doctest`, `edition2015`, `edition2021`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `r#true`, `ub_checks`, `unix`, and `windows` + = help: to expect this configuration use `--check-cfg=cfg(r#false)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `await` + --> $DIR/raw-keywords.rs:27:29 + | +LL | #[cfg_attr(edition2015, cfg(await))] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(await)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `raw` + --> $DIR/raw-keywords.rs:33:7 + | +LL | #[cfg(r#raw)] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(raw)` + = note: see for more information about checking conditional configuration + +warning: 4 warnings emitted + diff --git a/tests/ui/check-cfg/raw-keywords.edition2021.stderr b/tests/ui/check-cfg/raw-keywords.edition2021.stderr new file mode 100644 index 0000000000000..1ae1cad4e6b50 --- /dev/null +++ b/tests/ui/check-cfg/raw-keywords.edition2021.stderr @@ -0,0 +1,40 @@ +warning: unexpected `cfg` condition name: `tru` + --> $DIR/raw-keywords.rs:14:7 + | +LL | #[cfg(tru)] + | ^^^ help: there is a config with a similar name: `r#true` + | + = help: to expect this configuration use `--check-cfg=cfg(tru)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `r#false` + --> $DIR/raw-keywords.rs:19:7 + | +LL | #[cfg(r#false)] + | ^^^^^^^ + | + = help: expected names are: `r#async`, `clippy`, `debug_assertions`, `doc`, `doctest`, `edition2015`, `edition2021`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `r#true`, `ub_checks`, `unix`, and `windows` + = help: to expect this configuration use `--check-cfg=cfg(r#false)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `r#await` + --> $DIR/raw-keywords.rs:28:29 + | +LL | #[cfg_attr(edition2021, cfg(r#await))] + | ^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(r#await)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `raw` + --> $DIR/raw-keywords.rs:33:7 + | +LL | #[cfg(r#raw)] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(raw)` + = note: see for more information about checking conditional configuration + +warning: 4 warnings emitted + diff --git a/tests/ui/check-cfg/raw-keywords.rs b/tests/ui/check-cfg/raw-keywords.rs new file mode 100644 index 0000000000000..5de13240d7ed3 --- /dev/null +++ b/tests/ui/check-cfg/raw-keywords.rs @@ -0,0 +1,40 @@ +// This test check that using raw keywords works with --cfg and --check-cfg +// and that the diagnostics suggestions are coherent +// +//@ check-pass +//@ no-auto-check-cfg +//@ compile-flags: --cfg=true --cfg=async --check-cfg=cfg(r#true,r#async,edition2015,edition2021) +// +//@ revisions: edition2015 edition2021 +//@ [edition2021] compile-flags: --edition 2021 + +#[cfg(r#true)] +fn foo() {} + +#[cfg(tru)] +//~^ WARNING unexpected `cfg` condition name: `tru` +//~^^ SUGGESTION r#true +fn foo() {} + +#[cfg(r#false)] +//~^ WARNING unexpected `cfg` condition name: `r#false` +fn foo() {} + +#[cfg_attr(edition2015, cfg(async))] +#[cfg_attr(edition2021, cfg(r#async))] +fn bar() {} + +#[cfg_attr(edition2015, cfg(await))] +#[cfg_attr(edition2021, cfg(r#await))] +//[edition2015]~^^ WARNING unexpected `cfg` condition name: `await` +//[edition2021]~^^ WARNING unexpected `cfg` condition name: `r#await` +fn zoo() {} + +#[cfg(r#raw)] +//~^ WARNING unexpected `cfg` condition name: `raw` +fn foo() {} + +fn main() { + foo(); + bar(); +} diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 0530e1c34c9af..144a67025b308 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -210,7 +210,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -294,7 +294,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 30 warnings emitted diff --git a/tests/ui/closures/add_semicolon_non_block_closure.rs b/tests/ui/closures/add_semicolon_non_block_closure.rs index 62c5e343cd345..3ae91be60c5a0 100644 --- a/tests/ui/closures/add_semicolon_non_block_closure.rs +++ b/tests/ui/closures/add_semicolon_non_block_closure.rs @@ -8,5 +8,4 @@ fn main() { foo(|| bar()) //~^ ERROR mismatched types [E0308] //~| HELP consider using a semicolon here - //~| HELP try adding a return type } diff --git a/tests/ui/closures/add_semicolon_non_block_closure.stderr b/tests/ui/closures/add_semicolon_non_block_closure.stderr index 7883db8f98ec5..3dd8f12d55f32 100644 --- a/tests/ui/closures/add_semicolon_non_block_closure.stderr +++ b/tests/ui/closures/add_semicolon_non_block_closure.stderr @@ -8,10 +8,6 @@ help: consider using a semicolon here | LL | foo(|| { bar(); }) | + +++ -help: try adding a return type - | -LL | foo(|| -> i32 bar()) - | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs new file mode 100644 index 0000000000000..37c8319d98d0a --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs @@ -0,0 +1,20 @@ +//@ build-pass +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items, intrinsics)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[no_mangle] +pub extern "C-cmse-nonsecure-entry" fn test( + f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u32, + a: u32, + b: u32, + c: u32, +) -> u32 { + f(a, b, c, 42) +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs index e6b0bf3e6860b..9e0ffa75c2296 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs @@ -12,10 +12,31 @@ impl Copy for u32 {} struct Wrapper(T); struct Test { - f1: extern "C-cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, //~ ERROR cannot find type `U` in this scope - //~^ ERROR function pointer types may not have generic parameters + f1: extern "C-cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, + //~^ ERROR cannot find type `U` in this scope + //~| ERROR function pointer types may not have generic parameters f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, //~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798] f4: extern "C-cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, //~ ERROR [E0798] } + +type WithReference = extern "C-cmse-nonsecure-call" fn(&usize); + +trait Trait {} +type WithTraitObject = extern "C-cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait; +//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798] + +type WithStaticTraitObject = + extern "C-cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait; +//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798] + +#[repr(transparent)] +struct WrapperTransparent<'a>(&'a dyn Trait); + +type WithTransparentTraitObject = + extern "C-cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent; +//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798] + +type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...); +//~^ ERROR C-variadic function must have a compatible calling convention, like `C` or `cdecl` [E0045] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr index fa68d95218ccd..7cb8e135ea31b 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr @@ -22,7 +22,7 @@ LL | struct Test { | +++ error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters - --> $DIR/generics.rs:17:43 + --> $DIR/generics.rs:18:43 | LL | f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, | ^^^^^^^^^ @@ -30,18 +30,51 @@ LL | f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type - --> $DIR/generics.rs:19:9 + --> $DIR/generics.rs:20:9 | LL | f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type - --> $DIR/generics.rs:20:9 + --> $DIR/generics.rs:21:9 | LL | f4: extern "C-cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/generics.rs:27:73 + | +LL | type WithTraitObject = extern "C-cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait; + | ^^^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/generics.rs:31:62 + | +LL | extern "C-cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait; + | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/generics.rs:38:62 + | +LL | extern "C-cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent; + | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl` + --> $DIR/generics.rs:41:20 + | +LL | type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention + +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0412, E0562, E0798. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0045, E0412, E0562, E0798. +For more information about an error, try `rustc --explain E0045`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs index 02d5f20febc4a..6061451b2e973 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs @@ -1,10 +1,9 @@ // gate-test-cmse_nonsecure_entry #[no_mangle] -#[cmse_nonsecure_entry] -//~^ ERROR [E0775] -//~| ERROR [E0658] -pub extern "C" fn entry_function(input: u32) -> u32 { +pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + //~^ ERROR [E0570] + //~| ERROR [E0658] input + 6 } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr index beb9716d5906b..dabf16cab3098 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr @@ -1,20 +1,20 @@ -error[E0658]: the `#[cmse_nonsecure_entry]` attribute is an experimental feature - --> $DIR/gate_test.rs:4:1 +error[E0658]: C-cmse-nonsecure-entry ABI is experimental and subject to change + --> $DIR/gate_test.rs:4:12 | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #75835 for more information = help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target --> $DIR/gate_test.rs:4:1 | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -Some errors have detailed explanations: E0658, E0775. -For more information about an error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0570, E0658. +For more information about an error, try `rustc --explain E0570`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs deleted file mode 100644 index a839406cd0aaf..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Regression test for the ICE described in #83475. - -#![crate_type="lib"] - -#![feature(cmse_nonsecure_entry)] -#[cmse_nonsecure_entry] -//~^ ERROR: attribute should be applied to a function definition -struct XEmpty2; -//~^ NOTE: not a function definition diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.stderr deleted file mode 100644 index 26d3bfe78375b..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: attribute should be applied to a function definition - --> $DIR/issue-83475.rs:6:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct XEmpty2; - | --------------- not a function definition - -error: aborting due to 1 previous error - diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs index e197f94096d1d..de6888fae6235 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs @@ -3,14 +3,14 @@ //@ needs-llvm-components: arm #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] -#[lang="sized"] -trait Sized { } -#[lang="copy"] -trait Copy { } +#![crate_type = "lib"] +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} impl Copy for u32 {} #[no_mangle] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function(_: u32, _: u32, _: u32, d: u32) -> u32 { +pub extern "C-cmse-nonsecure-entry" fn entry_function(_: u32, _: u32, _: u32, d: u32) -> u32 { d } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs index e2da3ebb6ae16..4413c461c0444 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs @@ -3,14 +3,19 @@ //@ needs-llvm-components: arm #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] -#[lang="sized"] -trait Sized { } -#[lang="copy"] -trait Copy { } +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} impl Copy for u32 {} #[no_mangle] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function(_: u32, _: u32, _: u32, _: u32, e: u32) -> u32 { +pub extern "C-cmse-nonsecure-entry" fn entry_function( + _: u32, + _: u32, + _: u32, + _: u32, + e: u32, +) -> u32 { e } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr new file mode 100644 index 0000000000000..26409279fbeb4 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr @@ -0,0 +1,9 @@ +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/trustzone-only.rs:20:1 + | +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs index 87eccb4fc6e3e..a4ea7a1757d2d 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs @@ -1,10 +1,25 @@ -//@ ignore-thumbv8m.main-none-eabi -#![feature(cmse_nonsecure_entry)] +//@ revisions: x86 aarch64 thumb7 +// +//@[x86] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86] needs-llvm-components: x86 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@[thumb7] compile-flags: --target thumbv7em-none-eabi +//@[thumb7] needs-llvm-components: arm +#![feature(no_core, lang_items, rustc_attrs, cmse_nonsecure_entry)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +impl Copy for u32 {} #[no_mangle] -#[cmse_nonsecure_entry] //~ ERROR [E0775] -pub extern "C" fn entry_function(input: u32) -> u32 { - input + 6 +pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + //~^ ERROR [E0570] + input } fn main() {} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr deleted file mode 100644 index 3e6954394f445..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension - --> $DIR/trustzone-only.rs:5:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0775`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr new file mode 100644 index 0000000000000..26409279fbeb4 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr @@ -0,0 +1,9 @@ +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/trustzone-only.rs:20:1 + | +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr new file mode 100644 index 0000000000000..26409279fbeb4 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr @@ -0,0 +1,9 @@ +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/trustzone-only.rs:20:1 + | +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.rs deleted file mode 100644 index db4f90e9923cc..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -//@ needs-llvm-components: arm -#![feature(cmse_nonsecure_entry, no_core, lang_items)] -#![no_core] -#[lang = "sized"] -trait Sized {} - -#[lang = "copy"] -trait Copy {} - -#[no_mangle] -#[cmse_nonsecure_entry] -//~^ ERROR `#[cmse_nonsecure_entry]` requires C ABI [E0776] -pub fn entry_function(_: u32, _: u32, _: u32, d: u32) -> u32 { - d -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.stderr deleted file mode 100644 index c3fae3d8bbb67..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0776]: `#[cmse_nonsecure_entry]` requires C ABI - --> $DIR/wrong-abi.rs:12:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0776`. diff --git a/tests/ui/codegen/virtual-function-elimination.rs b/tests/ui/codegen/virtual-function-elimination.rs new file mode 100644 index 0000000000000..3cbeb1293e50a --- /dev/null +++ b/tests/ui/codegen/virtual-function-elimination.rs @@ -0,0 +1,17 @@ +//@ build-pass +//@ compile-flags: -Zvirtual-function-elimination=true -Clto=true +//@ only-x86_64 +//@ no-prefer-dynamic + +// issue #123955 +pub fn test0() { + _ = Box::new(()) as Box; +} + +// issue #124092 +const X: for<'b> fn(&'b ()) = |&()| (); +pub fn test1() { + let _dyn_debug = Box::new(X) as Box as Box; +} + +fn main() {} diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr deleted file mode 100644 index ef5633f71348a..0000000000000 --- a/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never.rs:18:5 - | -LL | Box::<_ /* ! */>::new(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` - | - = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.rs b/tests/ui/coercion/coerce-issue-49593-box-never.rs index 53071be47dcbe..e556959204590 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.rs +++ b/tests/ui/coercion/coerce-issue-49593-box-never.rs @@ -1,5 +1,5 @@ //@ revisions: nofallback fallback -//@check-fail +//@[fallback] check-pass #![feature(never_type)] #![cfg_attr(fallback, feature(never_type_fallback))] @@ -13,10 +13,10 @@ fn raw_ptr_box(t: T) -> *mut T { } fn foo(x: !) -> Box { - // Subtyping during method resolution will generate new inference vars and - // subtype them. Thus fallback will not fall back to `!`, but `()` instead. + // Method resolution will generate new inference vars and relate them. + // Thus fallback will not fall back to `!`, but `()` instead. Box::<_ /* ! */>::new(x) - //~^ ERROR trait bound `(): std::error::Error` is not satisfied + //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn foo_raw_ptr(x: !) -> *mut dyn Error { diff --git a/tests/ui/coercion/constrain-expectation-in-arg.rs b/tests/ui/coercion/constrain-expectation-in-arg.rs new file mode 100644 index 0000000000000..c515dedc4bb4d --- /dev/null +++ b/tests/ui/coercion/constrain-expectation-in-arg.rs @@ -0,0 +1,24 @@ +//@ check-pass + +// Regression test for for #129286. +// Makes sure that we don't have unconstrained type variables that come from +// bivariant type parameters due to the way that we construct expectation types +// when checking call expressions in HIR typeck. + +trait Trait { + type Item; +} + +struct Struct, B> { + pub field: A, +} + +fn identity(x: T) -> T { + x +} + +fn test, B>(x: &Struct) { + let x: &Struct<_, _> = identity(x); +} + +fn main() {} diff --git a/tests/ui/coherence/coherence-conflicting-repeated-negative-trait-impl-70849.rs b/tests/ui/coherence/coherence-conflicting-repeated-negative-trait-impl-70849.rs new file mode 100644 index 0000000000000..88b9d9e62bf75 --- /dev/null +++ b/tests/ui/coherence/coherence-conflicting-repeated-negative-trait-impl-70849.rs @@ -0,0 +1,10 @@ +#![feature(negative_impls)] +//@ edition: 2021 +// Test to ensure we are printing the polarity of the impl trait ref +// when printing out conflicting trait impls + +struct MyType; + +impl !Clone for &mut MyType {} +//~^ ERROR conflicting implementations of trait `Clone` for type `&mut MyType` +fn main() {} diff --git a/tests/ui/coherence/coherence-conflicting-repeated-negative-trait-impl-70849.stderr b/tests/ui/coherence/coherence-conflicting-repeated-negative-trait-impl-70849.stderr new file mode 100644 index 0000000000000..b317197eb405e --- /dev/null +++ b/tests/ui/coherence/coherence-conflicting-repeated-negative-trait-impl-70849.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Clone` for type `&mut MyType` + --> $DIR/coherence-conflicting-repeated-negative-trait-impl-70849.rs:8:1 + | +LL | impl !Clone for &mut MyType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl !Clone for &mut T + where T: ?Sized; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs index cdfeb9c434e6c..e07fa78463c7d 100644 --- a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs +++ b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs @@ -5,9 +5,7 @@ #![feature(with_negative_coherence)] trait Trait {} impl Trait for [(); N] {} -//~^ ERROR: mismatched types impl Trait for [(); N] {} //~^ ERROR: conflicting implementations of trait `Trait` -//~| ERROR: mismatched types fn main() {} diff --git a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr index d65450845bc12..2087be8e7115d 100644 --- a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr +++ b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr @@ -1,25 +1,11 @@ error[E0119]: conflicting implementations of trait `Trait` for type `[(); _]` - --> $DIR/generic_const_type_mismatch.rs:9:1 + --> $DIR/generic_const_type_mismatch.rs:8:1 | LL | impl Trait for [(); N] {} | ----------------------------------- first implementation here -LL | LL | impl Trait for [(); N] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); _]` -error[E0308]: mismatched types - --> $DIR/generic_const_type_mismatch.rs:7:34 - | -LL | impl Trait for [(); N] {} - | ^ expected `usize`, found `u8` - -error[E0308]: mismatched types - --> $DIR/generic_const_type_mismatch.rs:9:34 - | -LL | impl Trait for [(); N] {} - | ^ expected `usize`, found `i8` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0119, E0308. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr index 634a10b7a14c3..44952dc194456 100644 --- a/tests/ui/coherence/normalize-for-errors.next.stderr +++ b/tests/ui/coherence/normalize-for-errors.next.stderr @@ -7,7 +7,7 @@ LL | LL | impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)` | - = note: upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions + = note: upstream crates may add a new impl of trait `std::clone::Clone` for type `std::boxed::Box<(MyType,)>` in future versions = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions error: aborting due to 1 previous error diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs index 4188389a3ad5b..c17bb766b5bcd 100644 --- a/tests/ui/coherence/normalize-for-errors.rs +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -18,6 +18,6 @@ impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} //~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, //~| NOTE conflicting implementation for `(Box<(MyType,)>, //~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions -//[next]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions +//[next]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `std::boxed::Box<(MyType,)>` in future versions fn main() {} diff --git a/tests/ui/compiletest-self-test/compile-flags-last.stderr b/tests/ui/compiletest-self-test/compile-flags-last.stderr index d8d40a7d9f112..72d92206e2bb4 100644 --- a/tests/ui/compiletest-self-test/compile-flags-last.stderr +++ b/tests/ui/compiletest-self-test/compile-flags-last.stderr @@ -1,2 +1,5 @@ error: Argument to option 'cap-lints' missing + Usage: + --cap-lints LEVEL Set the most restrictive lint level. More restrictive + lints are capped at this level diff --git a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs new file mode 100644 index 0000000000000..794e6fad3fc22 --- /dev/null +++ b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs @@ -0,0 +1,11 @@ +// This was triggering an assertion failure in `NodeRange::new`. + +#![feature(cfg_eval)] +#![feature(stmt_expr_attributes)] + +fn f() -> u32 { + #[cfg_eval] #[cfg(not(FALSE))] 0 + //~^ ERROR removing an expression is not supported in this position +} + +fn main() {} diff --git a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr new file mode 100644 index 0000000000000..0699e182bd5f2 --- /dev/null +++ b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr @@ -0,0 +1,8 @@ +error: removing an expression is not supported in this position + --> $DIR/invalid-node-range-issue-129166.rs:7:17 + | +LL | #[cfg_eval] #[cfg(not(FALSE))] 0 + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs index c4e74596e9fdc..cc2ff9b8dea07 100644 --- a/tests/ui/const-generics/bad-subst-const-kind.rs +++ b/tests/ui/const-generics/bad-subst-const-kind.rs @@ -7,7 +7,6 @@ trait Q { impl Q for [u8; N] { //~^ ERROR: the constant `N` is not of type `usize` - //~| ERROR: mismatched types const ASSOC: usize = 1; } diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr index 21ec8f0768cf1..5c8d9c9036356 100644 --- a/tests/ui/const-generics/bad-subst-const-kind.stderr +++ b/tests/ui/const-generics/bad-subst-const-kind.stderr @@ -5,7 +5,7 @@ LL | impl Q for [u8; N] { | ^^^^^^^ expected `usize`, found `u64` error: the constant `13` is not of type `u64` - --> $DIR/bad-subst-const-kind.rs:14:24 + --> $DIR/bad-subst-const-kind.rs:13:24 | LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { | ^^^^^^^^ expected `u64`, found `usize` @@ -18,12 +18,5 @@ LL | impl Q for [u8; N] { | | | unsatisfied trait bound introduced here -error[E0308]: mismatched types - --> $DIR/bad-subst-const-kind.rs:8:31 - | -LL | impl Q for [u8; N] { - | ^ expected `usize`, found `u64` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-braced-expansion.rs b/tests/ui/const-generics/early/trivial-const-arg-macro-braced-expansion.rs new file mode 100644 index 0000000000000..33630205369f0 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-braced-expansion.rs @@ -0,0 +1,14 @@ +macro_rules! y { + () => { + N + }; +} + +struct A; + +fn foo() -> A<{ y!() }> { + A::<1> + //~^ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-braced-expansion.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-braced-expansion.stderr new file mode 100644 index 0000000000000..4461477f3e9b7 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-braced-expansion.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/trivial-const-arg-macro-braced-expansion.rs:10:5 + | +LL | fn foo() -> A<{ y!() }> { + | ----------- expected `A` because of return type +LL | A::<1> + | ^^^^^^ expected `N`, found `1` + | + = note: expected struct `A` + found struct `A<1>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.rs b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.rs new file mode 100644 index 0000000000000..5a9e62561dc99 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.rs @@ -0,0 +1,15 @@ +macro_rules! y { + () => { + N + //~^ ERROR: generic parameters may not be used in const operations + }; +} + +struct A; + +#[rustfmt::skip] +fn foo() -> A<{{ y!() }}> { + A::<1> +} + +fn main() {} diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr new file mode 100644 index 0000000000000..e40d05924b11d --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr @@ -0,0 +1,15 @@ +error: generic parameters may not be used in const operations + --> $DIR/trivial-const-arg-macro-nested-braces-2.rs:3:9 + | +LL | N + | ^ cannot perform const operation using `N` +... +LL | fn foo() -> A<{{ y!() }}> { + | ---- in this macro invocation + | + = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.rs b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.rs new file mode 100644 index 0000000000000..45c0768dde44a --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.rs @@ -0,0 +1,15 @@ +#[rustfmt::skip] +macro_rules! y { + () => { + { N } + //~^ ERROR: generic parameters may not be used in const operations + }; +} + +struct A; + +fn foo() -> A<{ y!() }> { + A::<1> +} + +fn main() {} diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr new file mode 100644 index 0000000000000..b91d6c7a024a3 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr @@ -0,0 +1,15 @@ +error: generic parameters may not be used in const operations + --> $DIR/trivial-const-arg-macro-nested-braces.rs:4:11 + | +LL | { N } + | ^ cannot perform const operation using `N` +... +LL | fn foo() -> A<{ y!() }> { + | ---- in this macro invocation + | + = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/early/trivial-const-arg-nested-braces.rs b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.rs new file mode 100644 index 0000000000000..941ba6bfea785 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.rs @@ -0,0 +1,9 @@ +struct A; + +#[rustfmt::skip] +fn foo() -> A<{ { N } }> { + //~^ ERROR: generic parameters may not be used in const operations + A::<1> +} + +fn main() {} diff --git a/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr new file mode 100644 index 0000000000000..d60516ba4bcd1 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr @@ -0,0 +1,11 @@ +error: generic parameters may not be used in const operations + --> $DIR/trivial-const-arg-nested-braces.rs:4:35 + | +LL | fn foo() -> A<{ { N } }> { + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 217f609459eed..b88fe966b77ce 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -8,7 +8,7 @@ note: required by a const generic parameter in `Mask::::splat` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | -LL | let y: Mask = Mask::<_, _>::splat(false); +LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); | ++++++++++++ error[E0284]: type annotations needed for `Mask<_, _>` @@ -21,7 +21,7 @@ note: required by a const generic parameter in `Mask` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | -LL | let y: Mask = Mask::<_, _>::splat(false); +LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); | ++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/different-fn.stderr b/tests/ui/const-generics/generic_const_exprs/different-fn.stderr index 52917df0da157..ac80463480db1 100644 --- a/tests/ui/const-generics/generic_const_exprs/different-fn.stderr +++ b/tests/ui/const-generics/generic_const_exprs/different-fn.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/different-fn.rs:10:5 | LL | [0; size_of::>()] - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::()`, found `size_of::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::()`, found `0` | = note: expected constant `size_of::()` - found constant `size_of::>()` + found constant `0` error: unconstrained generic constant --> $DIR/different-fn.rs:10:9 diff --git a/tests/ui/const-generics/generic_const_exprs/issue-109141.rs b/tests/ui/const-generics/generic_const_exprs/issue-109141.rs index c6dd981cced00..5303b24717353 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-109141.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-109141.rs @@ -3,8 +3,7 @@ impl EntriesBuffer { fn a(&self) -> impl Iterator { - self.0.iter_mut() //~ ERROR: cannot borrow `*self.0` as mutable, as it is behind a `&` reference - //~| ERROR captures lifetime that does not appear in bounds + self.0.iter_mut() } } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr b/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr index 24f3ed7cdf15e..fcbd690459972 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `HashesEntryLEN` in this scope - --> $DIR/issue-109141.rs:11:32 + --> $DIR/issue-109141.rs:10:32 | LL | struct EntriesBuffer(Box<[[u8; HashesEntryLEN]; 5]>); | ^^^^^^^^^^^^^^ not found in this scope @@ -9,33 +9,6 @@ help: you might be missing a const parameter LL | struct EntriesBuffer(Box<[[u8; HashesEntryLEN]; 5]>); | ++++++++++++++++++++++++++++++++++ -error[E0596]: cannot borrow `*self.0` as mutable, as it is behind a `&` reference - --> $DIR/issue-109141.rs:6:9 - | -LL | self.0.iter_mut() - | ^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable - | -help: consider changing this to be a mutable reference - | -LL | fn a(&mut self) -> impl Iterator { - | ~~~~~~~~~ - -error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds - --> $DIR/issue-109141.rs:6:9 - | -LL | fn a(&self) -> impl Iterator { - | ----- ------------- opaque type defined here - | | - | hidden type `std::slice::IterMut<'_, [u8; {const error}]>` captures the anonymous lifetime defined here -LL | self.0.iter_mut() - | ^^^^^^^^^^^^^^^^^ - | -help: add a `use<...>` bound to explicitly capture `'_` - | -LL | fn a(&self) -> impl Iterator + use<'_> { - | +++++++++ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0425, E0596, E0700. -For more information about an error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.rs b/tests/ui/const-generics/generic_const_exprs/opaque_type.rs index 7209290a36e0a..56b8acbf88cde 100644 --- a/tests/ui/const-generics/generic_const_exprs/opaque_type.rs +++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.rs @@ -2,7 +2,6 @@ #![allow(incomplete_features)] type Foo = impl Sized; -//~^ ERROR: unconstrained opaque type fn with_bound() -> Foo where diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr index c7a266205b4b5..e9fb8c0f403ae 100644 --- a/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr +++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/opaque_type.rs:11:17 + --> $DIR/opaque_type.rs:10:17 | LL | type Foo = impl Sized; | ---------- the found opaque type @@ -11,20 +11,12 @@ LL | let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize]; found opaque type `Foo` error[E0605]: non-primitive cast: `usize` as `Foo` - --> $DIR/opaque_type.rs:11:17 + --> $DIR/opaque_type.rs:10:17 | LL | let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize]; | ^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object -error: unconstrained opaque type - --> $DIR/opaque_type.rs:4:12 - | -LL | type Foo = impl Sized; - | ^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0308, E0605. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs index a45deabbb0f33..8e5e23b233718 100644 --- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs @@ -8,7 +8,6 @@ trait Q { impl Q for [u8; N] {} //~^ ERROR not all trait items implemented //~| ERROR the constant `N` is not of type `usize` -//~| ERROR mismatched types pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} //~^ ERROR the constant `13` is not of type `u64` diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr index 68870a8d38da6..e03580ec007ca 100644 --- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr @@ -14,7 +14,7 @@ LL | impl Q for [u8; N] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation error: the constant `13` is not of type `u64` - --> $DIR/type_mismatch.rs:13:26 + --> $DIR/type_mismatch.rs:12:26 | LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} | ^^^^^^^^ expected `u64`, found `usize` @@ -28,20 +28,14 @@ LL | impl Q for [u8; N] {} | unsatisfied trait bound introduced here error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:13:20 + --> $DIR/type_mismatch.rs:12:20 | LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `[u8; <[u8; 13] as Q>::ASSOC]`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:8:31 - | -LL | impl Q for [u8; N] {} - | ^ expected `usize`, found `u64` - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0308. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs deleted file mode 100644 index 81be8d5c7d767..0000000000000 --- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs +++ /dev/null @@ -1,54 +0,0 @@ -//@ known-bug: #110395 -//@ known-bug: #97156 - -#![feature(const_type_id, const_trait_impl, generic_const_exprs)] -#![allow(incomplete_features)] - -use std::any::TypeId; -// `One` and `Two` are currently considered equal types, as both -// `One <: Two` and `One :> Two` holds. -type One = for<'a> fn(&'a (), &'a ()); -type Two = for<'a, 'b> fn(&'a (), &'b ()); -trait AssocCt { - const ASSOC: usize; -} -const fn to_usize() -> usize { - const WHAT_A_TYPE: TypeId = TypeId::of::(); - match TypeId::of::() { - WHAT_A_TYPE => 0, - _ => 1000, - } -} -impl AssocCt for T { - const ASSOC: usize = to_usize::(); -} - -trait WithAssoc { - type Assoc; -} -impl WithAssoc<()> for T -where - [(); ::ASSOC]:, -{ - type Assoc = [u8; ::ASSOC]; -} - -fn generic(x: >::Assoc) -> >::Assoc -where - [(); ::ASSOC]:, - T: WithAssoc, -{ - x -} - -fn unsound(x: >::Assoc) -> >::Assoc -where - One: WithAssoc, -{ - let x: >::Assoc = generic::(x); - x -} - -fn main() { - println!("{:?}", unsound::<()>([])); -} diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr deleted file mode 100644 index 26e724c906137..0000000000000 --- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: to use a constant of type `TypeId` in a pattern, `TypeId` must be annotated with `#[derive(PartialEq)]` - --> $DIR/typeid-equality-by-subtyping.rs:18:9 - | -LL | WHAT_A_TYPE => 0, - | ^^^^^^^^^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details - -error[E0277]: the trait bound `for<'a, 'b> fn(&'a (), &'b ()): WithAssoc` is not satisfied - --> $DIR/typeid-equality-by-subtyping.rs:44:51 - | -LL | fn unsound(x: >::Assoc) -> >::Assoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WithAssoc` is not implemented for `for<'a, 'b> fn(&'a (), &'b ())` - -error[E0277]: the trait bound `for<'a, 'b> fn(&'a (), &'b ()): WithAssoc` is not satisfied - --> $DIR/typeid-equality-by-subtyping.rs:47:1 - | -LL | / { -LL | | let x: >::Assoc = generic::(x); -LL | | x -LL | | } - | |_^ the trait `WithAssoc` is not implemented for `for<'a, 'b> fn(&'a (), &'b ())` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs index 05a3487ffca51..d11b457a3f619 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs @@ -25,8 +25,8 @@ mod v20 { } impl v17 { - //~^ ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#1} - //~| ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#1} + //~^ ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#0} + //~| ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#0} pub const fn v21() -> v18 { //~^ ERROR cannot find type `v18` in this scope v18 { _p: () } diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr index 39f022fbee9db..15d3c47258525 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr @@ -72,13 +72,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more LL + #![feature(adt_const_params)] | -error: maximum number of nodes exceeded in constant v20::v17::::{constant#1} +error: maximum number of nodes exceeded in constant v20::v17::::{constant#0} --> $DIR/unevaluated-const-ice-119731.rs:27:37 | LL | impl v17 { | ^^ -error: maximum number of nodes exceeded in constant v20::v17::::{constant#1} +error: maximum number of nodes exceeded in constant v20::v17::::{constant#0} --> $DIR/unevaluated-const-ice-119731.rs:27:37 | LL | impl v17 { diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr index db93bcca60fb3..bae8249845c02 100644 --- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr @@ -1,3 +1,11 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/unify-op-with-fn-call.rs:3:12 + | +LL | #![feature(generic_const_exprs, adt_const_params, const_trait_impl, effects)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + error: const `impl` for trait `Add` which is not marked with `#[const_trait]` --> $DIR/unify-op-with-fn-call.rs:10:12 | @@ -67,7 +75,7 @@ error[E0284]: type annotations needed: cannot normalize `foo2::{constant#0}` LL | bar2::<{ std::ops::Add::add(N, N) }>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2::{constant#0}` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0284, E0741. For more information about an error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/invariant.rs b/tests/ui/const-generics/invariant.rs index ee4ad4e7c4e7b..95a28b61dde3a 100644 --- a/tests/ui/const-generics/invariant.rs +++ b/tests/ui/const-generics/invariant.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData; trait SadBee { const ASSOC: usize; } -// fn(&'static ())` is a supertype of `for<'a> fn(&'a ())` while +// `fn(&'static ())` is a supertype of `for<'a> fn(&'a ())` while // we allow two different impls for these types, leading // to different const eval results. impl SadBee for for<'a> fn(&'a ()) { diff --git a/tests/ui/const-generics/issue-112505-overflow.rs b/tests/ui/const-generics/issue-112505-overflow.rs deleted file mode 100644 index 0dd7776d59544..0000000000000 --- a/tests/ui/const-generics/issue-112505-overflow.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(transmute_generic_consts)] - -fn overflow(v: [[[u32; 8888888]; 9999999]; 777777777]) -> [[[u32; 9999999]; 777777777]; 239] { - unsafe { std::mem::transmute(v) } //~ ERROR cannot transmute between types of different sizes -} - -fn main() { } diff --git a/tests/ui/const-generics/issue-112505-overflow.stderr b/tests/ui/const-generics/issue-112505-overflow.stderr deleted file mode 100644 index 0bd3f6eddd459..0000000000000 --- a/tests/ui/const-generics/issue-112505-overflow.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/issue-112505-overflow.rs:4:14 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^ - | - = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture) - = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture) - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs index e07fde76a4a83..553165f90b889 100644 --- a/tests/ui/const-generics/issues/issue-100313.rs +++ b/tests/ui/const-generics/issues/issue-100313.rs @@ -1,5 +1,4 @@ #![allow(incomplete_features)] -#![feature(const_mut_refs)] #![feature(adt_const_params, unsized_const_params)] struct T; diff --git a/tests/ui/const-generics/issues/issue-100313.stderr b/tests/ui/const-generics/issues/issue-100313.stderr index a422764fe2c58..6e419078e5eed 100644 --- a/tests/ui/const-generics/issues/issue-100313.stderr +++ b/tests/ui/const-generics/issues/issue-100313.stderr @@ -1,16 +1,16 @@ error[E0080]: evaluation of constant value failed - --> $DIR/issue-100313.rs:10:13 + --> $DIR/issue-100313.rs:9:13 | LL | *(B as *const bool as *mut bool) = false; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC0 which is read-only | note: inside `T::<&true>::set_false` - --> $DIR/issue-100313.rs:10:13 + --> $DIR/issue-100313.rs:9:13 | LL | *(B as *const bool as *mut bool) = false; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: inside `_` - --> $DIR/issue-100313.rs:18:5 + --> $DIR/issue-100313.rs:17:5 | LL | x.set_false(); | ^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr index b5eec3046fd9e..98bb81968100b 100644 --- a/tests/ui/const-generics/issues/issue-88119.stderr +++ b/tests/ui/const-generics/issues/issue-88119.stderr @@ -1,3 +1,11 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/issue-88119.rs:4:39 + | +LL | #![feature(const_trait_impl, effects, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{constant#0}` --> $DIR/issue-88119.rs:19:49 | @@ -28,6 +36,6 @@ LL | where LL | [(); name_len::()]:, | --------------------- unsatisfied trait bound introduced here -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/occurs-check/unused-substs-1.stderr b/tests/ui/const-generics/occurs-check/unused-substs-1.stderr index 8c66c4fefb7ed..0184a05932707 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-1.stderr +++ b/tests/ui/const-generics/occurs-check/unused-substs-1.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `A<_>: Bar<_>` is not satisfied LL | let _ = A; | ^ the trait `Bar<_>` is not implemented for `A<_>` | - = help: the trait `Bar<_>` is implemented for `A<7>` + = help: the trait `Bar<_>` is implemented for `A<{ 6 + 1 }>` note: required by a bound in `A` --> $DIR/unused-substs-1.rs:9:11 | diff --git a/tests/ui/const-generics/occurs-check/unused-substs-3.rs b/tests/ui/const-generics/occurs-check/unused-substs-3.rs index 6db18d587d3e2..dfb051192e2f3 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-3.rs +++ b/tests/ui/const-generics/occurs-check/unused-substs-3.rs @@ -11,9 +11,11 @@ fn bind() -> (T, [u8; 6 + 1]) { fn main() { let (mut t, foo) = bind(); + //~^ ERROR mismatched types + //~| NOTE cyclic type + // `t` is `ty::Infer(TyVar(?1t))` // `foo` contains `ty::Infer(TyVar(?1t))` in its substs t = foo; - //~^ ERROR mismatched types - //~| NOTE cyclic type + } diff --git a/tests/ui/const-generics/occurs-check/unused-substs-3.stderr b/tests/ui/const-generics/occurs-check/unused-substs-3.stderr index bcb59705c6b2f..30a2a7901bdf5 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-3.stderr +++ b/tests/ui/const-generics/occurs-check/unused-substs-3.stderr @@ -1,10 +1,8 @@ error[E0308]: mismatched types - --> $DIR/unused-substs-3.rs:16:9 + --> $DIR/unused-substs-3.rs:13:24 | -LL | t = foo; - | ^^^- help: try using a conversion method: `.to_vec()` - | | - | cyclic type of infinite size +LL | let (mut t, foo) = bind(); + | ^^^^^^ cyclic type of infinite size error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/transmute-fail.rs b/tests/ui/const-generics/transmute-fail.rs index a9b297ffb62a2..95c711605675f 100644 --- a/tests/ui/const-generics/transmute-fail.rs +++ b/tests/ui/const-generics/transmute-fail.rs @@ -1,3 +1,8 @@ +// ignore-tidy-linelength +//@ normalize-stderr-32bit: "values of the type `[^`]+` are too big" -> "values of the type $$REALLY_TOO_BIG are too big" +//@ normalize-stderr-64bit: "values of the type `[^`]+` are too big" -> "values of the type $$REALLY_TOO_BIG are too big" + + #![feature(transmute_generic_consts)] #![feature(generic_const_exprs)] #![allow(incomplete_features)] @@ -11,8 +16,6 @@ fn foo(v: [[u32; H + 1]; W]) -> [[u32; W + 1]; H fn bar(v: [[u32; H]; W]) -> [[u32; W]; H] { //~^ ERROR: the constant `W` is not of type `usize` - //~| ERROR: mismatched types - //~| ERROR: mismatched types unsafe { std::mem::transmute(v) //~^ ERROR: the constant `W` is not of type `usize` @@ -33,6 +36,11 @@ fn overflow(v: [[[u32; 8888888]; 9999999]; 777777777]) -> [[[u32; 9999999]; 7777 } } +fn overflow_more(v: [[[u32; 8888888]; 9999999]; 777777777]) -> [[[u32; 9999999]; 777777777]; 239] { + unsafe { std::mem::transmute(v) } //~ ERROR cannot transmute between types of different sizes +} + + fn transpose(v: [[u32; H]; W]) -> [[u32; W]; H] { unsafe { std::mem::transmute(v) diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index 124fbee885057..638ce790345a3 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -1,11 +1,11 @@ error: the constant `W` is not of type `usize` - --> $DIR/transmute-fail.rs:12:42 + --> $DIR/transmute-fail.rs:17:42 | LL | fn bar(v: [[u32; H]; W]) -> [[u32; W]; H] { | ^^^^^^^^^^^^^ expected `usize`, found `bool` error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:7:9 + --> $DIR/transmute-fail.rs:12:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -14,13 +14,13 @@ LL | std::mem::transmute(v) = note: target type: `[[u32; W + 1]; H]` (size can vary because of [u32; W + 1]) error: the constant `W` is not of type `usize` - --> $DIR/transmute-fail.rs:17:9 + --> $DIR/transmute-fail.rs:20:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:24:9 + --> $DIR/transmute-fail.rs:27:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -29,16 +29,25 @@ LL | std::mem::transmute(v) = note: target type: `[u32; W * H * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:31:9 + --> $DIR/transmute-fail.rs:34:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture) - = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture) + = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type $REALLY_TOO_BIG are too big for the target architecture) + = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type $REALLY_TOO_BIG are too big for the target architecture) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:38:9 + --> $DIR/transmute-fail.rs:40:14 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type $REALLY_TOO_BIG are too big for the target architecture) + = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (values of the type $REALLY_TOO_BIG are too big for the target architecture) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-fail.rs:46:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -47,7 +56,7 @@ LL | std::mem::transmute(v) = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:49:9 + --> $DIR/transmute-fail.rs:57:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -56,7 +65,7 @@ LL | std::mem::transmute(v) = note: target type: `[u32; W * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:56:9 + --> $DIR/transmute-fail.rs:64:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -65,7 +74,7 @@ LL | std::mem::transmute(v) = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:65:9 + --> $DIR/transmute-fail.rs:73:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -74,7 +83,7 @@ LL | std::mem::transmute(v) = note: target type: `[u32; D * W * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:74:9 + --> $DIR/transmute-fail.rs:82:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -83,7 +92,7 @@ LL | std::mem::transmute(v) = note: target type: `[[u32; D * W]; H]` (size can vary because of [u32; D * W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:81:9 + --> $DIR/transmute-fail.rs:89:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -92,7 +101,7 @@ LL | std::mem::transmute(v) = note: target type: `[u8; L * 2]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:88:9 + --> $DIR/transmute-fail.rs:96:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -101,7 +110,7 @@ LL | std::mem::transmute(v) = note: target type: `[u16; L]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:95:9 + --> $DIR/transmute-fail.rs:103:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -110,7 +119,7 @@ LL | std::mem::transmute(v) = note: target type: `[[u8; 1]; L]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:104:9 + --> $DIR/transmute-fail.rs:112:9 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -118,19 +127,6 @@ LL | std::mem::transmute(v) = note: source type: `[[u32; 2 * H]; W + W]` (size can vary because of [u32; 2 * H]) = note: target type: `[[u32; W + W]; 2 * H]` (size can vary because of [u32; W + W]) -error[E0308]: mismatched types - --> $DIR/transmute-fail.rs:12:53 - | -LL | fn bar(v: [[u32; H]; W]) -> [[u32; W]; H] { - | ^ expected `usize`, found `bool` - -error[E0308]: mismatched types - --> $DIR/transmute-fail.rs:12:67 - | -LL | fn bar(v: [[u32; H]; W]) -> [[u32; W]; H] { - | ^ expected `usize`, found `bool` - -error: aborting due to 16 previous errors +error: aborting due to 15 previous errors -Some errors have detailed explanations: E0308, E0512. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/const-generics/type_mismatch.rs b/tests/ui/const-generics/type_mismatch.rs index 9c7217cd83eee..8187c785cd1c7 100644 --- a/tests/ui/const-generics/type_mismatch.rs +++ b/tests/ui/const-generics/type_mismatch.rs @@ -1,12 +1,10 @@ fn foo() -> [u8; N] { bar::() //~^ ERROR the constant `N` is not of type `u8` - //~| ERROR: mismatched types } fn bar() -> [u8; N] {} //~^ ERROR the constant `N` is not of type `usize` -//~| ERROR: mismatched types //~| ERROR mismatched types fn main() {} diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index 77e9f5e2b445e..d1bb5c1242f02 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -1,5 +1,5 @@ error: the constant `N` is not of type `usize` - --> $DIR/type_mismatch.rs:7:26 + --> $DIR/type_mismatch.rs:6:26 | LL | fn bar() -> [u8; N] {} | ^^^^^^^ expected `usize`, found `u8` @@ -11,31 +11,19 @@ LL | bar::() | ^ expected `u8`, found `usize` | note: required by a const generic parameter in `bar` - --> $DIR/type_mismatch.rs:7:8 + --> $DIR/type_mismatch.rs:6:8 | LL | fn bar() -> [u8; N] {} | ^^^^^^^^^^^ required by this const generic parameter in `bar` error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:7:26 + --> $DIR/type_mismatch.rs:6:26 | LL | fn bar() -> [u8; N] {} | --- ^^^^^^^ expected `[u8; N]`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:2:11 - | -LL | bar::() - | ^ expected `u8`, found `usize` - -error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:7:31 - | -LL | fn bar() -> [u8; N] {} - | ^ expected `usize`, found `u8` - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/unsized_const_params/symbol_mangling_v0_str.rs b/tests/ui/const-generics/unsized_const_params/symbol_mangling_v0_str.rs new file mode 100644 index 0000000000000..359126f125167 --- /dev/null +++ b/tests/ui/const-generics/unsized_const_params/symbol_mangling_v0_str.rs @@ -0,0 +1,24 @@ +//@ check-pass +//@ compile-flags: -Csymbol-mangling-version=v0 +#![allow(incomplete_features)] +#![feature(unsized_const_params)] + +// Regression test for #116303 + +#[derive(PartialEq, Eq)] +struct MyStr(str); +impl std::marker::UnsizedConstParamTy for MyStr {} + +fn function_with_my_str() -> &'static MyStr { + S +} + +impl MyStr { + const fn new(s: &'static str) -> &'static MyStr { + unsafe { std::mem::transmute(s) } + } +} + +pub fn main() { + let f = function_with_my_str::<{ MyStr::new("hello") }>(); +} diff --git a/tests/ui/const-generics/wrong-normalization.rs b/tests/ui/const-generics/wrong-normalization.rs index 8b2323e3d479c..f1ce317b3f78b 100644 --- a/tests/ui/const-generics/wrong-normalization.rs +++ b/tests/ui/const-generics/wrong-normalization.rs @@ -15,6 +15,5 @@ pub struct I8; impl as Identity>::Identity { //~^ ERROR no nominal type found for inherent implementation -//~| ERROR no associated item named `MIN` found for type `i8` pub fn foo(&self) {} } diff --git a/tests/ui/const-generics/wrong-normalization.stderr b/tests/ui/const-generics/wrong-normalization.stderr index 379a5593dd640..2f8dfc895b279 100644 --- a/tests/ui/const-generics/wrong-normalization.stderr +++ b/tests/ui/const-generics/wrong-normalization.stderr @@ -6,18 +6,6 @@ LL | impl as Identity>::Identity { | = note: either implement a trait on it or create a newtype to wrap it instead -error[E0599]: no associated item named `MIN` found for type `i8` in the current scope - --> $DIR/wrong-normalization.rs:16:15 - | -LL | impl as Identity>::Identity { - | ^^^ associated item not found in `i8` - | -help: you are looking for the module in `std`, not the primitive type - | -LL | impl as Identity>::Identity { - | +++++ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0118, E0599. -For more information about an error, try `rustc --explain E0118`. +For more information about this error, try `rustc --explain E0118`. diff --git a/tests/ui/consts/auxiliary/const_mut_refs_crate.rs b/tests/ui/consts/auxiliary/const_mut_refs_crate.rs index 8e78748e896e1..d8e4b74d73c98 100644 --- a/tests/ui/consts/auxiliary/const_mut_refs_crate.rs +++ b/tests/ui/consts/auxiliary/const_mut_refs_crate.rs @@ -10,8 +10,6 @@ // See also ../const-mut-refs-crate.rs for more details // about this test. -#![feature(const_mut_refs)] - // if we used immutable references here, then promotion would // turn the `&42` into a promoted, which gets duplicated arbitrarily. pub static mut FOO: &'static mut i32 = &mut 42; diff --git a/tests/ui/consts/const-address-of-interior-mut.rs b/tests/ui/consts/const-address-of-interior-mut.rs index 930fa0c492f35..450f1c4a94ebd 100644 --- a/tests/ui/consts/const-address-of-interior-mut.rs +++ b/tests/ui/consts/const-address-of-interior-mut.rs @@ -1,14 +1,15 @@ +//@check-pass use std::cell::Cell; -const A: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability +const A: () = { let x = Cell::new(2); &raw const x; }; -static B: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability +static B: () = { let x = Cell::new(2); &raw const x; }; -static mut C: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability +static mut C: () = { let x = Cell::new(2); &raw const x; }; const fn foo() { let x = Cell::new(0); - let y = &raw const x; //~ ERROR interior mutability + let y = &raw const x; } fn main() {} diff --git a/tests/ui/consts/const-address-of-interior-mut.stderr b/tests/ui/consts/const-address-of-interior-mut.stderr deleted file mode 100644 index 203745f0b019d..0000000000000 --- a/tests/ui/consts/const-address-of-interior-mut.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/const-address-of-interior-mut.rs:3:39 - | -LL | const A: () = { let x = Cell::new(2); &raw const x; }; - | ^^^^^^^^^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/const-address-of-interior-mut.rs:5:40 - | -LL | static B: () = { let x = Cell::new(2); &raw const x; }; - | ^^^^^^^^^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/const-address-of-interior-mut.rs:7:44 - | -LL | static mut C: () = { let x = Cell::new(2); &raw const x; }; - | ^^^^^^^^^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/const-address-of-interior-mut.rs:11:13 - | -LL | let y = &raw const x; - | ^^^^^^^^^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-address-of-mut.rs b/tests/ui/consts/const-address-of-mut.rs index c3f37843d3c15..2dd909b4ce74a 100644 --- a/tests/ui/consts/const-address-of-mut.rs +++ b/tests/ui/consts/const-address-of-mut.rs @@ -1,10 +1,12 @@ -const A: () = { let mut x = 2; &raw mut x; }; //~ mutable pointer +//@check-pass -static B: () = { let mut x = 2; &raw mut x; }; //~ mutable pointer +const A: () = { let mut x = 2; &raw mut x; }; + +static B: () = { let mut x = 2; &raw mut x; }; const fn foo() { let mut x = 0; - let y = &raw mut x; //~ mutable pointer + let y = &raw mut x; } fn main() {} diff --git a/tests/ui/consts/const-address-of-mut.stderr b/tests/ui/consts/const-address-of-mut.stderr deleted file mode 100644 index d4243485de159..0000000000000 --- a/tests/ui/consts/const-address-of-mut.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0658]: raw mutable pointers are not allowed in constants - --> $DIR/const-address-of-mut.rs:1:32 - | -LL | const A: () = { let mut x = 2; &raw mut x; }; - | ^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: raw mutable pointers are not allowed in statics - --> $DIR/const-address-of-mut.rs:3:33 - | -LL | static B: () = { let mut x = 2; &raw mut x; }; - | ^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: raw mutable pointers are not allowed in constant functions - --> $DIR/const-address-of-mut.rs:7:13 - | -LL | let y = &raw mut x; - | ^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr index 0d9b718cd067f..f6eda69e12791 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -12,8 +12,8 @@ LL | = [0; (i8::MAX + 1u8) as usize]; | = help: the trait `Add` is not implemented for `i8` = help: the following other types implement trait `Add`: - `&'a i8` implements `Add` - `&i8` implements `Add<&i8>` + `&i8` implements `Add` + `&i8` implements `Add` `i8` implements `Add<&i8>` `i8` implements `Add` diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index 32fe30dc88247..399f21a989429 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -12,8 +12,8 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | = help: the trait `Add` is not implemented for `i8` = help: the following other types implement trait `Add`: - `&'a i8` implements `Add` - `&i8` implements `Add<&i8>` + `&i8` implements `Add` + `&i8` implements `Add` `i8` implements `Add<&i8>` `i8` implements `Add` diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs index ac9e8b64b4897..9cf9360dcbd08 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs @@ -1,6 +1,5 @@ #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(const_mut_refs)] use std::intrinsics; const FOO: i32 = foo(); diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr index cdde14756e471..2fd7222da521f 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -1,16 +1,16 @@ error[E0080]: evaluation of constant value failed - --> $DIR/alloc_intrinsic_errors.rs:9:17 + --> $DIR/alloc_intrinsic_errors.rs:8:17 | LL | let _ = intrinsics::const_allocate(4, 3) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid align passed to `const_allocate`: 3 is not a power of 2 | note: inside `foo` - --> $DIR/alloc_intrinsic_errors.rs:9:17 + --> $DIR/alloc_intrinsic_errors.rs:8:17 | LL | let _ = intrinsics::const_allocate(4, 3) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: inside `FOO` - --> $DIR/alloc_intrinsic_errors.rs:6:18 + --> $DIR/alloc_intrinsic_errors.rs:5:18 | LL | const FOO: i32 = foo(); | ^^^^^ diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs index 0c292ec5af72e..83ed496ac2c25 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(const_mut_refs)] use std::intrinsics; const FOO: &i32 = foo(); diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs index 1ba20f908eaf7..69e980eb13d3e 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(const_mut_refs)] use std::intrinsics; const FOO: i32 = foo(); diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 383c167d3c01a..271c861109185 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc_intrinsic_uninit.rs:8:1 + --> $DIR/alloc_intrinsic_uninit.rs:7:1 | LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; | ^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected an integer diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index d06792283262d..ec7cc7d4140ac 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc_intrinsic_uninit.rs:8:1 + --> $DIR/alloc_intrinsic_uninit.rs:7:1 | LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; | ^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected an integer diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs index ed483bccc1fac..c283a5fae7de6 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -2,7 +2,6 @@ // compile-test #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(const_mut_refs)] use std::intrinsics; const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs index b8fed212c97f9..26cb69e458b61 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -1,11 +1,11 @@ +// We unleash Miri here since this test demonstrates code that bypasses the checks against interning +// mutable pointers, which currently ICEs. Unleashing Miri silences the ICE. +//@ compile-flags: -Zunleash-the-miri-inside-of-you #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(const_mut_refs)] -#![deny(const_eval_mutable_ptr_in_final_value)] use std::intrinsics; const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; //~^ error: mutable pointer in final value of constant -//~| WARNING this was previously accepted by the compiler fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr index bb47adacb9f95..0dc49dc3cd864 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -1,31 +1,8 @@ error: encountered mutable pointer in final value of constant - --> $DIR/alloc_intrinsic_untyped.rs:7:1 + --> $DIR/alloc_intrinsic_untyped.rs:8:1 | LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/alloc_intrinsic_untyped.rs:4:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -Future incompatibility report: Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/alloc_intrinsic_untyped.rs:7:1 - | -LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/alloc_intrinsic_untyped.rs:4:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs index 345fc096ca15a..3cc035c66d33f 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(const_mut_refs)] use std::intrinsics; diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs index da7ab7f8ba43a..3054e79770d9f 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -1,6 +1,5 @@ #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(const_mut_refs)] // Strip out raw byte dumps to make comparison platform-independent: //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index a42c26c0a8dee..0b0d2676dd3ef 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/dealloc_intrinsic_dangling.rs:12:1 + --> $DIR/dealloc_intrinsic_dangling.rs:11:1 | LL | const _X: &'static u8 = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) @@ -10,7 +10,7 @@ LL | const _X: &'static u8 = unsafe { } error[E0080]: evaluation of constant value failed - --> $DIR/dealloc_intrinsic_dangling.rs:23:5 + --> $DIR/dealloc_intrinsic_dangling.rs:22:5 | LL | *reference | ^^^^^^^^^^ memory access failed: ALLOC1 has been freed, so this pointer is dangling diff --git a/tests/ui/consts/const-eval/issue-114994-fail.rs b/tests/ui/consts/const-eval/issue-114994-fail.rs deleted file mode 100644 index 1b9abec3571ea..0000000000000 --- a/tests/ui/consts/const-eval/issue-114994-fail.rs +++ /dev/null @@ -1,14 +0,0 @@ -// This checks that function pointer signatures that are referenced mutably -// but contain a &mut T parameter still fail in a constant context: see issue #114994. -// -//@ check-fail - -const fn use_mut_const_fn(_f: &mut fn(&mut String)) { //~ ERROR mutable references are not allowed in constant functions - () -} - -const fn use_mut_const_tuple_fn(_f: (fn(), &mut u32)) { //~ ERROR mutable references are not allowed in constant functions - -} - -fn main() {} diff --git a/tests/ui/consts/const-eval/issue-114994-fail.stderr b/tests/ui/consts/const-eval/issue-114994-fail.stderr deleted file mode 100644 index 70b224b9b4c9b..0000000000000 --- a/tests/ui/consts/const-eval/issue-114994-fail.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/issue-114994-fail.rs:6:27 - | -LL | const fn use_mut_const_fn(_f: &mut fn(&mut String)) { - | ^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/issue-114994-fail.rs:10:33 - | -LL | const fn use_mut_const_tuple_fn(_f: (fn(), &mut u32)) { - | ^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-eval/issue-114994.rs b/tests/ui/consts/const-eval/issue-114994.rs deleted file mode 100644 index 5d99f265e62be..0000000000000 --- a/tests/ui/consts/const-eval/issue-114994.rs +++ /dev/null @@ -1,18 +0,0 @@ -// This checks that function pointer signatures containing &mut T types -// work in a constant context: see issue #114994. -// -//@ check-pass - -const fn use_const_fn(_f: fn(&mut String)) { - () -} - -const fn get_some_fn() -> fn(&mut String) { - String::clear -} - -const fn some_const_fn() { - let _f: fn(&mut String) = String::clear; -} - -fn main() {} diff --git a/tests/ui/consts/const-eval/issue-65394.rs b/tests/ui/consts/const-eval/issue-65394.rs index e6639826cb26a..2304dbebc7ef2 100644 --- a/tests/ui/consts/const-eval/issue-65394.rs +++ b/tests/ui/consts/const-eval/issue-65394.rs @@ -1,11 +1,16 @@ +//@ revisions: stock precise_drops +//@[precise_drops] check-pass + // This test originated from #65394. We conservatively assume that `x` is still `LiveDrop` even // after it has been moved because a mutable reference to it exists at some point in the const body. // -// We will likely have to change this behavior before we allow `&mut` in a `const`. +// With `&mut` in `const` being stable, this surprising behavior is now observable. +// `const_precise_live_drops` fixes that. +#![cfg_attr(precise_drops, feature(const_precise_live_drops))] const _: Vec = { - let mut x = Vec::::new(); //~ ERROR destructor of - let r = &mut x; //~ ERROR mutable references are not allowed in constants + let mut x = Vec::::new(); //[stock]~ ERROR destructor of + let r = &mut x; let y = x; y }; diff --git a/tests/ui/consts/const-eval/issue-65394.stderr b/tests/ui/consts/const-eval/issue-65394.stderr deleted file mode 100644 index 1fa4da4a78be4..0000000000000 --- a/tests/ui/consts/const-eval/issue-65394.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: mutable references are not allowed in constants - --> $DIR/issue-65394.rs:8:13 - | -LL | let r = &mut x; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0493]: destructor of `Vec` cannot be evaluated at compile-time - --> $DIR/issue-65394.rs:7:9 - | -LL | let mut x = Vec::::new(); - | ^^^^^ the destructor for this type cannot be evaluated in constants -... -LL | }; - | - value is dropped here - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0493, E0658. -For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/const-eval/issue-65394.stock.stderr b/tests/ui/consts/const-eval/issue-65394.stock.stderr new file mode 100644 index 0000000000000..f33593862a763 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-65394.stock.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructor of `Vec` cannot be evaluated at compile-time + --> $DIR/issue-65394.rs:12:9 + | +LL | let mut x = Vec::::new(); + | ^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/const-eval/mod-static-with-const-fn.rs b/tests/ui/consts/const-eval/mod-static-with-const-fn.rs index b6b74e67d20cb..7de9d44305d60 100644 --- a/tests/ui/consts/const-eval/mod-static-with-const-fn.rs +++ b/tests/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -1,8 +1,6 @@ // New test for #53818: modifying static memory at compile-time is not allowed. // The test should never compile successfully -#![feature(const_mut_refs)] - use std::cell::UnsafeCell; struct Foo(UnsafeCell); diff --git a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr index 901ae1922c74e..47bfc235a1afe 100644 --- a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -1,5 +1,5 @@ error[E0080]: could not evaluate static initializer - --> $DIR/mod-static-with-const-fn.rs:16:5 + --> $DIR/mod-static-with-const-fn.rs:14:5 | LL | *FOO.0.get() = 5; | ^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer diff --git a/tests/ui/consts/const-eval/nrvo.rs b/tests/ui/consts/const-eval/nrvo.rs index 02288d8d60ce5..e37fe2d8238cf 100644 --- a/tests/ui/consts/const-eval/nrvo.rs +++ b/tests/ui/consts/const-eval/nrvo.rs @@ -4,8 +4,6 @@ // its address may be taken and it may be written to indirectly. Ensure that the const-eval // interpreter can handle this. -#![feature(const_mut_refs)] - #[inline(never)] // Try to ensure that MIR optimizations don't optimize this away. const fn init(buf: &mut [u8; 1024]) { buf[33] = 3; diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs index d6c76886853f4..1e99d84bba4bc 100644 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs @@ -1,5 +1,4 @@ // Test for the behavior described in . -#![feature(const_mut_refs)] const PARTIAL_OVERWRITE: () = { let mut p = &42; diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr index 3203ca764bb0c..1443d353848b0 100644 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/partial_ptr_overwrite.rs:8:9 + --> $DIR/partial_ptr_overwrite.rs:7:9 | LL | *(ptr as *mut u8) = 123; | ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at ALLOC0 diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 5aced5b1bd6d5..5724293f145ff 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -1,6 +1,3 @@ -#![feature(const_mut_refs, const_intrinsic_copy)] - - const MISALIGNED_LOAD: () = unsafe { let mem = [0u32; 8]; let ptr = mem.as_ptr().byte_add(1); diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index aeb46725c0642..3426a768cb607 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:7:16 + --> $DIR/raw-pointer-ub.rs:4:16 | LL | let _val = *ptr; | ^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:14:5 + --> $DIR/raw-pointer-ub.rs:11:5 | LL | *ptr = 0; | ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required @@ -20,19 +20,19 @@ note: inside `copy_nonoverlapping::` note: inside `std::ptr::const_ptr::::copy_to_nonoverlapping` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `MISALIGNED_COPY` - --> $DIR/raw-pointer-ub.rs:22:5 + --> $DIR/raw-pointer-ub.rs:19:5 | LL | y.copy_to_nonoverlapping(&mut z, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:34:16 + --> $DIR/raw-pointer-ub.rs:31:16 | LL | let _val = (*ptr).0; | ^^^^^^^^ accessing memory based on pointer with alignment 4, but alignment 16 is required error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:41:16 + --> $DIR/raw-pointer-ub.rs:38:16 | LL | let _val = *ptr; | ^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got ALLOC0 which is only 4 bytes from the end of the allocation diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs index fc7dbd5a41c34..f4f25327aaf11 100644 --- a/tests/ui/consts/const-eval/simd/insert_extract.rs +++ b/tests/ui/consts/const-eval/simd/insert_extract.rs @@ -5,10 +5,9 @@ #![stable(feature = "foo", since = "1.3.37")] #![allow(non_camel_case_types)] -#[repr(simd)] struct i8x1(i8); -#[repr(simd)] struct u16x2(u16, u16); -// Make some of them array types to ensure those also work. -#[repr(simd)] struct i8x1_arr([i8; 1]); +// repr(simd) now only supports array types +#[repr(simd)] struct i8x1([i8; 1]); +#[repr(simd)] struct u16x2([u16; 2]); #[repr(simd)] struct f32x4([f32; 4]); extern "rust-intrinsic" { @@ -20,26 +19,18 @@ extern "rust-intrinsic" { fn main() { { - const U: i8x1 = i8x1(13); + const U: i8x1 = i8x1([13]); const V: i8x1 = unsafe { simd_insert(U, 0_u32, 42_i8) }; - const X0: i8 = V.0; - const Y0: i8 = unsafe { simd_extract(V, 0) }; - assert_eq!(X0, 42); - assert_eq!(Y0, 42); - } - { - const U: i8x1_arr = i8x1_arr([13]); - const V: i8x1_arr = unsafe { simd_insert(U, 0_u32, 42_i8) }; const X0: i8 = V.0[0]; const Y0: i8 = unsafe { simd_extract(V, 0) }; assert_eq!(X0, 42); assert_eq!(Y0, 42); } { - const U: u16x2 = u16x2(13, 14); + const U: u16x2 = u16x2([13, 14]); const V: u16x2 = unsafe { simd_insert(U, 1_u32, 42_u16) }; - const X0: u16 = V.0; - const X1: u16 = V.1; + const X0: u16 = V.0[0]; + const X1: u16 = V.0[1]; const Y0: u16 = unsafe { simd_extract(V, 0) }; const Y1: u16 = unsafe { simd_extract(V, 1) }; assert_eq!(X0, 13); diff --git a/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs new file mode 100644 index 0000000000000..a2d34eaa384c9 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs @@ -0,0 +1,24 @@ +//@ check-pass + +#![allow(long_running_const_eval)] + +//@ compile-flags: -Z tiny-const-eval-limit -Z deduplicate-diagnostics=yes +const FOO: () = { + let mut i = 0; + loop { + //~^ WARN is taking a long time + //~| WARN is taking a long time + //~| WARN is taking a long time + //~| WARN is taking a long time + //~| WARN is taking a long time + if i == 1000 { + break; + } else { + i += 1; + } + } +}; + +fn main() { + FOO +} diff --git a/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr new file mode 100644 index 0000000000000..cb19c59b15bc0 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr @@ -0,0 +1,92 @@ +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: 5 warnings emitted + diff --git a/tests/ui/consts/const-eval/transmute-const.32bit.stderr b/tests/ui/consts/const-eval/transmute-const.32bit.stderr deleted file mode 100644 index 35a5cabaa6710..0000000000000 --- a/tests/ui/consts/const-eval/transmute-const.32bit.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/transmute-const.rs:4:1 - | -LL | static FOO: bool = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 1, align: 1) { - 03 │ . - } - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/transmute-const.rs b/tests/ui/consts/const-eval/transmute-const.rs index bf25b52ed66f6..1cfad00ca76df 100644 --- a/tests/ui/consts/const-eval/transmute-const.rs +++ b/tests/ui/consts/const-eval/transmute-const.rs @@ -1,4 +1,3 @@ -//@ stderr-per-bitwidth use std::mem; static FOO: bool = unsafe { mem::transmute(3u8) }; diff --git a/tests/ui/consts/const-eval/transmute-const.64bit.stderr b/tests/ui/consts/const-eval/transmute-const.stderr similarity index 95% rename from tests/ui/consts/const-eval/transmute-const.64bit.stderr rename to tests/ui/consts/const-eval/transmute-const.stderr index 35a5cabaa6710..d72289487d7bf 100644 --- a/tests/ui/consts/const-eval/transmute-const.64bit.stderr +++ b/tests/ui/consts/const-eval/transmute-const.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/transmute-const.rs:4:1 + --> $DIR/transmute-const.rs:3:1 | LL | static FOO: bool = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.rs b/tests/ui/consts/const-eval/ub-enum-overwrite.rs index 086a1001d11ca..69f1d01b2f31c 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.rs +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.rs @@ -1,5 +1,3 @@ -#![feature(const_mut_refs)] - enum E { A(u8), B, diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr index 2a133c057b3e3..315e865df93f3 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum-overwrite.rs:13:14 + --> $DIR/ub-enum-overwrite.rs:11:14 | LL | unsafe { *p } | ^^ using uninitialized data, but this operation requires initialized memory diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs index 3800abddd4240..e805ac01c9d06 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs @@ -1,7 +1,5 @@ //@ known-bug: #110395 -#![feature(const_slice_index)] - const A: [(); 5] = [(), (), (), (), ()]; // Since the indexing is on a ZST, the addresses are all fine, diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr index de96821e8b987..94aa3ee4d7a1f 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const fn `core::slice::::get_unchecked::>` in constants - --> $DIR/ub-slice-get-unchecked.rs:9:29 + --> $DIR/ub-slice-get-unchecked.rs:7:29 | LL | const B: &[()] = unsafe { A.get_unchecked(3..1) }; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.rs b/tests/ui/consts/const-eval/ub-write-through-immutable.rs index 9860b8fde4af8..d3ae2d8188486 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.rs +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.rs @@ -1,5 +1,4 @@ //! Ensure we catch UB due to writing through a shared reference. -#![feature(const_mut_refs, const_refs_to_cell)] #![allow(invalid_reference_casting)] use std::mem; diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr index dbcd35e0b8815..d30df33bc55f9 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/ub-write-through-immutable.rs:11:5 + --> $DIR/ub-write-through-immutable.rs:10:5 | LL | *ptr = 0; | ^^^^^^^^ writing through a pointer that was derived from a shared (immutable) reference error[E0080]: evaluation of constant value failed - --> $DIR/ub-write-through-immutable.rs:18:5 + --> $DIR/ub-write-through-immutable.rs:17:5 | LL | *ptr = 0; | ^^^^^^^^ writing through a pointer that was derived from a shared (immutable) reference diff --git a/tests/ui/consts/const-eval/unwind-abort.rs b/tests/ui/consts/const-eval/unwind-abort.rs index 26113e238883d..8d5ed876e4398 100644 --- a/tests/ui/consts/const-eval/unwind-abort.rs +++ b/tests/ui/consts/const-eval/unwind-abort.rs @@ -1,5 +1,3 @@ -#![feature(const_extern_fn)] - const extern "C" fn foo() { panic!() //~ ERROR evaluation of constant value failed } diff --git a/tests/ui/consts/const-eval/unwind-abort.stderr b/tests/ui/consts/const-eval/unwind-abort.stderr index d7330beca7b54..340f1dbe841fe 100644 --- a/tests/ui/consts/const-eval/unwind-abort.stderr +++ b/tests/ui/consts/const-eval/unwind-abort.stderr @@ -1,16 +1,16 @@ error[E0080]: evaluation of constant value failed - --> $DIR/unwind-abort.rs:4:5 + --> $DIR/unwind-abort.rs:2:5 | LL | panic!() - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:4:5 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:2:5 | note: inside `foo` - --> $DIR/unwind-abort.rs:4:5 + --> $DIR/unwind-abort.rs:2:5 | LL | panic!() | ^^^^^^^^ note: inside `_` - --> $DIR/unwind-abort.rs:7:15 + --> $DIR/unwind-abort.rs:5:15 | LL | const _: () = foo(); | ^^^^^ diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs index eccda49db3eb5..31c15400f84a4 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -1,5 +1,3 @@ -#![feature(const_extern_fn)] - extern "C" { fn regular_in_block(); } diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr index 5acf22e4bc66e..5d37f524e03db 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const fn `regular_in_block` in constant functions - --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 + --> $DIR/const-extern-fn-call-extern-fn.rs:7:9 | LL | regular_in_block(); | ^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | regular_in_block(); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const fn `regular` in constant functions - --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 + --> $DIR/const-extern-fn-call-extern-fn.rs:16:9 | LL | regular(); | ^^^^^^^^^ diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs index efc0a1c2fba39..73b6dd51db719 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -1,7 +1,6 @@ -#![feature(const_extern_fn)] - -const extern "C" fn ptr_cast(val: *const u8) { val as usize; } -//~^ ERROR pointers cannot be cast to integers - +const extern "C" fn ptr_cast(val: *const u8) { + val as usize; + //~^ ERROR pointers cannot be cast to integers +} fn main() {} diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 9cdeec159beeb..7c21b1b606e26 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -1,8 +1,8 @@ error: pointers cannot be cast to integers during const eval - --> $DIR/const-extern-fn-min-const-fn.rs:3:48 + --> $DIR/const-extern-fn-min-const-fn.rs:2:5 | -LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } - | ^^^^^^^^^^^^ +LL | val as usize; + | ^^^^^^^^^^^^ | = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs index 95fb9ef42603a..a77ee29382076 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs @@ -1,12 +1,18 @@ -#![feature(const_extern_fn)] - const unsafe extern "C" fn foo() -> usize { 5 } +const unsafe extern "C-unwind" fn bar() -> usize { + 5 +} + fn main() { let a: [u8; foo()]; //~^ call to unsafe function `foo` is unsafe and requires unsafe function or block foo(); //~^ ERROR call to unsafe function `foo` is unsafe and requires unsafe function or block + let b: [u8; bar()]; + //~^ call to unsafe function `bar` is unsafe and requires unsafe function or block + bar(); + //~^ ERROR call to unsafe function `bar` is unsafe and requires unsafe function or block } diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr index 6f59b2f205537..b4c779d59de51 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr @@ -1,19 +1,35 @@ error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block - --> $DIR/const-extern-fn-requires-unsafe.rs:10:5 + --> $DIR/const-extern-fn-requires-unsafe.rs:12:5 | LL | foo(); | ^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior +error[E0133]: call to unsafe function `bar` is unsafe and requires unsafe function or block + --> $DIR/const-extern-fn-requires-unsafe.rs:16:5 + | +LL | bar(); + | ^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block - --> $DIR/const-extern-fn-requires-unsafe.rs:8:17 + --> $DIR/const-extern-fn-requires-unsafe.rs:10:17 | LL | let a: [u8; foo()]; | ^^^^^ 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 +error[E0133]: call to unsafe function `bar` is unsafe and requires unsafe function or block + --> $DIR/const-extern-fn-requires-unsafe.rs:14:17 + | +LL | let b: [u8; bar()]; + | ^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn.rs b/tests/ui/consts/const-extern-fn/const-extern-fn.rs index 4b16476706449..75ffa783a117b 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn.rs +++ b/tests/ui/consts/const-extern-fn/const-extern-fn.rs @@ -1,5 +1,4 @@ //@ run-pass -#![feature(const_extern_fn)] const extern "C" fn foo1(val: u8) -> u8 { val + 1 @@ -47,6 +46,10 @@ fn main() { let _bar2_cast: unsafe extern "C" fn(bool) -> bool = bar2; unsize(&[0, 1, 2]); - unsafe { closure(); } - unsafe { use_float(); } + unsafe { + closure(); + } + unsafe { + use_float(); + } } diff --git a/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs b/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs deleted file mode 100644 index f7bed91b03787..0000000000000 --- a/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Check that `const extern fn` and `const unsafe extern fn` are feature-gated -// for certain ABIs. - -const extern fn foo1() {} -const extern "C" fn foo2() {} -const extern "Rust" fn foo3() {} -const extern "cdecl" fn foo4() {} //~ ERROR `cdecl` as a `const fn` ABI is unstable -const unsafe extern fn bar1() {} -const unsafe extern "C" fn bar2() {} -const unsafe extern "Rust" fn bar3() {} -const unsafe extern "cdecl" fn bar4() {} //~ ERROR `cdecl` as a `const fn` ABI is unstable - -fn main() {} diff --git a/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr b/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr deleted file mode 100644 index 81fb62e10a724..0000000000000 --- a/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: `cdecl` as a `const fn` ABI is unstable - --> $DIR/feature-gate-const_extern_fn.rs:7:14 - | -LL | const extern "cdecl" fn foo4() {} - | ^^^^^^^ - | - = note: see issue #64926 for more information - = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cdecl` as a `const fn` ABI is unstable - --> $DIR/feature-gate-const_extern_fn.rs:11:21 - | -LL | const unsafe extern "cdecl" fn bar4() {} - | ^^^^^^^ - | - = note: see issue #64926 for more information - = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs deleted file mode 100644 index 3a526c54dc376..0000000000000 --- a/tests/ui/consts/const-float-bits-conv.rs +++ /dev/null @@ -1,162 +0,0 @@ -//@ compile-flags: -Zmir-opt-level=0 -//@ run-pass - -#![feature(const_float_bits_conv)] -#![feature(const_float_classify)] -#![feature(f16)] -#![feature(f128)] -#![allow(unused_macro_rules)] -// Don't promote -const fn nop(x: T) -> T { x } - -macro_rules! const_assert { - ($a:expr) => { - { - const _: () = assert!($a); - assert!(nop($a)); - } - }; - ($a:expr, $b:expr) => { - { - const _: () = assert!($a == $b); - assert_eq!(nop($a), nop($b)); - } - }; -} - -fn has_broken_floats() -> bool { - // i586 targets are broken due to . - std::env::var("TARGET").is_ok_and(|v| v.contains("i586")) -} - -#[cfg(target_arch = "x86_64")] -fn f16(){ - const_assert!((1f16).to_bits(), 0x3c00); - const_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00); - const_assert!((12.5f16).to_bits(), 0x4a40); - const_assert!(u16::from_le_bytes(12.5f16.to_le_bytes()), 0x4a40); - const_assert!((1337f16).to_bits(), 0x6539); - const_assert!(u16::from_ne_bytes(1337f16.to_ne_bytes()), 0x6539); - const_assert!((-14.25f16).to_bits(), 0xcb20); - const_assert!(f16::from_bits(0x3c00), 1.0); - const_assert!(f16::from_be_bytes(0x3c00u16.to_be_bytes()), 1.0); - const_assert!(f16::from_bits(0x4a40), 12.5); - const_assert!(f16::from_le_bytes(0x4a40u16.to_le_bytes()), 12.5); - const_assert!(f16::from_bits(0x5be0), 252.0); - const_assert!(f16::from_ne_bytes(0x5be0u16.to_ne_bytes()), 252.0); - const_assert!(f16::from_bits(0xcb20), -14.25); - - // Check that NaNs roundtrip their bits regardless of signalingness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! - const QUIET_NAN: u16 = f16::NAN.to_bits() ^ 0x0155; - const SIGNALING_NAN: u16 = f16::NAN.to_bits() ^ 0x02AA; - - const_assert!(f16::from_bits(QUIET_NAN).is_nan()); - const_assert!(f16::from_bits(SIGNALING_NAN).is_nan()); - const_assert!(f16::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); - if !has_broken_floats() { - const_assert!(f16::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); - } -} - -fn f32() { - const_assert!((1f32).to_bits(), 0x3f800000); - const_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000); - const_assert!((12.5f32).to_bits(), 0x41480000); - const_assert!(u32::from_le_bytes(12.5f32.to_le_bytes()), 0x41480000); - const_assert!((1337f32).to_bits(), 0x44a72000); - const_assert!(u32::from_ne_bytes(1337f32.to_ne_bytes()), 0x44a72000); - const_assert!((-14.25f32).to_bits(), 0xc1640000); - const_assert!(f32::from_bits(0x3f800000), 1.0); - const_assert!(f32::from_be_bytes(0x3f800000u32.to_be_bytes()), 1.0); - const_assert!(f32::from_bits(0x41480000), 12.5); - const_assert!(f32::from_le_bytes(0x41480000u32.to_le_bytes()), 12.5); - const_assert!(f32::from_bits(0x44a72000), 1337.0); - const_assert!(f32::from_ne_bytes(0x44a72000u32.to_ne_bytes()), 1337.0); - const_assert!(f32::from_bits(0xc1640000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signalingness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! - const QUIET_NAN: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA; - const SIGNALING_NAN: u32 = f32::NAN.to_bits() ^ 0x0055_5555; - - const_assert!(f32::from_bits(QUIET_NAN).is_nan()); - const_assert!(f32::from_bits(SIGNALING_NAN).is_nan()); - const_assert!(f32::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); - if !has_broken_floats() { - const_assert!(f32::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); - } -} - -fn f64() { - const_assert!((1f64).to_bits(), 0x3ff0000000000000); - const_assert!(u64::from_be_bytes(1f64.to_be_bytes()), 0x3ff0000000000000); - const_assert!((12.5f64).to_bits(), 0x4029000000000000); - const_assert!(u64::from_le_bytes(12.5f64.to_le_bytes()), 0x4029000000000000); - const_assert!((1337f64).to_bits(), 0x4094e40000000000); - const_assert!(u64::from_ne_bytes(1337f64.to_ne_bytes()), 0x4094e40000000000); - const_assert!((-14.25f64).to_bits(), 0xc02c800000000000); - const_assert!(f64::from_bits(0x3ff0000000000000), 1.0); - const_assert!(f64::from_be_bytes(0x3ff0000000000000u64.to_be_bytes()), 1.0); - const_assert!(f64::from_bits(0x4029000000000000), 12.5); - const_assert!(f64::from_le_bytes(0x4029000000000000u64.to_le_bytes()), 12.5); - const_assert!(f64::from_bits(0x4094e40000000000), 1337.0); - const_assert!(f64::from_ne_bytes(0x4094e40000000000u64.to_ne_bytes()), 1337.0); - const_assert!(f64::from_bits(0xc02c800000000000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signalingness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! - const QUIET_NAN: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; - const SIGNALING_NAN: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; - - const_assert!(f64::from_bits(QUIET_NAN).is_nan()); - const_assert!(f64::from_bits(SIGNALING_NAN).is_nan()); - const_assert!(f64::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); - if !has_broken_floats() { - const_assert!(f64::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); - } -} - -#[cfg(target_arch = "x86_64")] -fn f128() { - const_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000); - const_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000); - const_assert!((12.5f128).to_bits(), 0x40029000000000000000000000000000); - const_assert!(u128::from_le_bytes(12.5f128.to_le_bytes()), 0x40029000000000000000000000000000); - const_assert!((1337f128).to_bits(), 0x40094e40000000000000000000000000); - const_assert!(u128::from_ne_bytes(1337f128.to_ne_bytes()), 0x40094e40000000000000000000000000); - const_assert!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); - const_assert!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0); - const_assert!(f128::from_be_bytes(0x3fff0000000000000000000000000000u128.to_be_bytes()), 1.0); - const_assert!(f128::from_bits(0x40029000000000000000000000000000), 12.5); - const_assert!(f128::from_le_bytes(0x40029000000000000000000000000000u128.to_le_bytes()), 12.5); - const_assert!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0); - assert_eq!(f128::from_ne_bytes(0x40094e40000000000000000000000000u128.to_ne_bytes()), 1337.0); - const_assert!(f128::from_bits(0xc002c800000000000000000000000000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signalingness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! - const QUIET_NAN: u128 = f128::NAN.to_bits() | 0x0000_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA; - const SIGNALING_NAN: u128 = f128::NAN.to_bits() ^ 0x0000_5555_5555_5555_5555_5555_5555_5555; - - const_assert!(f128::from_bits(QUIET_NAN).is_nan()); - const_assert!(f128::from_bits(SIGNALING_NAN).is_nan()); - const_assert!(f128::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); - if !has_broken_floats() { - const_assert!(f128::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); - } -} - -fn main() { - #[cfg(target_arch = "x86_64")] - { - f16(); - f128(); - } - f32(); - f64(); -} diff --git a/tests/ui/consts/const-float-classify.rs b/tests/ui/consts/const-float-classify.rs deleted file mode 100644 index c64d31a5c60ae..0000000000000 --- a/tests/ui/consts/const-float-classify.rs +++ /dev/null @@ -1,77 +0,0 @@ -//@ compile-flags: -Zmir-opt-level=0 -Znext-solver -//@ known-bug: #110395 -// FIXME(effects) run-pass - -#![feature(const_float_bits_conv)] -#![feature(const_float_classify)] -#![feature(const_trait_impl, effects)] -#![allow(incomplete_features)] - -// Don't promote -const fn nop(x: T) -> T { x } - -impl const PartialEq for bool { - fn eq(&self, _: &NonDet) -> bool { - true - } -} - -macro_rules! const_assert { - ($a:expr, $b:expr) => { - { - const _: () = assert!($a == $b); - assert!(nop($a) == nop($b)); - } - }; -} - -macro_rules! suite { - ( $( $tt:tt )* ) => { - fn f32() { - suite_inner!(f32 $($tt)*); - } - - fn f64() { - suite_inner!(f64 $($tt)*); - } - } - -} - -macro_rules! suite_inner { - ( - $ty:ident [$( $fn:ident ),*] - $val:expr => [$($out:ident),*] - - $( $tail:tt )* - ) => { - $( const_assert!($ty::$fn($val), $out); )* - suite_inner!($ty [$($fn),*] $($tail)*) - }; - - ( $ty:ident [$( $fn:ident ),*]) => {}; -} - -#[derive(Debug)] -struct NonDet; - -// The result of the `is_sign` methods are not checked for correctness, since LLVM does not -// guarantee anything about the signedness of NaNs. See -// https://github.com/rust-lang/rust/issues/55131. - -suite! { - [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] - -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] - 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] - 1.0 => [ false, false, true, true, true, false] - -1.0 => [ false, false, true, true, false, true] - 0.0 => [ false, false, true, false, true, false] - -0.0 => [ false, false, true, false, false, true] - 1.0 / 0.0 => [ false, true, false, false, true, false] - -1.0 / 0.0 => [ false, true, false, false, false, true] -} - -fn main() { - f32(); - f64(); -} diff --git a/tests/ui/consts/const-float-classify.stderr b/tests/ui/consts/const-float-classify.stderr deleted file mode 100644 index 38acb8a228104..0000000000000 --- a/tests/ui/consts/const-float-classify.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/const-float-classify.rs:13:12 - | -LL | impl const PartialEq for bool { - | ^^^^^^^^^^^^^^^^^ - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: aborting due to 1 previous error - diff --git a/tests/ui/consts/const-fn-error.rs b/tests/ui/consts/const-fn-error.rs index 50b7ce1f8c01d..42061ef0670f5 100644 --- a/tests/ui/consts/const-fn-error.rs +++ b/tests/ui/consts/const-fn-error.rs @@ -5,7 +5,6 @@ const fn f(x: usize) -> usize { for i in 0..x { //~^ ERROR cannot convert //~| ERROR `for` is not allowed in a `const fn` - //~| ERROR mutable references are not allowed in constant functions //~| ERROR cannot call non-const fn sum += i; } diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr index 14603e433c1c3..e886a0b4fe44c 100644 --- a/tests/ui/consts/const-fn-error.stderr +++ b/tests/ui/consts/const-fn-error.stderr @@ -5,7 +5,6 @@ LL | / for i in 0..x { LL | | LL | | LL | | -LL | | LL | | sum += i; LL | | } | |_____^ @@ -28,16 +27,6 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/const-fn-error.rs:5:14 - | -LL | for i in 0..x { - | ^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0015]: cannot call non-const fn ` as Iterator>::next` in constant functions --> $DIR/const-fn-error.rs:5:14 | @@ -50,7 +39,7 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0015, E0658. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-for-feature-gate.rs b/tests/ui/consts/const-for-feature-gate.rs index c834046c5b07f..d74178662b3aa 100644 --- a/tests/ui/consts/const-for-feature-gate.rs +++ b/tests/ui/consts/const-for-feature-gate.rs @@ -5,7 +5,6 @@ const _: () = { //~^ error: `for` is not allowed in a `const` //~| ERROR: cannot convert //~| ERROR: cannot call - //~| ERROR: mutable references }; fn main() {} diff --git a/tests/ui/consts/const-for-feature-gate.stderr b/tests/ui/consts/const-for-feature-gate.stderr index 0f2f912572e8d..3344611a60ca8 100644 --- a/tests/ui/consts/const-for-feature-gate.stderr +++ b/tests/ui/consts/const-for-feature-gate.stderr @@ -22,16 +22,6 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error[E0658]: mutable references are not allowed in constants - --> $DIR/const-for-feature-gate.rs:4:14 - | -LL | for _ in 0..5 {} - | ^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/const-for-feature-gate.rs:4:14 | @@ -44,7 +34,7 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0015, E0658. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-for.rs b/tests/ui/consts/const-for.rs index 8db2485355833..4f8034e73f09a 100644 --- a/tests/ui/consts/const-for.rs +++ b/tests/ui/consts/const-for.rs @@ -1,5 +1,4 @@ #![feature(const_for)] -#![feature(const_mut_refs)] const _: () = { for _ in 0..5 {} diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr index 8605fb8eef54a..2b817c2d20c8e 100644 --- a/tests/ui/consts/const-for.stderr +++ b/tests/ui/consts/const-for.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot convert `std::ops::Range` into an iterator in constants - --> $DIR/const-for.rs:5:14 + --> $DIR/const-for.rs:4:14 | LL | for _ in 0..5 {} | ^^^^ @@ -13,7 +13,7 @@ LL + #![feature(const_trait_impl)] | error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants - --> $DIR/const-for.rs:5:14 + --> $DIR/const-for.rs:4:14 | LL | for _ in 0..5 {} | ^^^^ diff --git a/tests/ui/consts/const-multi-ref.rs b/tests/ui/consts/const-multi-ref.rs deleted file mode 100644 index 7e0f1a812fd9c..0000000000000 --- a/tests/ui/consts/const-multi-ref.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Ensure that we point the user to the erroneous borrow but not to any subsequent borrows of that -// initial one. - -const _: i32 = { - let mut a = 5; - let p = &mut a; //~ ERROR mutable references are not allowed in constants - - let reborrow = {p}; - let pp = &reborrow; - let ppp = &pp; - ***ppp -}; - -const _: std::cell::Cell = { - let mut a = std::cell::Cell::new(5); - let p = &a; //~ ERROR borrowed element may contain interior mutability - - let reborrow = {p}; - let pp = &reborrow; - let ppp = &pp; - a -}; - -fn main() {} diff --git a/tests/ui/consts/const-multi-ref.stderr b/tests/ui/consts/const-multi-ref.stderr deleted file mode 100644 index 516162194cdf8..0000000000000 --- a/tests/ui/consts/const-multi-ref.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: mutable references are not allowed in constants - --> $DIR/const-multi-ref.rs:6:13 - | -LL | let p = &mut a; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/const-multi-ref.rs:16:13 - | -LL | let p = &a; - | ^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-mut-refs-crate.rs b/tests/ui/consts/const-mut-refs-crate.rs index dcc8ff370e1ec..aca3589720cc7 100644 --- a/tests/ui/consts/const-mut-refs-crate.rs +++ b/tests/ui/consts/const-mut-refs-crate.rs @@ -1,8 +1,6 @@ //@ run-pass //@ aux-build:const_mut_refs_crate.rs -#![feature(const_mut_refs)] - //! Regression test for https://github.com/rust-lang/rust/issues/79738 //! Show how we are not duplicating allocations anymore. Statics that //! copy their value from another static used to also duplicate diff --git a/tests/ui/consts/const-mut-refs/const_mut_address_of.rs b/tests/ui/consts/const-mut-refs/const_mut_address_of.rs index 437bdc88722c0..e88a01ec765f5 100644 --- a/tests/ui/consts/const-mut-refs/const_mut_address_of.rs +++ b/tests/ui/consts/const-mut-refs/const_mut_address_of.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(const_mut_refs)] struct Foo { x: usize diff --git a/tests/ui/consts/const-mut-refs/const_mut_refs.rs b/tests/ui/consts/const-mut-refs/const_mut_refs.rs index 1b3091c8dba5d..2553ad3199f65 100644 --- a/tests/ui/consts/const-mut-refs/const_mut_refs.rs +++ b/tests/ui/consts/const-mut-refs/const_mut_refs.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(const_mut_refs)] use std::sync::Mutex; diff --git a/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs deleted file mode 100644 index ce9be4ac5c2af..0000000000000 --- a/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - foo(&mut 5); -} - -const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references - *x + 1 - -} diff --git a/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr b/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr deleted file mode 100644 index 212d172fe1316..0000000000000 --- a/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/feature-gate-const_mut_refs.rs:5:14 - | -LL | const fn foo(x: &mut i32) -> i32 { - | ^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.rs b/tests/ui/consts/const-mut-refs/issue-76510.rs index 685e3a129c25e..6ebbd4e50f6df 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.rs +++ b/tests/ui/consts/const-mut-refs/issue-76510.rs @@ -2,7 +2,6 @@ use std::mem::{transmute, ManuallyDrop}; const S: &'static mut str = &mut " hello "; //~^ ERROR: mutable references are not allowed in the final value of constants -//~| ERROR: mutation through a reference is not allowed in constants const fn trigger() -> [(); unsafe { let s = transmute::<(*const u8, usize), &ManuallyDrop>((S.as_ptr(), 3)); diff --git a/tests/ui/consts/const-mut-refs/issue-76510.stderr b/tests/ui/consts/const-mut-refs/issue-76510.stderr index ab4487026cf4b..aff86e83578d7 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.stderr +++ b/tests/ui/consts/const-mut-refs/issue-76510.stderr @@ -4,17 +4,6 @@ error[E0764]: mutable references are not allowed in the final value of constants LL | const S: &'static mut str = &mut " hello "; | ^^^^^^^^^^^^^^ -error[E0658]: mutation through a reference is not allowed in constants - --> $DIR/issue-76510.rs:3:29 - | -LL | const S: &'static mut str = &mut " hello "; - | ^^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0658, E0764. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0764`. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs index 10339ee6798e8..af7463e6574ff 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs @@ -1,4 +1,9 @@ -#![feature(const_mut_refs)] +//@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +//@ normalize-stderr-test: "( 0x[0-9a-f][0-9a-f] │)? ([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> " HEX_DUMP" +//@ normalize-stderr-test: "HEX_DUMP\s*\n\s*HEX_DUMP" -> "HEX_DUMP" + +use std::cell::UnsafeCell; +use std::mem; const NULL: *mut i32 = std::ptr::null_mut(); const A: *const i32 = &4; @@ -17,6 +22,11 @@ const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR temporary value dropped wh const fn helper(x: &mut i32) -> Option<&mut i32> { Some(x) } const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped while borrowed +// Not ok, since it points to read-only memory. +const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; +//~^ ERROR undefined behavior to use this value +//~| pointing to read-only memory + // Ok, because no references to mutable data exist here, since the `{}` moves // its value and then takes a reference to that. const C: *const i32 = &{ @@ -25,7 +35,14 @@ const C: *const i32 = &{ x }; -use std::cell::UnsafeCell; +// Still ok, since `x` will be moved before the final pointer is crated, +// so `_ref` doesn't actually point to the memory that escapes. +const C_NO: *const i32 = &{ + let mut x = 42; + let _ref = &mut x; + x +}; + struct NotAMutex(UnsafeCell); unsafe impl Sync for NotAMutex {} diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index 00a8421076b88..4f50ae3231290 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -1,11 +1,11 @@ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:9:21 + --> $DIR/mut_ref_in_final.rs:14:21 | LL | const B: *mut i32 = &mut 4; | ^^^^^^ error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:15:40 + --> $DIR/mut_ref_in_final.rs:20:40 | LL | const B3: Option<&mut i32> = Some(&mut 42); | ----------^^- @@ -15,7 +15,7 @@ LL | const B3: Option<&mut i32> = Some(&mut 42); | using this value as a constant requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:18:42 + --> $DIR/mut_ref_in_final.rs:23:42 | LL | const B4: Option<&mut i32> = helper(&mut 42); | ------------^^- @@ -24,8 +24,19 @@ LL | const B4: Option<&mut i32> = helper(&mut 42); | | creates a temporary value which is freed while still in use | using this value as a constant requires that borrow lasts for `'static` +error[E0080]: it is undefined behavior to use this value + --> $DIR/mut_ref_in_final.rs:26:1 + | +LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:33:65 + --> $DIR/mut_ref_in_final.rs:50:65 | LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -35,7 +46,7 @@ LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a constant requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:36:67 + --> $DIR/mut_ref_in_final.rs:53:67 | LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -45,7 +56,7 @@ LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:39:71 + --> $DIR/mut_ref_in_final.rs:56:71 | LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -55,30 +66,30 @@ LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a static requires that borrow lasts for `'static` error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/mut_ref_in_final.rs:52:53 + --> $DIR/mut_ref_in_final.rs:69:53 | LL | static RAW_MUT_CAST_S: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/mut_ref_in_final.rs:54:54 + --> $DIR/mut_ref_in_final.rs:71:54 | LL | static RAW_MUT_COERCE_S: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:56:52 + --> $DIR/mut_ref_in_final.rs:73:52 | LL | const RAW_MUT_CAST_C: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:58:53 + --> $DIR/mut_ref_in_final.rs:75:53 | LL | const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0716, E0764. -For more information about an error, try `rustc --explain E0716`. +Some errors have detailed explanations: E0080, E0716, E0764. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs index e208845e74702..7bf178484cc76 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -1,7 +1,7 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "( 0x[0-9a-f][0-9a-f] │)? ([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> " HEX_DUMP" //@ normalize-stderr-test: "HEX_DUMP\s*\n\s*HEX_DUMP" -> "HEX_DUMP" -#![feature(const_mut_refs, const_refs_to_static)] +#![feature(const_refs_to_static)] use std::sync::Mutex; diff --git a/tests/ui/consts/const-promoted-opaque.atomic.stderr b/tests/ui/consts/const-promoted-opaque.atomic.stderr index 1f2a7753ff543..b9d5cbf801a80 100644 --- a/tests/ui/consts/const-promoted-opaque.atomic.stderr +++ b/tests/ui/consts/const-promoted-opaque.atomic.stderr @@ -1,30 +1,20 @@ -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/const-promoted-opaque.rs:28:25 - | -LL | let _: &'static _ = &FOO; - | ^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0493]: destructor of `helper::Foo` cannot be evaluated at compile-time --> $DIR/const-promoted-opaque.rs:28:26 | LL | let _: &'static _ = &FOO; | ^^^ the destructor for this type cannot be evaluated in constants -... +LL | LL | }; | - value is dropped here error[E0492]: constants cannot refer to interior mutable data - --> $DIR/const-promoted-opaque.rs:33:19 + --> $DIR/const-promoted-opaque.rs:32:19 | LL | const BAZ: &Foo = &FOO; | ^^^^ this borrow of an interior mutable value may end up in the final value error[E0716]: temporary value dropped while borrowed - --> $DIR/const-promoted-opaque.rs:37:26 + --> $DIR/const-promoted-opaque.rs:36:26 | LL | let _: &'static _ = &FOO; | ---------- ^^^ creates a temporary value which is freed while still in use @@ -34,7 +24,7 @@ LL | LL | } | - temporary value is freed at the end of this statement -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0492, E0493, E0658, E0716. +Some errors have detailed explanations: E0492, E0493, E0716. For more information about an error, try `rustc --explain E0492`. diff --git a/tests/ui/consts/const-promoted-opaque.rs b/tests/ui/consts/const-promoted-opaque.rs index 303618df9df06..bb33e92778aa9 100644 --- a/tests/ui/consts/const-promoted-opaque.rs +++ b/tests/ui/consts/const-promoted-opaque.rs @@ -27,7 +27,6 @@ use helper::*; const BAR: () = { let _: &'static _ = &FOO; //[string,atomic]~^ ERROR: destructor of `helper::Foo` cannot be evaluated at compile-time - //[atomic]~| ERROR: cannot borrow here }; const BAZ: &Foo = &FOO; diff --git a/tests/ui/consts/const-promoted-opaque.string.stderr b/tests/ui/consts/const-promoted-opaque.string.stderr index fa1dbb05d175d..33e5f426448ca 100644 --- a/tests/ui/consts/const-promoted-opaque.string.stderr +++ b/tests/ui/consts/const-promoted-opaque.string.stderr @@ -3,12 +3,12 @@ error[E0493]: destructor of `helper::Foo` cannot be evaluated at compile-time | LL | let _: &'static _ = &FOO; | ^^^ the destructor for this type cannot be evaluated in constants -... +LL | LL | }; | - value is dropped here error[E0716]: temporary value dropped while borrowed - --> $DIR/const-promoted-opaque.rs:37:26 + --> $DIR/const-promoted-opaque.rs:36:26 | LL | let _: &'static _ = &FOO; | ---------- ^^^ creates a temporary value which is freed while still in use diff --git a/tests/ui/consts/const-ptr-is-null.rs b/tests/ui/consts/const-ptr-is-null.rs new file mode 100644 index 0000000000000..82c293c0ad6e3 --- /dev/null +++ b/tests/ui/consts/const-ptr-is-null.rs @@ -0,0 +1,20 @@ +#![feature(const_ptr_is_null)] +use std::ptr; + +const IS_NULL: () = { + assert!(ptr::null::().is_null()); +}; +const IS_NOT_NULL: () = { + assert!(!ptr::null::().wrapping_add(1).is_null()); +}; + +const MAYBE_NULL: () = { + let x = 15; + let ptr = &x as *const i32; + // This one is still unambiguous... + assert!(!ptr.is_null()); + // but once we shift outside the allocation, we might become null. + assert!(!ptr.wrapping_sub(512).is_null()); //~inside `MAYBE_NULL` +}; + +fn main() {} diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr new file mode 100644 index 0000000000000..20e44a1401f9e --- /dev/null +++ b/tests/ui/consts/const-ptr-is-null.stderr @@ -0,0 +1,19 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: the evaluated program panicked at 'null-ness of this pointer cannot be determined in const context', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | +note: inside `std::ptr::const_ptr::::is_null::const_impl` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `std::ptr::const_ptr::::is_null` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `MAYBE_NULL` + --> $DIR/const-ptr-is-null.rs:17:14 + | +LL | assert!(!ptr.wrapping_sub(512).is_null()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-ref-to-static-linux-vtable.rs b/tests/ui/consts/const-ref-to-static-linux-vtable.rs index 9325746c1e725..b9d29d0c1f43e 100644 --- a/tests/ui/consts/const-ref-to-static-linux-vtable.rs +++ b/tests/ui/consts/const-ref-to-static-linux-vtable.rs @@ -1,6 +1,6 @@ //@check-pass //! This is the reduced version of the "Linux kernel vtable" use-case. -#![feature(const_mut_refs, const_refs_to_static)] +#![feature(const_refs_to_static)] use std::ptr::addr_of_mut; #[repr(C)] diff --git a/tests/ui/consts/const-suggest-feature.rs b/tests/ui/consts/const-suggest-feature.rs index d76d01a3d5ed8..0c94036897610 100644 --- a/tests/ui/consts/const-suggest-feature.rs +++ b/tests/ui/consts/const-suggest-feature.rs @@ -1,7 +1,10 @@ +//@compile-flags: --edition 2018 +use std::cell::Cell; + const WRITE: () = unsafe { - *std::ptr::null_mut() = 0; - //~^ ERROR dereferencing raw mutable pointers in constants is unstable - //~| HELP add `#![feature(const_mut_refs)]` to the crate attributes to enable + let x = async { 13 }; + //~^ ERROR `async` blocks + //~| HELP add `#![feature(const_async_blocks)]` to the crate attributes to enable }; fn main() {} diff --git a/tests/ui/consts/const-suggest-feature.stderr b/tests/ui/consts/const-suggest-feature.stderr index faa1226ca2540..398b21caeb0cf 100644 --- a/tests/ui/consts/const-suggest-feature.stderr +++ b/tests/ui/consts/const-suggest-feature.stderr @@ -1,11 +1,11 @@ -error[E0658]: dereferencing raw mutable pointers in constants is unstable - --> $DIR/const-suggest-feature.rs:2:5 +error[E0658]: `async` blocks are not allowed in constants + --> $DIR/const-suggest-feature.rs:5:13 | -LL | *std::ptr::null_mut() = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = async { 13 }; + | ^^^^^^^^^^^^ | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = note: see issue #85368 for more information + = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr index 87b94a7be67e2..9a1b84dbf09f5 100644 --- a/tests/ui/consts/const_let_assign2.stderr +++ b/tests/ui/consts/const_let_assign2.stderr @@ -4,14 +4,13 @@ warning: creating a mutable reference to mutable static is discouraged LL | let ptr = unsafe { &mut BB }; | ^^^^^^^ mutable reference to mutable static | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior + = note: for more information, see + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of_mut!` instead to create a raw pointer +help: use `&raw mut` instead to create a raw pointer | -LL | let ptr = unsafe { addr_of_mut!(BB) }; - | ~~~~~~~~~~~~~ + +LL | let ptr = unsafe { &raw mut BB }; + | ~~~~~~~~ warning: 1 warning emitted diff --git a/tests/ui/consts/const_let_assign3.rs b/tests/ui/consts/const_let_assign3.rs index 1f68de8eed09b..7928b2766e9ad 100644 --- a/tests/ui/consts/const_let_assign3.rs +++ b/tests/ui/consts/const_let_assign3.rs @@ -1,23 +1,24 @@ +//@ check-pass + struct S { state: u32, } impl S { const fn foo(&mut self, x: u32) { - //~^ ERROR mutable reference self.state = x; } } const FOO: S = { let mut s = S { state: 42 }; - s.foo(3); //~ ERROR mutable reference + s.foo(3); s }; type Array = [u32; { let mut x = 2; - let y = &mut x; //~ ERROR mutable reference + let y = &mut x; *y = 42; *y }]; diff --git a/tests/ui/consts/const_let_assign3.stderr b/tests/ui/consts/const_let_assign3.stderr deleted file mode 100644 index ae890131715e9..0000000000000 --- a/tests/ui/consts/const_let_assign3.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0658]: mutable references are not allowed in constants - --> $DIR/const_let_assign3.rs:14:5 - | -LL | s.foo(3); - | ^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/const_let_assign3.rs:6:18 - | -LL | const fn foo(&mut self, x: u32) { - | ^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constants - --> $DIR/const_let_assign3.rs:20:13 - | -LL | let y = &mut x; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const_refs_to_static_fail.rs b/tests/ui/consts/const_refs_to_static_fail.rs index 806aa5f8f6fba..a69902c34392d 100644 --- a/tests/ui/consts/const_refs_to_static_fail.rs +++ b/tests/ui/consts/const_refs_to_static_fail.rs @@ -1,6 +1,6 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" -#![feature(const_refs_to_static, const_mut_refs, sync_unsafe_cell)] +#![feature(const_refs_to_static, sync_unsafe_cell)] use std::cell::SyncUnsafeCell; static S: SyncUnsafeCell = SyncUnsafeCell::new(0); diff --git a/tests/ui/consts/control-flow/loop.rs b/tests/ui/consts/control-flow/loop.rs index 5b7f8d29df7c6..f8d9f3ddb9b2b 100644 --- a/tests/ui/consts/control-flow/loop.rs +++ b/tests/ui/consts/control-flow/loop.rs @@ -52,14 +52,12 @@ const _: i32 = { for i in 0..4 { //~ ERROR `for` is not allowed in a `const` //~^ ERROR: cannot call - //~| ERROR: mutable references //~| ERROR: cannot convert x += i; } for i in 0..4 { //~ ERROR `for` is not allowed in a `const` //~^ ERROR: cannot call - //~| ERROR: mutable references //~| ERROR: cannot convert x += i; } diff --git a/tests/ui/consts/control-flow/loop.stderr b/tests/ui/consts/control-flow/loop.stderr index 2815b888ccd97..13d5d3e0b55c8 100644 --- a/tests/ui/consts/control-flow/loop.stderr +++ b/tests/ui/consts/control-flow/loop.stderr @@ -4,7 +4,6 @@ error[E0658]: `for` is not allowed in a `const` LL | / for i in 0..4 { LL | | LL | | -LL | | LL | | x += i; LL | | } | |_____^ @@ -14,12 +13,11 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `for` is not allowed in a `const` - --> $DIR/loop.rs:60:5 + --> $DIR/loop.rs:59:5 | LL | / for i in 0..4 { LL | | LL | | -LL | | LL | | x += i; LL | | } | |_____^ @@ -42,16 +40,6 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error[E0658]: mutable references are not allowed in constants - --> $DIR/loop.rs:53:14 - | -LL | for i in 0..4 { - | ^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/loop.rs:53:14 | @@ -65,7 +53,7 @@ LL + #![feature(const_trait_impl)] | error[E0015]: cannot convert `std::ops::Range` into an iterator in constants - --> $DIR/loop.rs:60:14 + --> $DIR/loop.rs:59:14 | LL | for i in 0..4 { | ^^^^ @@ -78,18 +66,8 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error[E0658]: mutable references are not allowed in constants - --> $DIR/loop.rs:60:14 - | -LL | for i in 0..4 { - | ^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants - --> $DIR/loop.rs:60:14 + --> $DIR/loop.rs:59:14 | LL | for i in 0..4 { | ^^^^ @@ -100,7 +78,7 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0015, E0658. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index e3f43ce203754..805c03da546ab 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -2,7 +2,6 @@ // ignore-tidy-linelength #![feature(intrinsics, staged_api)] -#![feature(const_mut_refs)] use std::mem; extern "rust-intrinsic" { diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index 2dbb471131ecf..da8139129c9f3 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -1,23 +1,23 @@ error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:29:5 + --> $DIR/copy-intrinsic.rs:28:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:38:5 + --> $DIR/copy-intrinsic.rs:37:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:45:5 + --> $DIR/copy-intrinsic.rs:44:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:51:5 + --> $DIR/copy-intrinsic.rs:50:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` diff --git a/tests/ui/consts/fn_trait_refs.rs b/tests/ui/consts/fn_trait_refs.rs index e9444e5c09481..4defe4dedc784 100644 --- a/tests/ui/consts/fn_trait_refs.rs +++ b/tests/ui/consts/fn_trait_refs.rs @@ -4,9 +4,7 @@ #![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; diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index 42a6026cfbad3..218c90f89a9e2 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -5,25 +5,25 @@ LL | #![feature(const_fn_trait_ref_impls)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0635]: unknown feature `const_cmp` - --> $DIR/fn_trait_refs.rs:8:12 + --> $DIR/fn_trait_refs.rs:7:12 | LL | #![feature(const_cmp)] | ^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:15:15 + --> $DIR/fn_trait_refs.rs:13:15 | LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:15:31 + --> $DIR/fn_trait_refs.rs:13:31 | LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:15:15 + --> $DIR/fn_trait_refs.rs:13:15 | LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^ @@ -31,19 +31,19 @@ LL | T: ~const Fn<()> + ~const Destruct, = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:22:15 + --> $DIR/fn_trait_refs.rs:20:15 | LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:22:34 + --> $DIR/fn_trait_refs.rs:20:34 | LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:22:15 + --> $DIR/fn_trait_refs.rs:20:15 | LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^^ @@ -51,13 +51,13 @@ LL | T: ~const FnMut<()> + ~const Destruct, = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:29:15 + --> $DIR/fn_trait_refs.rs:27:15 | LL | T: ~const FnOnce<()>, | ^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:29:15 + --> $DIR/fn_trait_refs.rs:27:15 | LL | T: ~const FnOnce<()>, | ^^^^^^^^^^ @@ -65,19 +65,19 @@ LL | T: ~const FnOnce<()>, = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:36:15 + --> $DIR/fn_trait_refs.rs:34:15 | LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:36:31 + --> $DIR/fn_trait_refs.rs:34:31 | LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:36:15 + --> $DIR/fn_trait_refs.rs:34:15 | LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^ @@ -85,19 +85,19 @@ LL | T: ~const Fn<()> + ~const Destruct, = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:50:15 + --> $DIR/fn_trait_refs.rs:48:15 | LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:50:34 + --> $DIR/fn_trait_refs.rs:48:34 | LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:50:15 + --> $DIR/fn_trait_refs.rs:48:15 | LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL | T: ~const FnMut<()> + ~const Destruct, = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const operator in constants - --> $DIR/fn_trait_refs.rs:72:17 + --> $DIR/fn_trait_refs.rs:70:17 | LL | assert!(test_one == (1, 1, 1)); | ^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL + #![feature(effects)] | error[E0015]: cannot call non-const operator in constants - --> $DIR/fn_trait_refs.rs:75:17 + --> $DIR/fn_trait_refs.rs:73:17 | LL | assert!(test_two == (2, 2)); | ^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL + #![feature(effects)] | error[E0015]: cannot call non-const closure in constant functions - --> $DIR/fn_trait_refs.rs:17:5 + --> $DIR/fn_trait_refs.rs:15:5 | LL | f() | ^^^ @@ -145,7 +145,7 @@ LL + #![feature(effects)] | error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/fn_trait_refs.rs:13:23 + --> $DIR/fn_trait_refs.rs:11:23 | LL | const fn tester_fn(f: T) -> T::Output | ^ the destructor for this type cannot be evaluated in constant functions @@ -154,7 +154,7 @@ LL | } | - value is dropped here error[E0015]: cannot call non-const closure in constant functions - --> $DIR/fn_trait_refs.rs:24:5 + --> $DIR/fn_trait_refs.rs:22:5 | LL | f() | ^^^ @@ -170,7 +170,7 @@ LL + #![feature(effects)] | error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/fn_trait_refs.rs:20:27 + --> $DIR/fn_trait_refs.rs:18:27 | LL | const fn tester_fn_mut(mut f: T) -> T::Output | ^^^^^ the destructor for this type cannot be evaluated in constant functions @@ -179,7 +179,7 @@ LL | } | - value is dropped here error[E0015]: cannot call non-const closure in constant functions - --> $DIR/fn_trait_refs.rs:31:5 + --> $DIR/fn_trait_refs.rs:29:5 | LL | f() | ^^^ @@ -195,7 +195,7 @@ LL + #![feature(effects)] | error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/fn_trait_refs.rs:34:21 + --> $DIR/fn_trait_refs.rs:32:21 | LL | const fn test_fn(mut f: T) -> (T::Output, T::Output, T::Output) | ^^^^^ the destructor for this type cannot be evaluated in constant functions @@ -204,7 +204,7 @@ LL | } | - value is dropped here error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/fn_trait_refs.rs:48:25 + --> $DIR/fn_trait_refs.rs:46:25 | LL | const fn test_fn_mut(mut f: T) -> (T::Output, T::Output) | ^^^^^ the destructor for this type cannot be evaluated in constant functions diff --git a/tests/ui/consts/future-incompat-mutable-in-final-value-issue-121610.rs b/tests/ui/consts/future-incompat-mutable-in-final-value-issue-121610.rs deleted file mode 100644 index ca119f831b145..0000000000000 --- a/tests/ui/consts/future-incompat-mutable-in-final-value-issue-121610.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ check-pass -use std::cell::Cell; - -pub enum JsValue { - Undefined, - Object(Cell), -} - -impl ::std::ops::Drop for JsValue { - fn drop(&mut self) {} -} - -const UNDEFINED: &JsValue = &JsValue::Undefined; - //~^ WARN encountered mutable pointer in final value of constant - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -fn main() { -} diff --git a/tests/ui/consts/future-incompat-mutable-in-final-value-issue-121610.stderr b/tests/ui/consts/future-incompat-mutable-in-final-value-issue-121610.stderr deleted file mode 100644 index 85de4e7ff32e1..0000000000000 --- a/tests/ui/consts/future-incompat-mutable-in-final-value-issue-121610.stderr +++ /dev/null @@ -1,23 +0,0 @@ -warning: encountered mutable pointer in final value of constant - --> $DIR/future-incompat-mutable-in-final-value-issue-121610.rs:13:1 - | -LL | const UNDEFINED: &JsValue = &JsValue::Undefined; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - = note: `#[warn(const_eval_mutable_ptr_in_final_value)]` on by default - -warning: 1 warning emitted - -Future incompatibility report: Future breakage diagnostic: -warning: encountered mutable pointer in final value of constant - --> $DIR/future-incompat-mutable-in-final-value-issue-121610.rs:13:1 - | -LL | const UNDEFINED: &JsValue = &JsValue::Undefined; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - = note: `#[warn(const_eval_mutable_ptr_in_final_value)]` on by default - diff --git a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr index e9e9f1a4545d9..fb06643df8598 100644 --- a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/interior-mut-const-via-union.rs:35:1 + --> $DIR/interior-mut-const-via-union.rs:34:1 | LL | fn main() { | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory @@ -10,13 +10,13 @@ LL | fn main() { } note: erroneous constant encountered - --> $DIR/interior-mut-const-via-union.rs:37:25 + --> $DIR/interior-mut-const-via-union.rs:36:25 | LL | let _: &'static _ = &C; | ^^ note: erroneous constant encountered - --> $DIR/interior-mut-const-via-union.rs:37:25 + --> $DIR/interior-mut-const-via-union.rs:36:25 | LL | let _: &'static _ = &C; | ^^ diff --git a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr index 9cc98975ca9b5..f39ebe0afbd23 100644 --- a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/interior-mut-const-via-union.rs:35:1 + --> $DIR/interior-mut-const-via-union.rs:34:1 | LL | fn main() { | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory @@ -10,13 +10,13 @@ LL | fn main() { } note: erroneous constant encountered - --> $DIR/interior-mut-const-via-union.rs:37:25 + --> $DIR/interior-mut-const-via-union.rs:36:25 | LL | let _: &'static _ = &C; | ^^ note: erroneous constant encountered - --> $DIR/interior-mut-const-via-union.rs:37:25 + --> $DIR/interior-mut-const-via-union.rs:36:25 | LL | let _: &'static _ = &C; | ^^ diff --git a/tests/ui/consts/interior-mut-const-via-union.rs b/tests/ui/consts/interior-mut-const-via-union.rs index 20485b90bf7aa..6d40a9ba850eb 100644 --- a/tests/ui/consts/interior-mut-const-via-union.rs +++ b/tests/ui/consts/interior-mut-const-via-union.rs @@ -3,7 +3,6 @@ // //@ build-fail //@ stderr-per-bitwidth -#![feature(const_mut_refs)] use std::cell::Cell; use std::mem::ManuallyDrop; diff --git a/tests/ui/consts/issue-116186.rs b/tests/ui/consts/issue-116186.rs index a77c38c64dc57..8bfb47629e7f4 100644 --- a/tests/ui/consts/issue-116186.rs +++ b/tests/ui/consts/issue-116186.rs @@ -4,7 +4,7 @@ fn something(path: [usize; N]) -> impl Clone { //~^ ERROR cannot find value `N` in this scope match path { - [] => 0, //~ ERROR cannot pattern-match on an array without a fixed length + [] => 0, _ => 1, }; } diff --git a/tests/ui/consts/issue-116186.stderr b/tests/ui/consts/issue-116186.stderr index e6eae2d9f55ef..46931f79dd0cb 100644 --- a/tests/ui/consts/issue-116186.stderr +++ b/tests/ui/consts/issue-116186.stderr @@ -9,13 +9,6 @@ help: you might be missing a const parameter LL | fn something(path: [usize; N]) -> impl Clone { | +++++++++++++++++++++ -error[E0730]: cannot pattern-match on an array without a fixed length - --> $DIR/issue-116186.rs:7:9 - | -LL | [] => 0, - | ^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0425, E0730. -For more information about an error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 33347d8df622a..52f8c9bf149a6 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -6,6 +6,5 @@ const C1: &'static mut [usize] = &mut []; static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; //~^ ERROR: referencing statics in constants -//~| ERROR: mutable references are not allowed fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index e755e5601a87d..57fcb1c7e9a52 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -16,17 +16,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. = help: to fix this, the value can be extracted to a `const` and then used. -error[E0658]: mutable references are not allowed in constants - --> $DIR/issue-17718-const-bad-values.rs:7:41 - | -LL | const C2: &'static mut usize = unsafe { &mut S }; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0658, E0764. For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/issue-36163.stderr b/tests/ui/consts/issue-36163.stderr index 8a7a0981f4154..52d3e003f0ac9 100644 --- a/tests/ui/consts/issue-36163.stderr +++ b/tests/ui/consts/issue-36163.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::{constant#0}` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... +note: ...which requires const-evaluating + checking `Foo::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, @@ -19,7 +19,7 @@ note: ...which requires const-evaluating + checking `A`... | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^ - = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::{constant#0}`, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/issue-36163.rs:3:1 | diff --git a/tests/ui/consts/issue-69488.rs b/tests/ui/consts/issue-69488.rs index 35071999111f5..d528d6a88de60 100644 --- a/tests/ui/consts/issue-69488.rs +++ b/tests/ui/consts/issue-69488.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(const_ptr_write)] -#![feature(const_mut_refs)] // Or, equivalently: `MaybeUninit`. pub union BagOfBits { diff --git a/tests/ui/consts/issue-94371.rs b/tests/ui/consts/issue-94371.rs index 3484437e57173..ad9ee9a5a3ef4 100644 --- a/tests/ui/consts/issue-94371.rs +++ b/tests/ui/consts/issue-94371.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(const_swap)] -#![feature(const_mut_refs)] #[repr(C)] struct Demo(u64, bool, u64, u32, u64, u64, u64); diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 00f5c3251e0a9..56c4b6ea36f6a 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -1,6 +1,6 @@ //@ known-bug: #103507 -#![feature(const_trait_impl, const_mut_refs)] +#![feature(const_trait_impl)] struct Foo<'a> { bar: &'a mut Vec, diff --git a/tests/ui/consts/min_const_fn/address_of.rs b/tests/ui/consts/min_const_fn/address_of.rs deleted file mode 100644 index dc481e17ba38e..0000000000000 --- a/tests/ui/consts/min_const_fn/address_of.rs +++ /dev/null @@ -1,15 +0,0 @@ -const fn mutable_address_of_in_const() { - let mut a = 0; - let b = &raw mut a; //~ ERROR mutable pointer -} - -struct X; - -impl X { - const fn inherent_mutable_address_of_in_const() { - let mut a = 0; - let b = &raw mut a; //~ ERROR mutable pointer - } -} - -fn main() {} diff --git a/tests/ui/consts/min_const_fn/address_of.stderr b/tests/ui/consts/min_const_fn/address_of.stderr deleted file mode 100644 index dd6fe6486d49c..0000000000000 --- a/tests/ui/consts/min_const_fn/address_of.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: raw mutable pointers are not allowed in constant functions - --> $DIR/address_of.rs:3:13 - | -LL | let b = &raw mut a; - | ^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: raw mutable pointers are not allowed in constant functions - --> $DIR/address_of.rs:11:17 - | -LL | let b = &raw mut a; - | ^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn.rs b/tests/ui/consts/min_const_fn/min_const_fn.rs index f7663f6044eef..ed5aa40b66c38 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn.rs @@ -37,34 +37,22 @@ impl Foo { const fn into_inner(self) -> T { self.0 } //~ destructor of const fn get(&self) -> &T { &self.0 } const fn get_mut(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references - //~| mutable references - //~| mutable references } impl<'a, T> Foo { const fn new_lt(t: T) -> Self { Foo(t) } const fn into_inner_lt(self) -> T { self.0 } //~ destructor of - const fn get_lt(&'a self) -> &T { &self.0 } //~ WARNING elided lifetime has a name - const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } //~ WARNING elided lifetime has a name - //~^ mutable references - //~| mutable references - //~| mutable references + const fn get_lt(&self) -> &T { &self.0 } + const fn get_mut_lt(&mut self) -> &mut T { &mut self.0 } } impl Foo { const fn new_s(t: T) -> Self { Foo(t) } const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructor const fn get_s(&self) -> &T { &self.0 } const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references - //~| mutable references - //~| mutable references } impl Foo { const fn get_sq(&self) -> &T { &self.0 } const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references - //~| mutable references - //~| mutable references } @@ -98,7 +86,6 @@ const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } //~^ ERROR pointers cannot be cast to integers const fn foo30_6() -> bool { let x = true; x } const fn inc(x: &mut i32) { *x += 1 } -//~^ ERROR mutable references // ok const fn foo36(a: bool, b: bool) -> bool { a && b } diff --git a/tests/ui/consts/min_const_fn/min_const_fn.stderr b/tests/ui/consts/min_const_fn/min_const_fn.stderr index 4b348a182b87f..c02f8c76d4418 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn.stderr @@ -1,23 +1,3 @@ -warning: elided lifetime has a name - --> $DIR/min_const_fn.rs:47:34 - | -LL | impl<'a, T> Foo { - | -- lifetime `'a` declared here -... -LL | const fn get_lt(&'a self) -> &T { &self.0 } - | ^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - -warning: elided lifetime has a name - --> $DIR/min_const_fn.rs:48:42 - | -LL | impl<'a, T> Foo { - | -- lifetime `'a` declared here -... -LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } - | ^ this elided lifetime gets resolved as `'a` - error[E0493]: destructor of `Foo` cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:37:25 | @@ -26,144 +6,24 @@ LL | const fn into_inner(self) -> T { self.0 } | | | the destructor for this type cannot be evaluated in constant functions -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:39:22 - | -LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:39:36 - | -LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:39:45 - | -LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0493]: destructor of `Foo` cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:46:28 + --> $DIR/min_const_fn.rs:43:28 | LL | const fn into_inner_lt(self) -> T { self.0 } | ^^^^ - value is dropped here | | | the destructor for this type cannot be evaluated in constant functions -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:48:25 - | -LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } - | ^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:48:42 - | -LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:48:51 - | -LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } - | ^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0493]: destructor of `Foo` cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:55:27 + --> $DIR/min_const_fn.rs:49:27 | LL | const fn into_inner_s(self) -> T { self.0 } | ^^^^ - value is dropped here | | | the destructor for this type cannot be evaluated in constant functions -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:57:24 - | -LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:57:38 - | -LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:57:47 - | -LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:64:25 - | -LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:64:39 - | -LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:64:48 - | -LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: referencing statics in constant functions is unstable - --> $DIR/min_const_fn.rs:89:27 + --> $DIR/min_const_fn.rs:77:27 | LL | const fn foo25() -> u32 { BAR } | ^^^ @@ -175,7 +35,7 @@ LL | const fn foo25() -> u32 { BAR } = help: to fix this, the value can be extracted to a `const` and then used. error[E0658]: referencing statics in constant functions is unstable - --> $DIR/min_const_fn.rs:90:37 + --> $DIR/min_const_fn.rs:78:37 | LL | const fn foo26() -> &'static u32 { &BAR } | ^^^ @@ -187,7 +47,7 @@ LL | const fn foo26() -> &'static u32 { &BAR } = help: to fix this, the value can be extracted to a `const` and then used. error: pointers cannot be cast to integers during const eval - --> $DIR/min_const_fn.rs:91:42 + --> $DIR/min_const_fn.rs:79:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ @@ -196,7 +56,7 @@ LL | const fn foo30(x: *const u32) -> usize { x as usize } = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior error: pointers cannot be cast to integers during const eval - --> $DIR/min_const_fn.rs:93:63 + --> $DIR/min_const_fn.rs:81:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ @@ -205,7 +65,7 @@ LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior error: pointers cannot be cast to integers during const eval - --> $DIR/min_const_fn.rs:95:42 + --> $DIR/min_const_fn.rs:83:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ @@ -214,7 +74,7 @@ LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior error: pointers cannot be cast to integers during const eval - --> $DIR/min_const_fn.rs:97:63 + --> $DIR/min_const_fn.rs:85:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ @@ -222,18 +82,8 @@ LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:100:14 - | -LL | const fn inc(x: &mut i32) { *x += 1 } - | ^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0493]: destructor of `AlanTuring` cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:122:19 + --> $DIR/min_const_fn.rs:109:19 | LL | const fn no_apit2(_x: AlanTuring) {} | ^^ - value is dropped here @@ -241,14 +91,14 @@ LL | const fn no_apit2(_x: AlanTuring) {} | the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `impl std::fmt::Debug` cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:124:18 + --> $DIR/min_const_fn.rs:111:18 | LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^ - value is dropped here | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 24 previous errors; 2 warnings emitted +error: aborting due to 11 previous errors Some errors have detailed explanations: E0493, E0658. For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index 480b16b28a501..461499e942fcd 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -1,10 +1,11 @@ +//@ compile-flags: --edition 2018 #![unstable(feature = "humans", reason = "who ever let humans program computers, we're apparently really bad at it", issue = "none")] -#![feature(const_refs_to_cell, foo, foo2)] -#![feature(staged_api)] +#![feature(foo, foo2)] +#![feature(const_async_blocks, staged_api)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] @@ -27,10 +28,8 @@ const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required const fn bar3() -> u32 { - let x = std::cell::Cell::new(0u32); - x.get(); - //~^ ERROR const-stable function cannot use `#[feature(const_refs_to_cell)]` - //~| ERROR cannot call non-const fn + let x = async { 13 }; + //~^ ERROR const-stable function cannot use `#[feature(const_async_blocks)]` foo() //~^ ERROR is not yet stable as a const fn } diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index cb447719f9c58..fedc5a4809d65 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,5 +1,5 @@ error: `foo` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:16:25 + --> $DIR/min_const_fn_libstd_stability.rs:17:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ @@ -7,18 +7,18 @@ LL | const fn bar() -> u32 { foo() } = help: const-stable functions can only call other const-stable functions error: `foo2` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:24:26 + --> $DIR/min_const_fn_libstd_stability.rs:25:26 | LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | = help: const-stable functions can only call other const-stable functions -error: const-stable function cannot use `#[feature(const_refs_to_cell)]` - --> $DIR/min_const_fn_libstd_stability.rs:31:5 +error: const-stable function cannot use `#[feature(const_async_blocks)]` + --> $DIR/min_const_fn_libstd_stability.rs:31:13 | -LL | x.get(); - | ^ +LL | let x = async { 13 }; + | ^^^^^^^^^^^^ | help: if the function is not (yet) meant to be stable, make this function unstably const | @@ -27,20 +27,12 @@ LL | const fn bar3() -> u32 { | help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval) | -LL + #[rustc_allow_const_fn_unstable(const_refs_to_cell)] +LL + #[rustc_allow_const_fn_unstable(const_async_blocks)] LL | const fn bar3() -> u32 { | -error[E0015]: cannot call non-const fn `Cell::::get` in constant functions - --> $DIR/min_const_fn_libstd_stability.rs:31:7 - | -LL | x.get(); - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - error: `foo` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:34:5 + --> $DIR/min_const_fn_libstd_stability.rs:33:5 | LL | foo() | ^^^^^ @@ -48,13 +40,12 @@ LL | foo() = help: const-stable functions can only call other const-stable functions error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:45:32 + --> $DIR/min_const_fn_libstd_stability.rs:44:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | = help: const-stable functions can only call other const-stable functions -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs deleted file mode 100644 index df20ff446cda2..0000000000000 --- a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs +++ /dev/null @@ -1,13 +0,0 @@ -const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } -//~^ dereferencing raw mutable pointers in constant functions - -const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } -//~^ dereferencing raw mutable pointers in constant functions - -const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } -//~^ dereferencing raw mutable pointers in constant functions - -const unsafe fn bad_const_unsafe_deref_raw_underscore(x: *mut usize) { let _ = *x; } -//~^ dereferencing raw mutable pointers in constant functions - -fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr deleted file mode 100644 index 13d733494d219..0000000000000 --- a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe_bad.rs:1:77 - | -LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } - | ^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe_bad.rs:4:70 - | -LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } - | ^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe_bad.rs:7:83 - | -LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } - | ^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe_bad.rs:10:80 - | -LL | const unsafe fn bad_const_unsafe_deref_raw_underscore(x: *mut usize) { let _ = *x; } - | ^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs index 06e7d6f5d70f3..8b09b529ecc65 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs @@ -41,4 +41,12 @@ const unsafe fn call_unsafe_generic_cell_const_unsafe_fn_immediate() ret_null_mut_ptr_no_unsafe::>>() } +const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } + +const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } + +const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } + +const unsafe fn bad_const_unsafe_deref_raw_underscore(x: *mut usize) { let _ = *x; } + fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index f2a54b8a13dee..274b4444799ae 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_refs_to_cell, foo, foo2)] +#![feature(foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/tests/ui/consts/min_const_fn/mutable_borrow.rs b/tests/ui/consts/min_const_fn/mutable_borrow.rs deleted file mode 100644 index 580b1d50f774e..0000000000000 --- a/tests/ui/consts/min_const_fn/mutable_borrow.rs +++ /dev/null @@ -1,17 +0,0 @@ -const fn mutable_ref_in_const() -> u8 { - let mut a = 0; - let b = &mut a; //~ ERROR mutable references - *b -} - -struct X; - -impl X { - const fn inherent_mutable_ref_in_const() -> u8 { - let mut a = 0; - let b = &mut a; //~ ERROR mutable references - *b - } -} - -fn main() {} diff --git a/tests/ui/consts/min_const_fn/mutable_borrow.stderr b/tests/ui/consts/min_const_fn/mutable_borrow.stderr deleted file mode 100644 index 31653602c75d2..0000000000000 --- a/tests/ui/consts/min_const_fn/mutable_borrow.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/mutable_borrow.rs:3:13 - | -LL | let b = &mut a; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/mutable_borrow.rs:12:17 - | -LL | let b = &mut a; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.rs b/tests/ui/consts/miri_unleashed/abi-mismatch.rs index 57680479a1796..da5b1dd5802d2 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.rs +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.rs @@ -1,8 +1,6 @@ // Checks that we report ABI mismatches for "const extern fn" //@ compile-flags: -Z unleash-the-miri-inside-of-you -#![feature(const_extern_fn)] - const extern "C" fn c_fn() {} const fn call_rust_fn(my_fn: extern "Rust" fn()) { diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr index 51364b01a2d38..639795efae798 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -1,16 +1,16 @@ error[E0080]: could not evaluate static initializer - --> $DIR/abi-mismatch.rs:9:5 + --> $DIR/abi-mismatch.rs:7:5 | LL | my_fn(); | ^^^^^^^ calling a function with calling convention C using calling convention Rust | note: inside `call_rust_fn` - --> $DIR/abi-mismatch.rs:9:5 + --> $DIR/abi-mismatch.rs:7:5 | LL | my_fn(); | ^^^^^^^ note: inside `VAL` - --> $DIR/abi-mismatch.rs:15:18 + --> $DIR/abi-mismatch.rs:13:18 | LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern " warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/abi-mismatch.rs:9:5 + --> $DIR/abi-mismatch.rs:7:5 | LL | my_fn(); | ^^^^^^^ diff --git a/tests/ui/consts/miri_unleashed/box.stderr b/tests/ui/consts/miri_unleashed/box.stderr index a0518c99cda56..25cefa036ebb3 100644 --- a/tests/ui/consts/miri_unleashed/box.stderr +++ b/tests/ui/consts/miri_unleashed/box.stderr @@ -11,16 +11,6 @@ help: skipping check that does not even have a feature gate | LL | &mut *(Box::new(0)) | ^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/box.rs:8:5 - | -LL | &mut *(Box::new(0)) - | ^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/box.rs:8:5 - | -LL | &mut *(Box::new(0)) - | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs index 7e759a1a1e42e..6ac61e6700160 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -3,7 +3,6 @@ //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" #![allow(static_mut_refs)] -#![deny(const_eval_mutable_ptr_in_final_value)] use std::cell::UnsafeCell; use std::sync::atomic::*; @@ -18,13 +17,11 @@ static OH_YES: &mut i32 = &mut 42; //~| pointing to read-only memory static BAR: &mut () = &mut (); //~^ ERROR encountered mutable pointer in final value of static -//~| WARNING this was previously accepted by the compiler struct Foo(T); static BOO: &mut Foo<()> = &mut Foo(()); //~^ ERROR encountered mutable pointer in final value of static -//~| WARNING this was previously accepted by the compiler const BLUNT: &mut i32 = &mut 42; //~^ ERROR: it is undefined behavior to use this value @@ -81,36 +78,32 @@ const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; //~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; //~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler +// This does *not* error since it uses a shared reference, and we have to ignore +// those. See . const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; -//~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler struct SyncPtr { x: *const T, } unsafe impl Sync for SyncPtr {} -// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. -// (This relies on `SyncPtr` being a curly brace struct.) -// However, we intern the inner memory as read-only, so this must be rejected. +// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. (This +// relies on `SyncPtr` being a curly brace struct.) However, we intern the inner memory as +// read-only, so ideally this should be rejected. Unfortunately, as explained in +// , we have to accept it. // (Also see `static-no-inner-mut` for similar tests on `static`.) const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; -//~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler +// With mutable references at least, we can detect this and error. const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; //~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; //~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler fn main() { diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 620953ffa3e2e..874dd0389d455 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:13:1 + --> $DIR/mutable_references.rs:12:1 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered mutable reference or box pointing to read-only memory @@ -10,7 +10,7 @@ LL | static FOO: &&mut u32 = &&mut 42; } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:16:1 + --> $DIR/mutable_references.rs:15:1 | LL | static OH_YES: &mut i32 = &mut 42; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory @@ -21,30 +21,19 @@ LL | static OH_YES: &mut i32 = &mut 42; } error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:19:1 + --> $DIR/mutable_references.rs:18:1 | LL | static BAR: &mut () = &mut (); | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:25:1 + --> $DIR/mutable_references.rs:23:1 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:29:1 + --> $DIR/mutable_references.rs:26:1 | LL | const BLUNT: &mut i32 = &mut 42; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory @@ -55,7 +44,7 @@ LL | const BLUNT: &mut i32 = &mut 42; } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:33:1 + --> $DIR/mutable_references.rs:30:1 | LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` @@ -66,7 +55,7 @@ LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC } } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:43:1 + --> $DIR/mutable_references.rs:40:1 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory @@ -77,7 +66,7 @@ LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:49:1 + --> $DIR/mutable_references.rs:46:1 | LL | const MUH: Meh = Meh { | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory @@ -88,7 +77,7 @@ LL | const MUH: Meh = Meh { } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:61:1 + --> $DIR/mutable_references.rs:58:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory @@ -99,7 +88,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:68:1 + --> $DIR/mutable_references.rs:65:1 | LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory @@ -110,7 +99,7 @@ LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:75:1 + --> $DIR/mutable_references.rs:72:1 | LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` @@ -121,67 +110,37 @@ LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; } error[E0080]: evaluation of constant value failed - --> $DIR/mutable_references.rs:78:43 + --> $DIR/mutable_references.rs:75:43 | LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ^^^^^^^^^^^^^ constant accesses mutable global memory error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:82:1 + --> $DIR/mutable_references.rs:79:1 | LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:86:1 + --> $DIR/mutable_references.rs:82:1 | LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:90:1 - | -LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:103:1 - | -LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:107:1 + --> $DIR/mutable_references.rs:102:1 | LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:111:1 + --> $DIR/mutable_references.rs:105:1 | LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:120:5 + --> $DIR/mutable_references.rs:113:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign @@ -189,227 +148,92 @@ LL | *OH_YES = 99; warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:13:26 + --> $DIR/mutable_references.rs:12:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:16:27 + --> $DIR/mutable_references.rs:15:27 | LL | static OH_YES: &mut i32 = &mut 42; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:19:23 + --> $DIR/mutable_references.rs:18:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:25:28 + --> $DIR/mutable_references.rs:23:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:29:25 + --> $DIR/mutable_references.rs:26:25 | LL | const BLUNT: &mut i32 = &mut 42; | ^^^^^^^ help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references.rs:33:68 + --> $DIR/mutable_references.rs:30:68 | LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; | ^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references.rs:33:63 - | -LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; - | ^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:43:28 + --> $DIR/mutable_references.rs:40:28 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:52:8 + --> $DIR/mutable_references.rs:49:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:61:27 + --> $DIR/mutable_references.rs:58:27 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references.rs:68:49 - | -LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references.rs:68:49 - | -LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references.rs:75:43 + --> $DIR/mutable_references.rs:72:43 | LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; | ^^^^^^^ help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references.rs:78:45 + --> $DIR/mutable_references.rs:75:45 | LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:82:45 + --> $DIR/mutable_references.rs:79:45 | LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:86:46 + --> $DIR/mutable_references.rs:82:46 | LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:90:47 + --> $DIR/mutable_references.rs:87:47 | LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:103:51 + --> $DIR/mutable_references.rs:99:51 | LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; | ^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:107:49 + --> $DIR/mutable_references.rs:102:49 | LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:111:51 + --> $DIR/mutable_references.rs:105:51 | LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ -error: aborting due to 19 previous errors; 1 warning emitted +error: aborting due to 17 previous errors; 1 warning emitted Some errors have detailed explanations: E0080, E0594. For more information about an error, try `rustc --explain E0080`. -Future incompatibility report: Future breakage diagnostic: -error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:19:1 - | -LL | static BAR: &mut () = &mut (); - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:25:1 - | -LL | static BOO: &mut Foo<()> = &mut Foo(()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:82:1 - | -LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:86:1 - | -LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:90:1 - | -LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:103:1 - | -LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:107:1 - | -LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:111:1 - | -LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr index 1e554f6bac375..88a734bc241eb 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/static-no-inner-mut.rs:9:1 + --> $DIR/static-no-inner-mut.rs:8:1 | LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory @@ -10,7 +10,7 @@ LL | static REF: &AtomicI32 = &AtomicI32::new(42); } error[E0080]: it is undefined behavior to use this value - --> $DIR/static-no-inner-mut.rs:12:1 + --> $DIR/static-no-inner-mut.rs:11:1 | LL | static REFMUT: &mut i32 = &mut 0; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory @@ -21,7 +21,7 @@ LL | static REFMUT: &mut i32 = &mut 0; } error[E0080]: it is undefined behavior to use this value - --> $DIR/static-no-inner-mut.rs:16:1 + --> $DIR/static-no-inner-mut.rs:15:1 | LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory @@ -32,7 +32,7 @@ LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; } error[E0080]: it is undefined behavior to use this value - --> $DIR/static-no-inner-mut.rs:18:1 + --> $DIR/static-no-inner-mut.rs:17:1 | LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory @@ -45,118 +45,53 @@ LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; error: encountered mutable pointer in final value of static --> $DIR/static-no-inner-mut.rs:34:1 | -LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/static-no-inner-mut.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:38:1 - | LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:42:1 + --> $DIR/static-no-inner-mut.rs:37:1 | LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:9:26 + --> $DIR/static-no-inner-mut.rs:8:26 | LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:12:27 + --> $DIR/static-no-inner-mut.rs:11:27 | LL | static REFMUT: &mut i32 = &mut 0; | ^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:16:56 + --> $DIR/static-no-inner-mut.rs:15:56 | LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:18:44 + --> $DIR/static-no-inner-mut.rs:17:44 | LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:34:52 + --> $DIR/static-no-inner-mut.rs:31:52 | LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; | ^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:38:51 + --> $DIR/static-no-inner-mut.rs:34:51 | LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:42:52 + --> $DIR/static-no-inner-mut.rs:37:52 | LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. -Future incompatibility report: Future breakage diagnostic: -error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:34:1 - | -LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/static-no-inner-mut.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:38:1 - | -LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/static-no-inner-mut.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:42:1 - | -LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/static-no-inner-mut.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr index 84ed631fcdab3..c4f3903e14331 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/static-no-inner-mut.rs:9:1 + --> $DIR/static-no-inner-mut.rs:8:1 | LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory @@ -10,7 +10,7 @@ LL | static REF: &AtomicI32 = &AtomicI32::new(42); } error[E0080]: it is undefined behavior to use this value - --> $DIR/static-no-inner-mut.rs:12:1 + --> $DIR/static-no-inner-mut.rs:11:1 | LL | static REFMUT: &mut i32 = &mut 0; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory @@ -21,7 +21,7 @@ LL | static REFMUT: &mut i32 = &mut 0; } error[E0080]: it is undefined behavior to use this value - --> $DIR/static-no-inner-mut.rs:16:1 + --> $DIR/static-no-inner-mut.rs:15:1 | LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory @@ -32,7 +32,7 @@ LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; } error[E0080]: it is undefined behavior to use this value - --> $DIR/static-no-inner-mut.rs:18:1 + --> $DIR/static-no-inner-mut.rs:17:1 | LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory @@ -45,118 +45,53 @@ LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; error: encountered mutable pointer in final value of static --> $DIR/static-no-inner-mut.rs:34:1 | -LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/static-no-inner-mut.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:38:1 - | LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:42:1 + --> $DIR/static-no-inner-mut.rs:37:1 | LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:9:26 + --> $DIR/static-no-inner-mut.rs:8:26 | LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:12:27 + --> $DIR/static-no-inner-mut.rs:11:27 | LL | static REFMUT: &mut i32 = &mut 0; | ^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:16:56 + --> $DIR/static-no-inner-mut.rs:15:56 | LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:18:44 + --> $DIR/static-no-inner-mut.rs:17:44 | LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:34:52 + --> $DIR/static-no-inner-mut.rs:31:52 | LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; | ^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:38:51 + --> $DIR/static-no-inner-mut.rs:34:51 | LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/static-no-inner-mut.rs:42:52 + --> $DIR/static-no-inner-mut.rs:37:52 | LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. -Future incompatibility report: Future breakage diagnostic: -error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:34:1 - | -LL | static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/static-no-inner-mut.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:38:1 - | -LL | static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/static-no-inner-mut.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of static - --> $DIR/static-no-inner-mut.rs:42:1 - | -LL | static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/static-no-inner-mut.rs:6:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs index 810760319c1bc..126d78158fe0d 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs @@ -1,9 +1,8 @@ //@ stderr-per-bitwidth //@ compile-flags: -Zunleash-the-miri-inside-of-you -#![feature(const_refs_to_cell, const_mut_refs)] + // All "inner" allocations that come with a `static` are interned immutably. This means it is // crucial that we do not accept any form of (interior) mutability there. -#![deny(const_eval_mutable_ptr_in_final_value)] use std::sync::atomic::*; static REF: &AtomicI32 = &AtomicI32::new(42); @@ -27,20 +26,15 @@ unsafe impl Sync for SyncPtr {} // All of these pass the lifetime checks because of the "tail expression" / "outer scope" rule. // (This relies on `SyncPtr` being a curly brace struct.) -// Then they get interned immutably, which is not great. -// `mut_ref_in_final.rs` and `std/cell.rs` ensure that we don't accept this even with the feature -// fate, but for unleashed Miri there's not really any way we can reject them: it's just -// non-dangling raw pointers. +// Then they get interned immutably, which is not great. See +// for why we accept such code. static RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; -//~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler +// With mutable references at least, we can detect this and error. static RAW_MUT_CAST: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; //~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; //~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler fn main() {} diff --git a/tests/ui/consts/missing_assoc_const_type.rs b/tests/ui/consts/missing_assoc_const_type.rs index 8d95e3dca633c..633998e9bc157 100644 --- a/tests/ui/consts/missing_assoc_const_type.rs +++ b/tests/ui/consts/missing_assoc_const_type.rs @@ -16,7 +16,7 @@ impl Range for TwoDigits { const fn digits(x: u8) -> usize { match x { - TwoDigits::FIRST..=TwoDigits::LAST => 0, + TwoDigits::FIRST..=TwoDigits::LAST => 0, //~ ERROR: could not evaluate constant pattern 0..=9 | 100..=255 => panic!(), } } diff --git a/tests/ui/consts/missing_assoc_const_type.stderr b/tests/ui/consts/missing_assoc_const_type.stderr index 28af1f0f321e6..ef7ff962d2d12 100644 --- a/tests/ui/consts/missing_assoc_const_type.stderr +++ b/tests/ui/consts/missing_assoc_const_type.stderr @@ -4,5 +4,11 @@ error: missing type for `const` item LL | const FIRST: = 10; | ^ help: provide a type for the associated constant: `u8` -error: aborting due to 1 previous error +error: could not evaluate constant pattern + --> $DIR/missing_assoc_const_type.rs:19:9 + | +LL | TwoDigits::FIRST..=TwoDigits::LAST => 0, + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs index d45deee18fa80..ea457c96f153c 100644 --- a/tests/ui/consts/missing_span_in_backtrace.rs +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -2,7 +2,6 @@ #![feature(const_swap)] -#![feature(const_mut_refs)] use std::{ mem::{self, MaybeUninit}, ptr, diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index 9e0506e7e386c..72d15702e8913 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -10,13 +10,13 @@ note: inside `std::ptr::swap_nonoverlapping_simple_untyped::>` note: inside `swap_nonoverlapping::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `X` - --> $DIR/missing_span_in_backtrace.rs:17:9 + --> $DIR/missing_span_in_backtrace.rs:16:9 | -17 | / ptr::swap_nonoverlapping( -18 | | &mut ptr1 as *mut _ as *mut MaybeUninit, -19 | | &mut ptr2 as *mut _ as *mut MaybeUninit, -20 | | mem::size_of::<&i32>(), -21 | | ); +16 | / ptr::swap_nonoverlapping( +17 | | &mut ptr1 as *mut _ as *mut MaybeUninit, +18 | | &mut ptr2 as *mut _ as *mut MaybeUninit, +19 | | mem::size_of::<&i32>(), +20 | | ); | |_________^ = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/mut-ptr-to-static.rs b/tests/ui/consts/mut-ptr-to-static.rs index e921365c7d407..e2e256980d2fa 100644 --- a/tests/ui/consts/mut-ptr-to-static.rs +++ b/tests/ui/consts/mut-ptr-to-static.rs @@ -1,5 +1,4 @@ //@run-pass -#![feature(const_mut_refs)] #![feature(sync_unsafe_cell)] use std::cell::SyncUnsafeCell; diff --git a/tests/ui/consts/promoted-const-drop.rs b/tests/ui/consts/promoted-const-drop.rs index b7d92d6523a81..c6ea0d0c924da 100644 --- a/tests/ui/consts/promoted-const-drop.rs +++ b/tests/ui/consts/promoted-const-drop.rs @@ -1,5 +1,4 @@ #![feature(const_trait_impl)] -#![feature(const_mut_refs)] struct A(); diff --git a/tests/ui/consts/promoted-const-drop.stderr b/tests/ui/consts/promoted-const-drop.stderr index 1201f608232df..e015f75620690 100644 --- a/tests/ui/consts/promoted-const-drop.stderr +++ b/tests/ui/consts/promoted-const-drop.stderr @@ -1,5 +1,5 @@ error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/promoted-const-drop.rs:6:12 + --> $DIR/promoted-const-drop.rs:5:12 | LL | impl const Drop for A { | ^^^^ @@ -8,7 +8,7 @@ LL | impl const Drop for A { = note: adding a non-const method body in the future would be a breaking change error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted-const-drop.rs:14:26 + --> $DIR/promoted-const-drop.rs:13:26 | LL | let _: &'static A = &A(); | ---------- ^^^ creates a temporary value which is freed while still in use @@ -19,7 +19,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted-const-drop.rs:15:28 + --> $DIR/promoted-const-drop.rs:14:28 | LL | let _: &'static [A] = &[C]; | ------------ ^^^ creates a temporary value which is freed while still in use diff --git a/tests/ui/consts/promoted_const_call.rs b/tests/ui/consts/promoted_const_call.rs index deaa053c4156b..c3920ff7241bc 100644 --- a/tests/ui/consts/promoted_const_call.rs +++ b/tests/ui/consts/promoted_const_call.rs @@ -1,6 +1,5 @@ //@ known-bug: #103507 -#![feature(const_mut_refs)] #![feature(const_trait_impl)] struct Panic; diff --git a/tests/ui/consts/promoted_const_call.stderr b/tests/ui/consts/promoted_const_call.stderr index 64bf6bd73b0a5..bcb9dfb704b1d 100644 --- a/tests/ui/consts/promoted_const_call.stderr +++ b/tests/ui/consts/promoted_const_call.stderr @@ -1,5 +1,5 @@ error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/promoted_const_call.rs:7:12 + --> $DIR/promoted_const_call.rs:6:12 | LL | impl const Drop for Panic { fn drop(&mut self) { panic!(); } } | ^^^^ @@ -8,7 +8,7 @@ LL | impl const Drop for Panic { fn drop(&mut self) { panic!(); } } = note: adding a non-const method body in the future would be a breaking change error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_call.rs:11:26 + --> $DIR/promoted_const_call.rs:10:26 | LL | let _: &'static _ = &id(&Panic); | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -19,7 +19,7 @@ LL | }; | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_call.rs:11:30 + --> $DIR/promoted_const_call.rs:10:30 | LL | let _: &'static _ = &id(&Panic); | ---------- ^^^^^ - temporary value is freed at the end of this statement @@ -28,7 +28,7 @@ LL | let _: &'static _ = &id(&Panic); | type annotation requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_call.rs:17:26 + --> $DIR/promoted_const_call.rs:16:26 | LL | let _: &'static _ = &id(&Panic); | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -39,7 +39,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_call.rs:17:30 + --> $DIR/promoted_const_call.rs:16:30 | LL | let _: &'static _ = &id(&Panic); | ---------- ^^^^^ - temporary value is freed at the end of this statement @@ -48,7 +48,7 @@ LL | let _: &'static _ = &id(&Panic); | type annotation requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_call.rs:20:26 + --> $DIR/promoted_const_call.rs:19:26 | LL | let _: &'static _ = &&(Panic, 0).1; | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -59,7 +59,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_call.rs:20:27 + --> $DIR/promoted_const_call.rs:19:27 | LL | let _: &'static _ = &&(Panic, 0).1; | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use diff --git a/tests/ui/consts/promotion-mutable-ref.rs b/tests/ui/consts/promotion-mutable-ref.rs index 0bca8a8dca42f..36a0c8ad80500 100644 --- a/tests/ui/consts/promotion-mutable-ref.rs +++ b/tests/ui/consts/promotion-mutable-ref.rs @@ -1,5 +1,4 @@ //@ run-pass -#![feature(const_mut_refs)] static mut TEST: i32 = { // We must not promote this, as CTFE needs to be able to mutate it later. diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.rs b/tests/ui/consts/qualif-indirect-mutation-fail.rs index a99d0633ba130..c6e08a557c8af 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.rs +++ b/tests/ui/consts/qualif-indirect-mutation-fail.rs @@ -1,5 +1,4 @@ //@ compile-flags: --crate-type=lib -#![feature(const_mut_refs)] #![feature(const_precise_live_drops)] #![feature(const_swap)] diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index 21c872ed13f20..433dfba2257d0 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -1,5 +1,5 @@ error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:14:9 + --> $DIR/qualif-indirect-mutation-fail.rs:13:9 | LL | let mut x = None; | ^^^^^ the destructor for this type cannot be evaluated in constants @@ -16,13 +16,13 @@ note: inside `std::ptr::drop_in_place:: - shim(Some(String))` note: inside `std::ptr::drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `A1` - --> $DIR/qualif-indirect-mutation-fail.rs:20:1 + --> $DIR/qualif-indirect-mutation-fail.rs:19:1 | LL | }; | ^ error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:30:9 + --> $DIR/qualif-indirect-mutation-fail.rs:29:9 | LL | let _z = x; | ^^ the destructor for this type cannot be evaluated in constants @@ -39,49 +39,49 @@ note: inside `std::ptr::drop_in_place:: - shim(Some(String))` note: inside `std::ptr::drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `A2` - --> $DIR/qualif-indirect-mutation-fail.rs:31:1 + --> $DIR/qualif-indirect-mutation-fail.rs:30:1 | LL | }; | ^ error[E0493]: destructor of `(u32, Option)` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:8:9 + --> $DIR/qualif-indirect-mutation-fail.rs:7:9 | LL | let mut a: (u32, Option) = (0, None); | ^^^^^ the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:35:9 + --> $DIR/qualif-indirect-mutation-fail.rs:34:9 | LL | let x: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:43:9 + --> $DIR/qualif-indirect-mutation-fail.rs:42:9 | LL | let _y = x; | ^^ the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:51:9 + --> $DIR/qualif-indirect-mutation-fail.rs:50:9 | LL | let mut y: Option = None; | ^^^^^ the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:48:9 + --> $DIR/qualif-indirect-mutation-fail.rs:47:9 | LL | let mut x: Option = None; | ^^^^^ the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:61:9 + --> $DIR/qualif-indirect-mutation-fail.rs:60:9 | LL | let y: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:58:9 + --> $DIR/qualif-indirect-mutation-fail.rs:57:9 | LL | let x: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions diff --git a/tests/ui/consts/qualif-indirect-mutation-pass.rs b/tests/ui/consts/qualif-indirect-mutation-pass.rs index 9d5f0d4306d72..de417216a4943 100644 --- a/tests/ui/consts/qualif-indirect-mutation-pass.rs +++ b/tests/ui/consts/qualif-indirect-mutation-pass.rs @@ -1,6 +1,5 @@ //@ compile-flags: --crate-type=lib //@ check-pass -#![feature(const_mut_refs)] #![feature(const_precise_live_drops)] // Mutable reference allows only mutation of !Drop place. diff --git a/tests/ui/consts/refs-to-cell-in-final.rs b/tests/ui/consts/refs-to-cell-in-final.rs index c7ccd25fc4cb7..844b140cff2b5 100644 --- a/tests/ui/consts/refs-to-cell-in-final.rs +++ b/tests/ui/consts/refs-to-cell-in-final.rs @@ -1,8 +1,8 @@ -#![feature(const_refs_to_cell)] - use std::cell::*; -struct SyncPtr { x : *const T } +struct SyncPtr { + x: *const T, +} unsafe impl Sync for SyncPtr {} // These pass the lifetime checks because of the "tail expression" / "outer scope" rule. @@ -18,8 +18,8 @@ const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; // This one does not get promoted because of `Drop`, and then enters interesting codepaths because // as a value it has no interior mutability, but as a type it does. See // . Value-based reasoning for interior mutability -// is questionable (https://github.com/rust-lang/unsafe-code-guidelines/issues/493) so for now we -// reject this, though not with a great error message. +// is questionable (https://github.com/rust-lang/unsafe-code-guidelines/issues/493) but we've +// done it since Rust 1.0 so we can't stop now. pub enum JsValue { Undefined, Object(Cell), @@ -28,10 +28,8 @@ impl Drop for JsValue { fn drop(&mut self) {} } const UNDEFINED: &JsValue = &JsValue::Undefined; -//~^ WARNING: mutable pointer in final value of constant -//~| WARNING: this was previously accepted by the compiler but is being phased out -// In contrast, this one works since it is being promoted. +// Here's a variant of the above that uses promotion instead of the "outer scope" rule. const NONE: &'static Option> = &None; // Making it clear that this is promotion, not "outer scope". const NONE_EXPLICIT_PROMOTED: &'static Option> = { @@ -39,4 +37,13 @@ const NONE_EXPLICIT_PROMOTED: &'static Option> = { x }; +// Not okay, since we are borrowing something with interior mutability. +const INTERIOR_MUT_VARIANT: &Option> = &{ + //~^ERROR: cannot refer to interior mutable data + let mut x = None; + assert!(x.is_none()); + x = Some(UnsafeCell::new(false)); + x +}; + fn main() {} diff --git a/tests/ui/consts/refs-to-cell-in-final.stderr b/tests/ui/consts/refs-to-cell-in-final.stderr index 2a7a858ebc9bf..8d82d94f4126f 100644 --- a/tests/ui/consts/refs-to-cell-in-final.stderr +++ b/tests/ui/consts/refs-to-cell-in-final.stderr @@ -12,27 +12,19 @@ error[E0492]: constants cannot refer to interior mutable data LL | const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; | ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value -warning: encountered mutable pointer in final value of constant - --> $DIR/refs-to-cell-in-final.rs:30:1 - | -LL | const UNDEFINED: &JsValue = &JsValue::Undefined; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/refs-to-cell-in-final.rs:41:57 | - = 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 #122153 - = note: `#[warn(const_eval_mutable_ptr_in_final_value)]` on by default +LL | const INTERIOR_MUT_VARIANT: &Option> = &{ + | _________________________________________________________^ +LL | | +LL | | let mut x = None; +LL | | assert!(x.is_none()); +LL | | x = Some(UnsafeCell::new(false)); +LL | | x +LL | | }; + | |_^ this borrow of an interior mutable value may end up in the final value -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0492`. -Future incompatibility report: Future breakage diagnostic: -warning: encountered mutable pointer in final value of constant - --> $DIR/refs-to-cell-in-final.rs:30:1 - | -LL | const UNDEFINED: &JsValue = &JsValue::Undefined; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - = note: `#[warn(const_eval_mutable_ptr_in_final_value)]` on by default - diff --git a/tests/ui/consts/slice-index-overflow-issue-130284.rs b/tests/ui/consts/slice-index-overflow-issue-130284.rs new file mode 100644 index 0000000000000..299009082563a --- /dev/null +++ b/tests/ui/consts/slice-index-overflow-issue-130284.rs @@ -0,0 +1,13 @@ +const C: () = { + let value = [1, 2]; + let ptr = value.as_ptr().wrapping_add(2); + let fat = std::ptr::slice_from_raw_parts(ptr, usize::MAX); + unsafe { + // This used to ICE, but it should just report UB. + let _ice = (*fat)[usize::MAX - 1]; + //~^ERROR: constant value failed + //~| overflow + } +}; + +fn main() {} diff --git a/tests/ui/consts/slice-index-overflow-issue-130284.stderr b/tests/ui/consts/slice-index-overflow-issue-130284.stderr new file mode 100644 index 0000000000000..e3e676c894947 --- /dev/null +++ b/tests/ui/consts/slice-index-overflow-issue-130284.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/slice-index-overflow-issue-130284.rs:7:20 + | +LL | let _ice = (*fat)[usize::MAX - 1]; + | ^^^^^^^^^^^^^^^^^^^^^^ overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/static-mut-refs.rs b/tests/ui/consts/static-mut-refs.rs index d4ebfbbf17a86..c0d0bb613325c 100644 --- a/tests/ui/consts/static-mut-refs.rs +++ b/tests/ui/consts/static-mut-refs.rs @@ -1,6 +1,9 @@ //@ run-pass #![allow(dead_code)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + // Checks that mutable static items can have mutable slices and other references diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs index 547f6449f1303..2b1fe55df78b3 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs @@ -1,13 +1,10 @@ -//@ revisions: stock mut_refs #![allow(static_mut_refs)] -#![cfg_attr(mut_refs, feature(const_mut_refs))] static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; - //[mut_refs]~^ ERROR could not evaluate static initializer - //[stock]~^^ ERROR mutation through a reference is not allowed in statics + //~^ ERROR could not evaluate static initializer }; fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stderr similarity index 86% rename from tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr rename to tests/ui/consts/static_mut_containing_mut_ref2.stderr index 42cb119d2aeeb..37cd2b51ad143 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stderr @@ -1,5 +1,5 @@ error[E0080]: could not evaluate static initializer - --> $DIR/static_mut_containing_mut_ref2.rs:8:5 + --> $DIR/static_mut_containing_mut_ref2.rs:6:5 | LL | *(&mut STDERR_BUFFER_SPACE) = 42; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr deleted file mode 100644 index 5ff9c0b6e2b90..0000000000000 --- a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: mutation through a reference is not allowed in statics - --> $DIR/static_mut_containing_mut_ref2.rs:8:5 - | -LL | *(&mut STDERR_BUFFER_SPACE) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/std/cell.rs b/tests/ui/consts/std/cell.rs index f1ef541319a4b..5f8236245abb8 100644 --- a/tests/ui/consts/std/cell.rs +++ b/tests/ui/consts/std/cell.rs @@ -1,5 +1,3 @@ -#![feature(const_refs_to_cell)] - use std::cell::*; // not ok, because this creates a dangling pointer, just like `let x = Cell::new(42).as_ptr()` would diff --git a/tests/ui/consts/std/cell.stderr b/tests/ui/consts/std/cell.stderr index 873b797a466db..d505454b9ad55 100644 --- a/tests/ui/consts/std/cell.stderr +++ b/tests/ui/consts/std/cell.stderr @@ -1,23 +1,23 @@ error: encountered dangling pointer in final value of static - --> $DIR/cell.rs:6:1 + --> $DIR/cell.rs:4:1 | LL | static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered dangling pointer in final value of constant - --> $DIR/cell.rs:8:1 + --> $DIR/cell.rs:6:1 | LL | const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered dangling pointer in final value of constant - --> $DIR/cell.rs:22:1 + --> $DIR/cell.rs:20:1 | LL | const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered dangling pointer in final value of constant - --> $DIR/cell.rs:27:1 + --> $DIR/cell.rs:25:1 | LL | const FOO2: *mut u32 = Cell::new(42).as_ptr(); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/unwind-abort.rs b/tests/ui/consts/unwind-abort.rs index 1dd33f327fb68..b62fa81da0652 100644 --- a/tests/ui/consts/unwind-abort.rs +++ b/tests/ui/consts/unwind-abort.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(const_extern_fn)] - // We don't unwind in const-eval anyways. const extern "C" fn foo() { panic!() diff --git a/tests/ui/consts/write_to_mut_ref_dest.rs b/tests/ui/consts/write_to_mut_ref_dest.rs index 42ac228403841..18ded32a76f56 100644 --- a/tests/ui/consts/write_to_mut_ref_dest.rs +++ b/tests/ui/consts/write_to_mut_ref_dest.rs @@ -1,17 +1,14 @@ -//@ revisions: stock mut_refs -//@[mut_refs] check-pass - -#![cfg_attr(mut_refs, feature(const_mut_refs))] - -use std::cell::Cell; +//@run-pass const FOO: &u32 = { let mut a = 42; { - let b: *mut u32 = &mut a; //[stock]~ ERROR mutable references are not allowed in constants - unsafe { *b = 5; } //[stock]~ ERROR dereferencing raw mutable pointers in constants + let b: *mut u32 = &mut a; + unsafe { *b = 5; } } &{a} }; -fn main() {} +fn main() { + assert_eq!(*FOO, 5); +} diff --git a/tests/ui/consts/write_to_static_via_mut_ref.rs b/tests/ui/consts/write_to_static_via_mut_ref.rs index 39b830ae4e915..82ac85bd2509a 100644 --- a/tests/ui/consts/write_to_static_via_mut_ref.rs +++ b/tests/ui/consts/write_to_static_via_mut_ref.rs @@ -1,5 +1,3 @@ -#![feature(const_mut_refs)] - static OH_NO: &mut i32 = &mut 42; //~ ERROR mutable references are not allowed fn main() { assert_eq!(*OH_NO, 42); diff --git a/tests/ui/consts/write_to_static_via_mut_ref.stderr b/tests/ui/consts/write_to_static_via_mut_ref.stderr index f64f0db6b25a1..63ef788032f3c 100644 --- a/tests/ui/consts/write_to_static_via_mut_ref.stderr +++ b/tests/ui/consts/write_to_static_via_mut_ref.stderr @@ -1,11 +1,11 @@ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/write_to_static_via_mut_ref.rs:3:26 + --> $DIR/write_to_static_via_mut_ref.rs:1:26 | LL | static OH_NO: &mut i32 = &mut 42; | ^^^^^^^ error[E0594]: cannot assign to `*OH_NO`, as `OH_NO` is an immutable static item - --> $DIR/write_to_static_via_mut_ref.rs:6:5 + --> $DIR/write_to_static_via_mut_ref.rs:4:5 | LL | *OH_NO = 43; | ^^^^^^^^^^^ cannot assign diff --git a/tests/ui/coroutine/const_gen_fn.rs b/tests/ui/coroutine/const_gen_fn.rs new file mode 100644 index 0000000000000..986693f33ab1b --- /dev/null +++ b/tests/ui/coroutine/const_gen_fn.rs @@ -0,0 +1,12 @@ +//@ edition:2024 +//@ compile-flags: -Zunstable-options + +#![feature(gen_blocks)] + +const gen fn a() {} +//~^ ERROR functions cannot be both `const` and `gen` + +const async gen fn b() {} +//~^ ERROR functions cannot be both `const` and `async gen` + +fn main() {} diff --git a/tests/ui/coroutine/const_gen_fn.stderr b/tests/ui/coroutine/const_gen_fn.stderr new file mode 100644 index 0000000000000..b58446ac88fd1 --- /dev/null +++ b/tests/ui/coroutine/const_gen_fn.stderr @@ -0,0 +1,20 @@ +error: functions cannot be both `const` and `gen` + --> $DIR/const_gen_fn.rs:6:1 + | +LL | const gen fn a() {} + | ^^^^^-^^^---------- + | | | + | | `gen` because of this + | `const` because of this + +error: functions cannot be both `const` and `async gen` + --> $DIR/const_gen_fn.rs:9:1 + | +LL | const async gen fn b() {} + | ^^^^^-^^^^^^^^^---------- + | | | + | | `async gen` because of this + | `const` because of this + +error: aborting due to 2 previous errors + diff --git a/tests/ui/coroutine/discriminant.rs b/tests/ui/coroutine/discriminant.rs index d6879e2182556..ca4fcedd7e536 100644 --- a/tests/ui/coroutine/discriminant.rs +++ b/tests/ui/coroutine/discriminant.rs @@ -124,12 +124,14 @@ fn main() { }; assert_eq!(size_of_val(&gen_u8_tiny_niche()), 1); - assert_eq!(size_of_val(&Some(gen_u8_tiny_niche())), 1); // uses niche + // FIXME(#63818): niches in coroutines are disabled. + // assert_eq!(size_of_val(&Some(gen_u8_tiny_niche())), 1); // uses niche assert_eq!(size_of_val(&Some(Some(gen_u8_tiny_niche()))), 2); // cannot use niche anymore assert_eq!(size_of_val(&gen_u8_full()), 1); assert_eq!(size_of_val(&Some(gen_u8_full())), 2); // cannot use niche assert_eq!(size_of_val(&gen_u16()), 2); - assert_eq!(size_of_val(&Some(gen_u16())), 2); // uses niche + // FIXME(#63818): niches in coroutines are disabled. + // assert_eq!(size_of_val(&Some(gen_u16())), 2); // uses niche cycle(gen_u8_tiny_niche(), 254); cycle(gen_u8_full(), 255); diff --git a/tests/ui/coroutine/niche-in-coroutine.rs b/tests/ui/coroutine/niche-in-coroutine.rs index 117ee9e6f0386..f268ef09f8923 100644 --- a/tests/ui/coroutine/niche-in-coroutine.rs +++ b/tests/ui/coroutine/niche-in-coroutine.rs @@ -15,5 +15,6 @@ fn main() { take(x); }; - assert_eq!(size_of_val(&gen1), size_of_val(&Some(gen1))); + // FIXME(#63818): niches in coroutines are disabled. Should be `assert_eq`. + assert_ne!(size_of_val(&gen1), size_of_val(&Some(gen1))); } diff --git a/tests/ui/coroutine/static-mut-reference-across-yield.rs b/tests/ui/coroutine/static-mut-reference-across-yield.rs index 40d5fdf2d5736..d45d6e6428b9c 100644 --- a/tests/ui/coroutine/static-mut-reference-across-yield.rs +++ b/tests/ui/coroutine/static-mut-reference-across-yield.rs @@ -1,6 +1,8 @@ //@ build-pass #![feature(coroutines, stmt_expr_attributes)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.rs b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.rs index dc68f6cf71f11..a1922c98ef6d3 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.rs +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.rs @@ -3,7 +3,7 @@ //@ compile-flags:-C debuginfo=2 //@ build-fail -//@ error-pattern: too big for the current architecture +//@ error-pattern: too big for the target architecture //@ normalize-stderr-64bit: "18446744073709551615" -> "SIZE" //@ normalize-stderr-32bit: "4294967295" -> "SIZE" diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr index 06aad9616cb7a..a3772e509ed67 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; usize::MAX]` are too big for the current architecture +error: values of the type `[u8; usize::MAX]` are too big for the target architecture error: aborting due to 1 previous error diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs index 2b6e85362b68c..3456cd55b7582 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs @@ -5,7 +5,7 @@ //@ compile-flags:-C debuginfo=2 //@ build-fail -//@ error-pattern: too big for the current architecture +//@ error-pattern: too big for the target architecture //@ normalize-stderr-64bit: "18446744073709551615" -> "SIZE" //@ normalize-stderr-32bit: "4294967295" -> "SIZE" diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr index 06aad9616cb7a..a3772e509ed67 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; usize::MAX]` are too big for the current architecture +error: values of the type `[u8; usize::MAX]` are too big for the target architecture error: aborting due to 1 previous error diff --git a/tests/ui/delegation/generics/impl-to-free-fn-pass.rs b/tests/ui/delegation/generics/impl-to-free-fn-pass.rs new file mode 100644 index 0000000000000..3b39a45746758 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-free-fn-pass.rs @@ -0,0 +1,29 @@ +//@ run-pass +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo(_: T, y: U) -> U { y } +} + +trait Trait { + fn foo(&self, x: T) -> T { x } +} +struct F; +impl Trait for F {} + +struct S(F, T); + +impl Trait for S { + reuse to_reuse::foo { &self.0 } +} + +impl S { + reuse to_reuse::foo; +} + +fn main() { + let s = S(F, 42); + assert_eq!(S::::foo(F, 1), 1); + assert_eq!( as Trait<_>>::foo(&s, 1), 1); +} diff --git a/tests/ui/delegation/generics/impl-to-trait-method.rs b/tests/ui/delegation/generics/impl-to-trait-method.rs new file mode 100644 index 0000000000000..39e32e2ed1500 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-trait-method.rs @@ -0,0 +1,44 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod bounds { + trait Trait0 {} + + trait Trait1 { + fn foo(&self) + where + T: Trait0, + U: Trait0, + Self: Trait0, + //~^ ERROR the trait bound `bounds::S: Trait0` is not satisfied + { + } + } + + struct F; + impl Trait1 for F {} + + struct S(F); + + impl Trait1 for S { + reuse Trait1::::foo { &self.0 } + //~^ ERROR the trait bound `bounds::F: Trait0` is not satisfied + } +} + +mod unconstrained_parameter { + trait Trait { + fn foo(&self) {} + } + + struct F; + impl Trait for F {} + + struct S(F); + impl S { + reuse Trait::foo { &self.0 } + //~^ ERROR type annotations needed + } +} + +fn main() {} diff --git a/tests/ui/delegation/generics/impl-to-trait-method.stderr b/tests/ui/delegation/generics/impl-to-trait-method.stderr new file mode 100644 index 0000000000000..aeba30de043f5 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-trait-method.stderr @@ -0,0 +1,49 @@ +error[E0277]: the trait bound `bounds::S: Trait0` is not satisfied + --> $DIR/impl-to-trait-method.rs:12:19 + | +LL | Self: Trait0, + | ^^^^^^ the trait `Trait0` is not implemented for `bounds::S` + | +help: this trait has no implementations, consider adding one + --> $DIR/impl-to-trait-method.rs:5:5 + | +LL | trait Trait0 {} + | ^^^^^^^^^^^^ + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `bounds::F: Trait0` is not satisfied + --> $DIR/impl-to-trait-method.rs:24:34 + | +LL | reuse Trait1::::foo { &self.0 } + | --- ^^^^^^^ the trait `Trait0` is not implemented for `bounds::F` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/impl-to-trait-method.rs:5:5 + | +LL | trait Trait0 {} + | ^^^^^^^^^^^^ +note: required by a bound in `Trait1::foo` + --> $DIR/impl-to-trait-method.rs:12:19 + | +LL | fn foo(&self) + | --- required by a bound in this associated function +... +LL | Self: Trait0, + | ^^^^^^ required by this bound in `Trait1::foo` + +error[E0282]: type annotations needed + --> $DIR/impl-to-trait-method.rs:39:22 + | +LL | reuse Trait::foo { &self.0 } + | ^^^ cannot infer type for type parameter `T` declared on the trait `Trait` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0282. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs b/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs new file mode 100644 index 0000000000000..72440fe82d44d --- /dev/null +++ b/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs @@ -0,0 +1,77 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +use std::iter::{Iterator, Map}; + +pub mod same_trait { + use super::*; + + pub struct MapOuter { + pub inner: Map + } + + impl Iterator for MapOuter + where + F: FnMut(I::Item) -> B, + { + type Item = as Iterator>::Item; + + reuse Iterator::{next, fold} { self.inner } + } +} +use same_trait::MapOuter; + +mod another_trait { + use super::*; + + trait ZipImpl { + type Item; + + fn next(&mut self) -> Option; + } + + pub struct Zip { + pub a: A, + pub b: B, + } + + impl ZipImpl for Zip { + type Item = (A::Item, B::Item); + + fn next(&mut self) -> Option<(A::Item, B::Item)> { + let x = self.a.next()?; + let y = self.b.next()?; + Some((x, y)) + } + } + + impl Iterator for Zip { + type Item = (A::Item, B::Item); + + // Parameters are inherited from `Iterator::next`, not from `ZipImpl::next`. + // Otherwise, there would be a compilation error due to an unconstrained parameter. + reuse ZipImpl::next; + } +} +use another_trait::Zip; + +fn main() { + { + let x = vec![1, 2, 3]; + let iter = x.iter().map(|val| val * 2); + let outer_iter = MapOuter { inner: iter }; + let val = outer_iter.fold(0, |acc, x| acc + x); + assert_eq!(val, 12); + } + + { + let x = vec![1, 2]; + let y = vec![4, 5]; + + let mut zip = Zip { a: x.iter(), b: y.iter() }; + assert_eq!(zip.next(), Some((&1, &4))); + assert_eq!(zip.next(), Some((&2, &5))); + } +} diff --git a/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs b/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs new file mode 100644 index 0000000000000..6f3bb17897169 --- /dev/null +++ b/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs @@ -0,0 +1,23 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self, x: T, y: U) -> (T, U) { + (x, y) + } +} + +impl Trait for () {} +struct S(T, ()); + +impl S { + reuse Trait::foo { self.1 } +} + + +fn main() { + let s = S((), ()); + assert_eq!(s.foo(1u32, 2i32), (1u32, 2i32)); +} diff --git a/tests/ui/delegation/generics/trait-method-to-other-pass.rs b/tests/ui/delegation/generics/trait-method-to-other-pass.rs new file mode 100644 index 0000000000000..2094705a05ce6 --- /dev/null +++ b/tests/ui/delegation/generics/trait-method-to-other-pass.rs @@ -0,0 +1,30 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo(x: T) -> T { x } +} + +trait Trait1 { + fn foo(&self, _: T, x: U) -> U { x } +} + +#[derive(Default)] +struct F; + +impl Trait1 for F {} + +trait Trait2 { + fn get_f(&self) -> &F { &F } + reuse Trait1::foo as bar { self.get_f() } + reuse to_reuse::foo as baz; +} + +impl Trait2 for F {} + +fn main() { + assert_eq!(F.bar(1u8, 2u16), 2u16); + assert_eq!(F::baz(1u8), 1u8); +} diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs index 3bfae8face597..ee2bf9e33eb89 100644 --- a/tests/ui/delegation/ice-issue-124347.rs +++ b/tests/ui/delegation/ice-issue-124347.rs @@ -1,12 +1,12 @@ #![feature(fn_delegation)] #![allow(incomplete_features)] +// FIXME(fn_delegation): `recursive delegation` error should be emitted here trait Trait { reuse Trait::foo { &self.0 } - //~^ ERROR recursive delegation is not supported yet + //~^ ERROR cycle detected when computing generics of `Trait::foo` } -// FIXME(fn_delegation): `recursive delegation` error should be emitted here reuse foo; //~^ ERROR cycle detected when computing generics of `foo` diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr index 87dd75ffec82c..bd0bc970b94c2 100644 --- a/tests/ui/delegation/ice-issue-124347.stderr +++ b/tests/ui/delegation/ice-issue-124347.stderr @@ -1,8 +1,16 @@ -error: recursive delegation is not supported yet - --> $DIR/ice-issue-124347.rs:5:18 +error[E0391]: cycle detected when computing generics of `Trait::foo` + --> $DIR/ice-issue-124347.rs:6:18 | LL | reuse Trait::foo { &self.0 } - | ^^^ callee defined here + | ^^^ + | + = note: ...which immediately requires computing generics of `Trait::foo` again +note: cycle used when inheriting delegation signature + --> $DIR/ice-issue-124347.rs:6:18 + | +LL | reuse Trait::foo { &self.0 } + | ^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error[E0391]: cycle detected when computing generics of `foo` --> $DIR/ice-issue-124347.rs:10:7 diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs deleted file mode 100644 index d5ac68ecf1b8a..0000000000000 --- a/tests/ui/delegation/not-supported.rs +++ /dev/null @@ -1,116 +0,0 @@ -#![feature(const_trait_impl)] -#![feature(c_variadic)] -#![feature(effects)] -#![feature(fn_delegation)] -#![allow(incomplete_features)] - -mod generics { - trait GenericTrait { - fn bar(&self, x: T) -> T { x } - fn bar1() {} - } - trait Trait { - fn foo(&self, x: i32) -> i32 { x } - fn foo1<'a>(&self, x: &'a i32) -> &'a i32 { x } - fn foo2(&self, x: T) -> T { x } - fn foo3<'a: 'a>(_: &'a u32) {} - - reuse GenericTrait::bar; - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - struct F; - impl Trait for F {} - impl GenericTrait for F {} - - struct S(F); - - impl GenericTrait for S { - reuse >::bar { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl GenericTrait<()> for () { - reuse GenericTrait::bar { &F } - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl Trait for &S { - reuse Trait::foo; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl Trait for S { - reuse Trait::foo1 { &self.0 } - reuse Trait::foo2 { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - //~| ERROR method `foo2` has 0 type parameters but its trait declaration has 1 type parameter - reuse ::foo3; - //~^ ERROR early bound generics are not supported for associated delegation items - //~| ERROR lifetime parameters or bounds on associated function `foo3` do not match the trait declaration - } - - struct GenericS(T); - impl Trait for GenericS { - reuse Trait::foo { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - } -} - -mod opaque { - trait Trait {} - impl Trait for () {} - - mod to_reuse { - use super::Trait; - - pub fn opaque_ret() -> impl Trait { unimplemented!() } - //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - } - - trait ToReuse { - fn opaque_ret() -> impl Trait { unimplemented!() } - //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - } - - // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. - impl ToReuse for u8 { - reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type - } - impl ToReuse for u16 { - reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type - } -} - -mod recursive { - mod to_reuse1 { - pub mod to_reuse2 { - pub fn foo() {} - } - - pub reuse to_reuse2::foo; - } - - reuse to_reuse1::foo; - //~^ ERROR recursive delegation is not supported yet -} - -mod effects { - #[const_trait] - trait Trait { - fn foo(); - } - - reuse Trait::foo; - //~^ ERROR delegation to a function with effect parameter is not supported yet -} - -fn main() {} diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr deleted file mode 100644 index 14d6b374bd2c4..0000000000000 --- a/tests/ui/delegation/not-supported.stderr +++ /dev/null @@ -1,204 +0,0 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:18:29 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse GenericTrait::bar; - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:20:29 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:31:39 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse >::bar { &self.0 } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:33:34 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:38:29 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse GenericTrait::bar { &F } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:40:29 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:45:22 - | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo; - | ^^^ - -error[E0049]: method `foo2` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/not-supported.rs:51:22 - | -LL | fn foo2(&self, x: T) -> T { x } - | - expected 1 type parameter -... -LL | reuse Trait::foo2 { &self.0 } - | ^^^^ found 0 type parameters - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:54:29 - | -LL | fn foo3<'a: 'a>(_: &'a u32) {} - | --------------------------- callee defined here -... -LL | reuse ::foo3; - | ^^^^ - -error[E0195]: lifetime parameters or bounds on associated function `foo3` do not match the trait declaration - --> $DIR/not-supported.rs:54:29 - | -LL | fn foo3<'a: 'a>(_: &'a u32) {} - | -------- lifetimes in impl do not match this associated function in trait -... -LL | reuse ::foo3; - | ^^^^ lifetimes do not match associated function in trait - -error: delegation to a function with effect parameter is not supported yet - --> $DIR/not-supported.rs:112:18 - | -LL | fn foo(); - | --------- callee defined here -... -LL | reuse Trait::foo; - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:61:22 - | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo { &self.0 } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:51:22 - | -LL | fn foo2(&self, x: T) -> T { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo2 { &self.0 } - | ^^^^ - -warning: this function depends on never type fallback being `()` - --> $DIR/not-supported.rs:79:9 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #123748 - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/not-supported.rs:79:28 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default - -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:86:25 - | -LL | reuse to_reuse::opaque_ret; - | ^^^^^^^^^^ - | -note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/not-supported.rs:86:25 - | -LL | reuse to_reuse::opaque_ret; - | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::` is well-formed - --> $DIR/not-supported.rs:85:5 - | -LL | impl ToReuse for u8 { - | ^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -warning: this function depends on never type fallback being `()` - --> $DIR/not-supported.rs:73:9 - | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #123748 - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/not-supported.rs:73:32 - | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:89:24 - | -LL | reuse ToReuse::opaque_ret; - | ^^^^^^^^^^ - | -note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/not-supported.rs:89:24 - | -LL | reuse ToReuse::opaque_ret; - | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::` is well-formed - --> $DIR/not-supported.rs:88:5 - | -LL | impl ToReuse for u16 { - | ^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: recursive delegation is not supported yet - --> $DIR/not-supported.rs:102:22 - | -LL | pub reuse to_reuse2::foo; - | --- callee defined here -... -LL | reuse to_reuse1::foo; - | ^^^ - -error: aborting due to 17 previous errors; 2 warnings emitted - -Some errors have detailed explanations: E0049, E0195, E0391. -For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs new file mode 100644 index 0000000000000..e57effff48d81 --- /dev/null +++ b/tests/ui/delegation/unsupported.rs @@ -0,0 +1,57 @@ +#![feature(const_trait_impl)] +#![feature(c_variadic)] +#![feature(effects)] +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod opaque { + trait Trait {} + impl Trait for () {} + + mod to_reuse { + use super::Trait; + + pub fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + } + + trait ToReuse { + fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + } + + // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. + impl ToReuse for u8 { + reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type + } + impl ToReuse for u16 { + reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type + } +} + +mod recursive { + mod to_reuse1 { + pub mod to_reuse2 { + pub fn foo() {} + } + + pub reuse to_reuse2::foo; + } + + reuse to_reuse1::foo; + //~^ ERROR recursive delegation is not supported yet +} + +mod effects { + #[const_trait] + trait Trait { + fn foo(); + } + + reuse Trait::foo; + //~^ ERROR delegation to a function with effect parameter is not supported yet +} + +fn main() {} diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr new file mode 100644 index 0000000000000..03ded300bb446 --- /dev/null +++ b/tests/ui/delegation/unsupported.stderr @@ -0,0 +1,95 @@ +error: using `#![feature(effects)]` without enabling next trait solver globally + | + = note: the next trait solver must be enabled globally for the effects feature to work correctly + = help: use `-Znext-solver` to enable + +warning: this function depends on never type fallback being `()` + --> $DIR/unsupported.rs:20:9 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/unsupported.rs:20:28 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/unsupported.rs:27:25 + | +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/unsupported.rs:27:25 + | +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/unsupported.rs:26:5 + | +LL | impl ToReuse for u8 { + | ^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +warning: this function depends on never type fallback being `()` + --> $DIR/unsupported.rs:14:9 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/unsupported.rs:14:32 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ + +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/unsupported.rs:30:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/unsupported.rs:30:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/unsupported.rs:29:5 + | +LL | impl ToReuse for u16 { + | ^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: recursive delegation is not supported yet + --> $DIR/unsupported.rs:43:22 + | +LL | pub reuse to_reuse2::foo; + | --- callee defined here +... +LL | reuse to_reuse1::foo; + | ^^^ + +error: delegation to a function with effect parameter is not supported yet + --> $DIR/unsupported.rs:53:18 + | +LL | fn foo(); + | --------- callee defined here +... +LL | reuse Trait::foo; + | ^^^ + +error: aborting due to 5 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/drop/drop-struct-as-object.rs b/tests/ui/drop/drop-struct-as-object.rs index 07c8950f1b2ba..46633bd70751f 100644 --- a/tests/ui/drop/drop-struct-as-object.rs +++ b/tests/ui/drop/drop-struct-as-object.rs @@ -5,6 +5,9 @@ // Test that destructor on a struct runs successfully after the struct // is boxed and converted to an object. +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] + static mut value: usize = 0; struct Cat { diff --git a/tests/ui/drop/drop-struct-as-object.stderr b/tests/ui/drop/drop-struct-as-object.stderr index 10527c968ed70..16f6d1110babd 100644 --- a/tests/ui/drop/drop-struct-as-object.stderr +++ b/tests/ui/drop/drop-struct-as-object.stderr @@ -1,5 +1,5 @@ warning: method `get` is never used - --> $DIR/drop-struct-as-object.rs:15:8 + --> $DIR/drop-struct-as-object.rs:18:8 | LL | trait Dummy { | ----- method in this trait diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs index 54e9e491f7873..cf06253800745 100644 --- a/tests/ui/drop/drop_order.rs +++ b/tests/ui/drop/drop_order.rs @@ -1,6 +1,11 @@ //@ run-pass //@ compile-flags: -Z validate-mir +//@ revisions: edition2021 edition2024 +//@ [edition2021] edition: 2021 +//@ [edition2024] compile-flags: -Z unstable-options +//@ [edition2024] edition: 2024 #![feature(let_chains)] +#![cfg_attr(edition2024, feature(if_let_rescope))] use std::cell::RefCell; use std::convert::TryInto; @@ -55,11 +60,18 @@ impl DropOrderCollector { } fn if_let(&self) { + #[cfg(edition2021)] if let None = self.option_loud_drop(2) { unreachable!(); } else { self.print(1); } + #[cfg(edition2024)] + if let None = self.option_loud_drop(1) { + unreachable!(); + } else { + self.print(2); + } if let Some(_) = self.option_loud_drop(4) { self.print(3); @@ -194,6 +206,7 @@ impl DropOrderCollector { self.print(3); // 3 } + #[cfg(edition2021)] // take the "else" branch if self.option_loud_drop(5).is_some() // 1 && self.option_loud_drop(6).is_some() // 2 @@ -202,6 +215,15 @@ impl DropOrderCollector { } else { self.print(7); // 3 } + #[cfg(edition2024)] + // take the "else" branch + if self.option_loud_drop(5).is_some() // 1 + && self.option_loud_drop(6).is_some() // 2 + && let None = self.option_loud_drop(7) { // 4 + unreachable!(); + } else { + self.print(8); // 3 + } // let exprs interspersed if self.option_loud_drop(9).is_some() // 1 diff --git a/tests/ui/drop/drop_order_if_let_rescope.rs b/tests/ui/drop/drop_order_if_let_rescope.rs new file mode 100644 index 0000000000000..ae9f381820e16 --- /dev/null +++ b/tests/ui/drop/drop_order_if_let_rescope.rs @@ -0,0 +1,122 @@ +//@ run-pass +//@ edition:2024 +//@ compile-flags: -Z validate-mir -Zunstable-options + +#![feature(let_chains)] +#![feature(if_let_rescope)] + +use std::cell::RefCell; +use std::convert::TryInto; + +#[derive(Default)] +struct DropOrderCollector(RefCell>); + +struct LoudDrop<'a>(&'a DropOrderCollector, u32); + +impl Drop for LoudDrop<'_> { + fn drop(&mut self) { + println!("{}", self.1); + self.0.0.borrow_mut().push(self.1); + } +} + +impl DropOrderCollector { + fn option_loud_drop(&self, n: u32) -> Option { + Some(LoudDrop(self, n)) + } + + fn print(&self, n: u32) { + println!("{}", n); + self.0.borrow_mut().push(n) + } + + fn assert_sorted(self) { + assert!( + self.0 + .into_inner() + .into_iter() + .enumerate() + .all(|(idx, item)| idx + 1 == item.try_into().unwrap()) + ); + } + + fn if_let(&self) { + if let None = self.option_loud_drop(1) { + unreachable!(); + } else { + self.print(2); + } + + if let Some(_) = self.option_loud_drop(4) { + self.print(3); + } + + if let Some(_d) = self.option_loud_drop(6) { + self.print(5); + } + } + + fn let_chain(&self) { + // take the "then" branch + if self.option_loud_drop(1).is_some() // 1 + && self.option_loud_drop(2).is_some() // 2 + && let Some(_d) = self.option_loud_drop(4) + // 4 + { + self.print(3); // 3 + } + + // take the "else" branch + if self.option_loud_drop(5).is_some() // 1 + && self.option_loud_drop(6).is_some() // 2 + && let None = self.option_loud_drop(7) + // 3 + { + unreachable!(); + } else { + self.print(8); // 4 + } + + // let exprs interspersed + if self.option_loud_drop(9).is_some() // 1 + && let Some(_d) = self.option_loud_drop(13) // 5 + && self.option_loud_drop(10).is_some() // 2 + && let Some(_e) = self.option_loud_drop(12) + // 4 + { + self.print(11); // 3 + } + + // let exprs first + if let Some(_d) = self.option_loud_drop(18) // 5 + && let Some(_e) = self.option_loud_drop(17) // 4 + && self.option_loud_drop(14).is_some() // 1 + && self.option_loud_drop(15).is_some() + // 2 + { + self.print(16); // 3 + } + + // let exprs last + if self.option_loud_drop(19).is_some() // 1 + && self.option_loud_drop(20).is_some() // 2 + && let Some(_d) = self.option_loud_drop(23) // 5 + && let Some(_e) = self.option_loud_drop(22) + // 4 + { + self.print(21); // 3 + } + } +} + +fn main() { + println!("-- if let --"); + let collector = DropOrderCollector::default(); + collector.if_let(); + collector.assert_sorted(); + + println!("-- let chain --"); + let collector = DropOrderCollector::default(); + collector.let_chain(); + collector.assert_sorted(); +} diff --git a/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs b/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs new file mode 100644 index 0000000000000..2476f7cf2580a --- /dev/null +++ b/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs @@ -0,0 +1,33 @@ +//@ edition: 2024 +//@ compile-flags: -Z validate-mir -Zunstable-options + +#![feature(if_let_rescope)] +#![deny(if_let_rescope)] + +struct Droppy; +impl Drop for Droppy { + fn drop(&mut self) { + println!("dropped"); + } +} +impl Droppy { + fn get_ref(&self) -> Option<&u8> { + None + } +} + +fn do_something(_: &T) {} + +fn main() { + do_something(if let Some(value) = Droppy.get_ref() { value } else { &0 }); + //~^ ERROR: temporary value dropped while borrowed + do_something(if let Some(value) = Droppy.get_ref() { + //~^ ERROR: temporary value dropped while borrowed + value + } else if let Some(value) = Droppy.get_ref() { + //~^ ERROR: temporary value dropped while borrowed + value + } else { + &0 + }); +} diff --git a/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr b/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr new file mode 100644 index 0000000000000..0c6f1ea28d2ae --- /dev/null +++ b/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr @@ -0,0 +1,89 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/if-let-rescope-borrowck-suggestions.rs:22:39 + | +LL | do_something(if let Some(value) = Droppy.get_ref() { value } else { &0 }); + | ^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use + | +note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead + --> $DIR/if-let-rescope-borrowck-suggestions.rs:22:64 + | +LL | do_something(if let Some(value) = Droppy.get_ref() { value } else { &0 }); + | ^ +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = Droppy; +LL ~ do_something(if let Some(value) = binding.get_ref() { value } else { &0 }); + | +help: consider rewriting the `if` into `match` which preserves the extended lifetime + | +LL | do_something({ match Droppy.get_ref() { Some(value) => { value } _ => { &0 }}}); + | ~~~~~~~ ++++++++++++++++ ~~~~ ++ + +error[E0716]: temporary value dropped while borrowed + --> $DIR/if-let-rescope-borrowck-suggestions.rs:24:39 + | +LL | do_something(if let Some(value) = Droppy.get_ref() { + | ^^^^^^ creates a temporary value which is freed while still in use +... +LL | } else if let Some(value) = Droppy.get_ref() { + | - temporary value is freed at the end of this statement + | +note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead + --> $DIR/if-let-rescope-borrowck-suggestions.rs:27:5 + | +LL | } else if let Some(value) = Droppy.get_ref() { + | ^ +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = Droppy; +LL ~ do_something(if let Some(value) = binding.get_ref() { + | +help: consider rewriting the `if` into `match` which preserves the extended lifetime + | +LL ~ do_something({ match Droppy.get_ref() { Some(value) => { +LL | +LL | value +LL ~ } _ => if let Some(value) = Droppy.get_ref() { +LL | +... +LL | &0 +LL ~ }}}); + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/if-let-rescope-borrowck-suggestions.rs:27:33 + | +LL | } else if let Some(value) = Droppy.get_ref() { + | ^^^^^^ creates a temporary value which is freed while still in use +... +LL | } else { + | - temporary value is freed at the end of this statement + | +note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead + --> $DIR/if-let-rescope-borrowck-suggestions.rs:30:5 + | +LL | } else { + | ^ +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = Droppy; +LL ~ do_something(if let Some(value) = Droppy.get_ref() { +LL | +LL | value +LL ~ } else if let Some(value) = binding.get_ref() { + | +help: consider rewriting the `if` into `match` which preserves the extended lifetime + | +LL ~ } else { match Droppy.get_ref() { Some(value) => { +LL | +LL | value +LL ~ } _ => { +LL | &0 +LL ~ }}}); + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs index 1fa68a2e73813..6fee4520cbcc1 100644 --- a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs @@ -1,5 +1,7 @@ //@ run-pass #![allow(non_upper_case_globals)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] // This test is ensuring that parameters are indeed dropped after // temporaries in a fn body. @@ -91,7 +93,6 @@ pub mod d { pub fn max_width() -> u32 { unsafe { (mem::size_of_val(&trails) * 8) as u32 - //~^ WARN shared reference to mutable static is discouraged [static_mut_refs] } } diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr deleted file mode 100644 index 9126e6023913d..0000000000000 --- a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: creating a shared reference to mutable static is discouraged - --> $DIR/issue-23338-ensure-param-drop-order.rs:93:31 - | -LL | (mem::size_of_val(&trails) * 8) as u32 - | ^^^^^^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer - | -LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 - | ~~~~~~~~~ + - -warning: 1 warning emitted - diff --git a/tests/ui/drop/issue-23611-enum-swap-in-drop.rs b/tests/ui/drop/issue-23611-enum-swap-in-drop.rs index 1afaff0f735be..410b07b16fc77 100644 --- a/tests/ui/drop/issue-23611-enum-swap-in-drop.rs +++ b/tests/ui/drop/issue-23611-enum-swap-in-drop.rs @@ -1,5 +1,7 @@ //@ run-pass #![allow(non_upper_case_globals)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] // Issue 23611: this test is ensuring that, for an instance `X` of the // enum `E`, if you swap in a different variant during the execution @@ -187,7 +189,6 @@ pub mod d { pub fn max_width() -> u32 { unsafe { (mem::size_of_val(&trails) * 8) as u32 - //~^ WARN shared reference to mutable static is discouraged [static_mut_refs] } } diff --git a/tests/ui/drop/issue-23611-enum-swap-in-drop.stderr b/tests/ui/drop/issue-23611-enum-swap-in-drop.stderr deleted file mode 100644 index 6da8741680274..0000000000000 --- a/tests/ui/drop/issue-23611-enum-swap-in-drop.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: creating a shared reference to mutable static is discouraged - --> $DIR/issue-23611-enum-swap-in-drop.rs:189:31 - | -LL | (mem::size_of_val(&trails) * 8) as u32 - | ^^^^^^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer - | -LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 - | ~~~~~~~~~ + - -warning: 1 warning emitted - diff --git a/tests/ui/drop/issue-48962.rs b/tests/ui/drop/issue-48962.rs index 428a6ca6cd21b..98d3af49ac1ec 100644 --- a/tests/ui/drop/issue-48962.rs +++ b/tests/ui/drop/issue-48962.rs @@ -1,6 +1,9 @@ //@ run-pass #![allow(unused_must_use)] // Test that we are able to reinitialize box with moved referent +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + static mut ORDER: [usize; 3] = [0, 0, 0]; static mut INDEX: usize = 0; diff --git a/tests/ui/drop/lint-if-let-rescope-gated.rs b/tests/ui/drop/lint-if-let-rescope-gated.rs new file mode 100644 index 0000000000000..cef5de5a8fe56 --- /dev/null +++ b/tests/ui/drop/lint-if-let-rescope-gated.rs @@ -0,0 +1,34 @@ +// This test checks that the lint `if_let_rescope` only actions +// when the feature gate is enabled. +// Edition 2021 is used here because the lint should work especially +// when edition migration towards 2024 is run. + +//@ revisions: with_feature_gate without_feature_gate +//@ [without_feature_gate] check-pass +//@ edition: 2021 + +#![cfg_attr(with_feature_gate, feature(if_let_rescope))] +#![deny(if_let_rescope)] +#![allow(irrefutable_let_patterns)] + +struct Droppy; +impl Drop for Droppy { + fn drop(&mut self) { + println!("dropped"); + } +} +impl Droppy { + fn get(&self) -> Option { + None + } +} + +fn main() { + if let Some(_value) = Droppy.get() { + //[with_feature_gate]~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //[with_feature_gate]~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + //[with_feature_gate]~| WARN: this changes meaning in Rust 2024 + } else { + //[with_feature_gate]~^ HELP: the value is now dropped here in Edition 2024 + } +} diff --git a/tests/ui/drop/lint-if-let-rescope-gated.with_feature_gate.stderr b/tests/ui/drop/lint-if-let-rescope-gated.with_feature_gate.stderr new file mode 100644 index 0000000000000..48b7f3e11a682 --- /dev/null +++ b/tests/ui/drop/lint-if-let-rescope-gated.with_feature_gate.stderr @@ -0,0 +1,33 @@ +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope-gated.rs:27:8 + | +LL | if let Some(_value) = Droppy.get() { + | ^^^^^^^^^^^^^^^^^^^------^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope-gated.rs:31:5 + | +LL | } else { + | ^ +note: the lint level is defined here + --> $DIR/lint-if-let-rescope-gated.rs:11:9 + | +LL | #![deny(if_let_rescope)] + | ^^^^^^^^^^^^^^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match Droppy.get() { Some(_value) => { +LL | +LL | +LL | +LL ~ } _ => { +LL | +LL ~ }} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.rs b/tests/ui/drop/lint-if-let-rescope-with-macro.rs new file mode 100644 index 0000000000000..282b3320d3004 --- /dev/null +++ b/tests/ui/drop/lint-if-let-rescope-with-macro.rs @@ -0,0 +1,41 @@ +// This test ensures that no suggestion is emitted if the span originates from +// an expansion that is probably not under a user's control. + +//@ edition:2021 +//@ compile-flags: -Z unstable-options + +#![feature(if_let_rescope)] +#![deny(if_let_rescope)] +#![allow(irrefutable_let_patterns)] + +macro_rules! edition_2021_if_let { + ($p:pat, $e:expr, { $($conseq:tt)* } { $($alt:tt)* }) => { + if let $p = $e { $($conseq)* } else { $($alt)* } + //~^ ERROR `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN this changes meaning in Rust 2024 + } +} + +fn droppy() -> Droppy { + Droppy +} +struct Droppy; +impl Drop for Droppy { + fn drop(&mut self) { + println!("dropped"); + } +} +impl Droppy { + fn get(&self) -> Option { + None + } +} + +fn main() { + edition_2021_if_let! { + Some(_value), + droppy().get(), + {} + {} + }; +} diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr new file mode 100644 index 0000000000000..5fd0c61d17a57 --- /dev/null +++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr @@ -0,0 +1,39 @@ +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope-with-macro.rs:13:12 + | +LL | if let $p = $e { $($conseq)* } else { $($alt)* } + | ^^^ +... +LL | / edition_2021_if_let! { +LL | | Some(_value), +LL | | droppy().get(), + | | -------- this value has a significant drop implementation which may observe a major change in drop order and requires your discretion +LL | | {} +LL | | {} +LL | | }; + | |_____- in this macro invocation + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope-with-macro.rs:13:38 + | +LL | if let $p = $e { $($conseq)* } else { $($alt)* } + | ^ +... +LL | / edition_2021_if_let! { +LL | | Some(_value), +LL | | droppy().get(), +LL | | {} +LL | | {} +LL | | }; + | |_____- in this macro invocation +note: the lint level is defined here + --> $DIR/lint-if-let-rescope-with-macro.rs:8:9 + | +LL | #![deny(if_let_rescope)] + | ^^^^^^^^^^^^^^ + = note: this error originates in the macro `edition_2021_if_let` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/drop/lint-if-let-rescope.fixed b/tests/ui/drop/lint-if-let-rescope.fixed new file mode 100644 index 0000000000000..f228783f88bc5 --- /dev/null +++ b/tests/ui/drop/lint-if-let-rescope.fixed @@ -0,0 +1,71 @@ +//@ run-rustfix + +#![deny(if_let_rescope)] +#![feature(if_let_rescope)] +#![allow(irrefutable_let_patterns)] + +fn droppy() -> Droppy { + Droppy +} +struct Droppy; +impl Drop for Droppy { + fn drop(&mut self) { + println!("dropped"); + } +} +impl Droppy { + fn get(&self) -> Option { + None + } +} + +fn main() { + if let Some(_value) = droppy().get() { + // Should not lint + } + + match droppy().get() { Some(_value) => { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + // do something + } _ => { + //~^ HELP: the value is now dropped here in Edition 2024 + // do something else + }} + + match droppy().get() { Some(_value) => { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + // do something + } _ => { match droppy().get() { Some(_value) => { + //~^ HELP: the value is now dropped here in Edition 2024 + // do something else + } _ => {}}}} + //~^ HELP: the value is now dropped here in Edition 2024 + + if droppy().get().is_some() { + // Should not lint + } else { match droppy().get() { Some(_value) => { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + } _ => if droppy().get().is_none() { + //~^ HELP: the value is now dropped here in Edition 2024 + }}} + + if let Some(1) = { match Droppy.get() { Some(_value) => { Some(1) } _ => { None }} } { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + } + + if let () = { match Droppy.get() { Some(_value) => {} _ => {}} } { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + } +} diff --git a/tests/ui/drop/lint-if-let-rescope.rs b/tests/ui/drop/lint-if-let-rescope.rs new file mode 100644 index 0000000000000..241fb897fce17 --- /dev/null +++ b/tests/ui/drop/lint-if-let-rescope.rs @@ -0,0 +1,71 @@ +//@ run-rustfix + +#![deny(if_let_rescope)] +#![feature(if_let_rescope)] +#![allow(irrefutable_let_patterns)] + +fn droppy() -> Droppy { + Droppy +} +struct Droppy; +impl Drop for Droppy { + fn drop(&mut self) { + println!("dropped"); + } +} +impl Droppy { + fn get(&self) -> Option { + None + } +} + +fn main() { + if let Some(_value) = droppy().get() { + // Should not lint + } + + if let Some(_value) = droppy().get() { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + // do something + } else { + //~^ HELP: the value is now dropped here in Edition 2024 + // do something else + } + + if let Some(_value) = droppy().get() { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + // do something + } else if let Some(_value) = droppy().get() { + //~^ HELP: the value is now dropped here in Edition 2024 + // do something else + } + //~^ HELP: the value is now dropped here in Edition 2024 + + if droppy().get().is_some() { + // Should not lint + } else if let Some(_value) = droppy().get() { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + } else if droppy().get().is_none() { + //~^ HELP: the value is now dropped here in Edition 2024 + } + + if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else { None } } { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + } + + if let () = { if let Some(_value) = Droppy.get() {} } { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + } +} diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr new file mode 100644 index 0000000000000..25ca3cf1ca873 --- /dev/null +++ b/tests/ui/drop/lint-if-let-rescope.stderr @@ -0,0 +1,135 @@ +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope.rs:27:8 + | +LL | if let Some(_value) = droppy().get() { + | ^^^^^^^^^^^^^^^^^^^--------^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope.rs:32:5 + | +LL | } else { + | ^ +note: the lint level is defined here + --> $DIR/lint-if-let-rescope.rs:3:9 + | +LL | #![deny(if_let_rescope)] + | ^^^^^^^^^^^^^^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match droppy().get() { Some(_value) => { +LL | +... +LL | // do something +LL ~ } _ => { +LL | +LL | // do something else +LL ~ }} + | + +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope.rs:37:8 + | +LL | if let Some(_value) = droppy().get() { + | ^^^^^^^^^^^^^^^^^^^--------^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion +... +LL | } else if let Some(_value) = droppy().get() { + | -------- this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope.rs:42:5 + | +LL | } else if let Some(_value) = droppy().get() { + | ^ +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope.rs:45:5 + | +LL | } + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match droppy().get() { Some(_value) => { +LL | +... +LL | // do something +LL ~ } _ => { match droppy().get() { Some(_value) => { +LL | +LL | // do something else +LL ~ } _ => {}}}} + | + +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope.rs:50:15 + | +LL | } else if let Some(_value) = droppy().get() { + | ^^^^^^^^^^^^^^^^^^^--------^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope.rs:54:5 + | +LL | } else if droppy().get().is_none() { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ } else { match droppy().get() { Some(_value) => { +LL | +LL | +LL | +LL ~ } _ => if droppy().get().is_none() { +LL | +LL ~ }}} + | + +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope.rs:58:27 + | +LL | if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else { None } } { + | ^^^^^^^^^^^^^^^^^^^------^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope.rs:58:69 + | +LL | if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else { None } } { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL | if let Some(1) = { match Droppy.get() { Some(_value) => { Some(1) } _ => { None }} } { + | ~~~~~ +++++++++++++++++ ~~~~ + + +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope.rs:65:22 + | +LL | if let () = { if let Some(_value) = Droppy.get() {} } { + | ^^^^^^^^^^^^^^^^^^^------^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope.rs:65:55 + | +LL | if let () = { if let Some(_value) = Droppy.get() {} } { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL | if let () = { match Droppy.get() { Some(_value) => {} _ => {}} } { + | ~~~~~ +++++++++++++++++ ++++++++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/drop/repeat-drop.rs b/tests/ui/drop/repeat-drop.rs index b83bee8c1bf82..7488d9113b0af 100644 --- a/tests/ui/drop/repeat-drop.rs +++ b/tests/ui/drop/repeat-drop.rs @@ -3,6 +3,9 @@ #![allow(dropping_references, dropping_copy_types)] +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] + static mut CHECK: usize = 0; struct DropChecker(usize); diff --git a/tests/ui/issues/issue-17302.rs b/tests/ui/drop/static-issue-17302.rs similarity index 82% rename from tests/ui/issues/issue-17302.rs rename to tests/ui/drop/static-issue-17302.rs index c499cc5281f3a..060f5564efdae 100644 --- a/tests/ui/issues/issue-17302.rs +++ b/tests/ui/drop/static-issue-17302.rs @@ -1,5 +1,8 @@ //@ run-pass +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + static mut DROPPED: [bool; 2] = [false, false]; struct A(usize); diff --git a/tests/ui/dropck/dropck_trait_cycle_checked.stderr b/tests/ui/dropck/dropck_trait_cycle_checked.stderr index 63fd07a91633d..f32736f1a674c 100644 --- a/tests/ui/dropck/dropck_trait_cycle_checked.stderr +++ b/tests/ui/dropck/dropck_trait_cycle_checked.stderr @@ -2,7 +2,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:111:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` LL | o1.set0(&o2); | ^^^ borrowed value does not live long enough ... @@ -15,7 +15,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:112:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o3` declared here -------- cast requires that `o3` is borrowed for `'static` + | -- binding `o3` declared here -------- coercion requires that `o3` is borrowed for `'static` LL | o1.set0(&o2); LL | o1.set1(&o3); | ^^^ borrowed value does not live long enough @@ -29,7 +29,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:113:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` ... LL | o2.set0(&o2); | ^^^ borrowed value does not live long enough @@ -43,7 +43,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:114:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o3` declared here -------- cast requires that `o3` is borrowed for `'static` + | -- binding `o3` declared here -------- coercion requires that `o3` is borrowed for `'static` ... LL | o2.set1(&o3); | ^^^ borrowed value does not live long enough @@ -57,7 +57,7 @@ error[E0597]: `o1` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:115:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o1` declared here -------- cast requires that `o1` is borrowed for `'static` + | -- binding `o1` declared here -------- coercion requires that `o1` is borrowed for `'static` ... LL | o3.set0(&o1); | ^^^ borrowed value does not live long enough @@ -71,7 +71,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:116:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` ... LL | o3.set1(&o2); | ^^^ borrowed value does not live long enough diff --git a/tests/ui/duplicate/multiple-types-with-same-name-and-derive.rs b/tests/ui/duplicate/multiple-types-with-same-name-and-derive.rs new file mode 100644 index 0000000000000..8d36981b41b2f --- /dev/null +++ b/tests/ui/duplicate/multiple-types-with-same-name-and-derive.rs @@ -0,0 +1,19 @@ +// Here, there are two types with the same name. One of these has a `derive` annotation, but in the +// expansion these `impl`s are associated to the the *other* type. There is a suggestion to remove +// unneded type parameters, but because we're now point at a type with no type parameters, the +// suggestion would suggest removing code from an empty span, which would ICE in nightly. +// +// issue: rust-lang/rust#108748 + +struct NotSM; + +#[derive(PartialEq, Eq)] +//~^ ERROR struct takes 0 generic arguments +//~| ERROR struct takes 0 generic arguments +//~| ERROR struct takes 0 generic arguments +//~| ERROR struct takes 0 generic arguments +struct NotSM(T); +//~^ ERROR the name `NotSM` is defined multiple times +//~| ERROR no field `0` + +fn main() {} diff --git a/tests/ui/duplicate/multiple-types-with-same-name-and-derive.stderr b/tests/ui/duplicate/multiple-types-with-same-name-and-derive.stderr new file mode 100644 index 0000000000000..32c3cf4403169 --- /dev/null +++ b/tests/ui/duplicate/multiple-types-with-same-name-and-derive.stderr @@ -0,0 +1,71 @@ +error[E0428]: the name `NotSM` is defined multiple times + --> $DIR/multiple-types-with-same-name-and-derive.rs:15:1 + | +LL | struct NotSM; + | ------------- previous definition of the type `NotSM` here +... +LL | struct NotSM(T); + | ^^^^^^^^^^^^^^^^^^^ `NotSM` redefined here + | + = note: `NotSM` must be defined only once in the type namespace of this module + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive.rs:10:10 + | +LL | #[derive(PartialEq, Eq)] + | ^^^^^^^^^ expected 0 generic arguments + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive.rs:8:8 + | +LL | struct NotSM; + | ^^^^^ + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive.rs:10:10 + | +LL | #[derive(PartialEq, Eq)] + | ^^^^^^^^^ expected 0 generic arguments + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive.rs:8:8 + | +LL | struct NotSM; + | ^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive.rs:10:21 + | +LL | #[derive(PartialEq, Eq)] + | ^^ expected 0 generic arguments + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive.rs:8:8 + | +LL | struct NotSM; + | ^^^^^ + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive.rs:10:10 + | +LL | #[derive(PartialEq, Eq)] + | ^^^^^^^^^ expected 0 generic arguments + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive.rs:8:8 + | +LL | struct NotSM; + | ^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0609]: no field `0` on type `&NotSM` + --> $DIR/multiple-types-with-same-name-and-derive.rs:15:17 + | +LL | struct NotSM(T); + | ^ unknown field + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0107, E0428, E0609. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr index b39689afd1ca6..52ee6c81ab794 100644 --- a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr +++ b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr @@ -4,7 +4,15 @@ error[E0782]: trait objects must include the `dyn` keyword LL | fn function(x: &SomeTrait, y: Box) { | ^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: use a new generic type parameter, constrained by `SomeTrait` + | +LL | fn function(x: &T, y: Box) { + | ++++++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn function(x: &impl SomeTrait, y: Box) { + | ++++ +help: alternatively, use a trait object to accept any type that implements `SomeTrait`, accessing its methods at runtime using dynamic dispatch | LL | fn function(x: &dyn SomeTrait, y: Box) { | +++ diff --git a/tests/ui/dyn-star/dyn-to-rigid.rs b/tests/ui/dyn-star/dyn-to-rigid.rs index e80ee15902eef..dc33e288f24e6 100644 --- a/tests/ui/dyn-star/dyn-to-rigid.rs +++ b/tests/ui/dyn-star/dyn-to-rigid.rs @@ -5,7 +5,7 @@ trait Tr {} fn f(x: dyn* Tr) -> usize { x as usize - //~^ ERROR casting `(dyn* Tr + 'static)` as `usize` is invalid + //~^ ERROR non-primitive cast: `(dyn* Tr + 'static)` as `usize` } fn main() {} diff --git a/tests/ui/dyn-star/dyn-to-rigid.stderr b/tests/ui/dyn-star/dyn-to-rigid.stderr index b198c5245dea0..49b8f268aa4e9 100644 --- a/tests/ui/dyn-star/dyn-to-rigid.stderr +++ b/tests/ui/dyn-star/dyn-to-rigid.stderr @@ -1,9 +1,9 @@ -error[E0606]: casting `(dyn* Tr + 'static)` as `usize` is invalid +error[E0605]: non-primitive cast: `(dyn* Tr + 'static)` as `usize` --> $DIR/dyn-to-rigid.rs:7:5 | LL | x as usize - | ^^^^^^^^^^ + | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0606`. +For more information about this error, try `rustc --explain E0605`. diff --git a/tests/ui/dyn-star/enum-cast.rs b/tests/ui/dyn-star/enum-cast.rs new file mode 100644 index 0000000000000..6e895e9527aba --- /dev/null +++ b/tests/ui/dyn-star/enum-cast.rs @@ -0,0 +1,18 @@ +//@ check-pass + +// This used to ICE, because the compiler confused a pointer-like to dyn* coercion +// with a c-like enum to integer cast. + +#![feature(dyn_star)] +#![expect(incomplete_features)] + +enum E { + Num(usize), +} + +trait Trait {} +impl Trait for E {} + +fn main() { + let _ = E::Num(42) as dyn* Trait; +} diff --git a/tests/ui/empty/empty-struct-braces-pat-1.stderr b/tests/ui/empty/empty-struct-braces-pat-1.stderr index 14e09fc27a06d..c16fbc7de2b29 100644 --- a/tests/ui/empty/empty-struct-braces-pat-1.stderr +++ b/tests/ui/empty/empty-struct-braces-pat-1.stderr @@ -3,12 +3,22 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia | LL | E::Empty3 => () | ^^^^^^^^^ not a unit struct, unit variant or constant + | +help: use the struct variant pattern syntax + | +LL | E::Empty3 {} => () + | ++ error[E0533]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-1.rs:31:9 | LL | XE::XEmpty3 => () | ^^^^^^^^^^^ not a unit struct, unit variant or constant + | +help: use the struct variant pattern syntax + | +LL | XE::XEmpty3 {} => () + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/empty/empty-struct-braces-pat-3.stderr b/tests/ui/empty/empty-struct-braces-pat-3.stderr index 00c8b12e6f984..b2ab7113347ff 100644 --- a/tests/ui/empty/empty-struct-braces-pat-3.stderr +++ b/tests/ui/empty/empty-struct-braces-pat-3.stderr @@ -3,24 +3,44 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `E::E | LL | E::Empty3() => () | ^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | E::Empty3 {} => () + | ~~ error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-3.rs:21:9 | LL | XE::XEmpty3() => () | ^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | XE::XEmpty3 {} => () + | ~~ error[E0164]: expected tuple struct or tuple variant, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-pat-3.rs:25:9 | LL | E::Empty3(..) => () | ^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | E::Empty3 {} => () + | ~~ error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-3.rs:29:9 | LL | XE::XEmpty3(..) => () | ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | XE::XEmpty3 {} => () + | ~~ error: aborting due to 4 previous errors diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs index c046f7859fa09..e103d3bf5b116 100644 --- a/tests/ui/error-codes/E0017.rs +++ b/tests/ui/error-codes/E0017.rs @@ -1,5 +1,3 @@ -#![feature(const_mut_refs)] - //@ normalize-stderr-test: "\(size: ., align: .\)" -> "" //@ normalize-stderr-test: " +│ ╾─+╼" -> "" diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr index bb9f718b89592..285d363592f8b 100644 --- a/tests/ui/error-codes/E0017.stderr +++ b/tests/ui/error-codes/E0017.stderr @@ -1,5 +1,5 @@ warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:10:30 + --> $DIR/E0017.rs:8:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ @@ -7,26 +7,26 @@ LL | const CR: &'static mut i32 = &mut C; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/E0017.rs:7:1 + --> $DIR/E0017.rs:5:1 | LL | const C: i32 = 2; | ^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/E0017.rs:10:30 + --> $DIR/E0017.rs:8:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:13:39 + --> $DIR/E0017.rs:11:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:15:38 + --> $DIR/E0017.rs:13:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -34,13 +34,13 @@ LL | static CONST_REF: &'static mut i32 = &mut C; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/E0017.rs:7:1 + --> $DIR/E0017.rs:5:1 | LL | const C: i32 = 2; | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:15:38 + --> $DIR/E0017.rs:13:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ diff --git a/tests/ui/error-codes/E0075.rs b/tests/ui/error-codes/E0075.rs index 7feab0a8bd7a2..2c610d9186b64 100644 --- a/tests/ui/error-codes/E0075.rs +++ b/tests/ui/error-codes/E0075.rs @@ -3,5 +3,8 @@ #[repr(simd)] struct Bad; //~ ERROR E0075 +#[repr(simd)] +struct AlsoBad([i32; 1], [i32; 1]); //~ ERROR E0075 + fn main() { } diff --git a/tests/ui/error-codes/E0075.stderr b/tests/ui/error-codes/E0075.stderr index 43e9971e3095d..0a44a2eadebd1 100644 --- a/tests/ui/error-codes/E0075.stderr +++ b/tests/ui/error-codes/E0075.stderr @@ -4,6 +4,12 @@ error[E0075]: SIMD vector cannot be empty LL | struct Bad; | ^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0075]: SIMD vector cannot have multiple fields + --> $DIR/E0075.rs:7:1 + | +LL | struct AlsoBad([i32; 1], [i32; 1]); + | ^^^^^^^^^^^^^^ -------- excess field + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0075`. diff --git a/tests/ui/error-codes/E0076.rs b/tests/ui/error-codes/E0076.rs index a27072eb71e68..2c0376fe7e0bd 100644 --- a/tests/ui/error-codes/E0076.rs +++ b/tests/ui/error-codes/E0076.rs @@ -1,7 +1,7 @@ #![feature(repr_simd)] #[repr(simd)] -struct Bad(u16, u32, u32); +struct Bad(u32); //~^ ERROR E0076 fn main() { diff --git a/tests/ui/error-codes/E0076.stderr b/tests/ui/error-codes/E0076.stderr index ea3bbf094976f..8bf46cf38e338 100644 --- a/tests/ui/error-codes/E0076.stderr +++ b/tests/ui/error-codes/E0076.stderr @@ -1,8 +1,8 @@ -error[E0076]: SIMD vector should be homogeneous +error[E0076]: SIMD vector's only field must be an array --> $DIR/E0076.rs:4:1 | -LL | struct Bad(u16, u32, u32); - | ^^^^^^^^^^ SIMD elements must have the same type +LL | struct Bad(u32); + | ^^^^^^^^^^ --- not an array error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0077.rs b/tests/ui/error-codes/E0077.rs index fa2d5e24fa3ca..2704bbeb4ea17 100644 --- a/tests/ui/error-codes/E0077.rs +++ b/tests/ui/error-codes/E0077.rs @@ -1,7 +1,7 @@ #![feature(repr_simd)] #[repr(simd)] -struct Bad(String); //~ ERROR E0077 +struct Bad([String; 2]); //~ ERROR E0077 fn main() { } diff --git a/tests/ui/error-codes/E0077.stderr b/tests/ui/error-codes/E0077.stderr index aae4b3f2c2927..063b40a147c57 100644 --- a/tests/ui/error-codes/E0077.stderr +++ b/tests/ui/error-codes/E0077.stderr @@ -1,7 +1,7 @@ error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type --> $DIR/E0077.rs:4:1 | -LL | struct Bad(String); +LL | struct Bad([String; 2]); | ^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0388.rs b/tests/ui/error-codes/E0388.rs deleted file mode 100644 index bbc5f2710bf9a..0000000000000 --- a/tests/ui/error-codes/E0388.rs +++ /dev/null @@ -1,13 +0,0 @@ -static X: i32 = 1; -const C: i32 = 2; - -const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - -//~| WARN taking a mutable -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 - -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - -//~| WARN taking a mutable - -fn main() {} diff --git a/tests/ui/error-codes/E0388.stderr b/tests/ui/error-codes/E0388.stderr deleted file mode 100644 index cb7047072bd08..0000000000000 --- a/tests/ui/error-codes/E0388.stderr +++ /dev/null @@ -1,55 +0,0 @@ -warning: taking a mutable reference to a `const` item - --> $DIR/E0388.rs:4:30 - | -LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ - | - = note: each usage of a `const` item creates a new temporary - = note: the mutable reference will refer to this temporary, not the original `const` item -note: `const` item defined here - --> $DIR/E0388.rs:2:1 - | -LL | const C: i32 = 2; - | ^^^^^^^^^^^^ - = note: `#[warn(const_item_mutation)]` on by default - -error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/E0388.rs:4:30 - | -LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ - -error[E0658]: mutable references are not allowed in statics - --> $DIR/E0388.rs:7:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: taking a mutable reference to a `const` item - --> $DIR/E0388.rs:9:38 - | -LL | static CONST_REF: &'static mut i32 = &mut C; - | ^^^^^^ - | - = note: each usage of a `const` item creates a new temporary - = note: the mutable reference will refer to this temporary, not the original `const` item -note: `const` item defined here - --> $DIR/E0388.rs:2:1 - | -LL | const C: i32 = 2; - | ^^^^^^^^^^^^ - -error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0388.rs:9:38 - | -LL | static CONST_REF: &'static mut i32 = &mut C; - | ^^^^^^ - -error: aborting due to 3 previous errors; 2 warnings emitted - -Some errors have detailed explanations: E0658, E0764. -For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/error-codes/E0396-fixed.rs b/tests/ui/error-codes/E0396-fixed.rs deleted file mode 100644 index fe20da1a8ea87..0000000000000 --- a/tests/ui/error-codes/E0396-fixed.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(const_mut_refs)] - -const REG_ADDR: *mut u8 = 0x5f3759df as *mut u8; - -const VALUE: u8 = unsafe { *REG_ADDR }; -//~^ ERROR evaluation of constant value failed - -fn main() { -} diff --git a/tests/ui/error-codes/E0396-fixed.stderr b/tests/ui/error-codes/E0396-fixed.stderr deleted file mode 100644 index c14f4948095de..0000000000000 --- a/tests/ui/error-codes/E0396-fixed.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/E0396-fixed.rs:5:28 - | -LL | const VALUE: u8 = unsafe { *REG_ADDR }; - | ^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x5f3759df[noalloc] which is a dangling pointer (it has no provenance) - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/error-codes/E0396.rs b/tests/ui/error-codes/E0396.rs deleted file mode 100644 index 383eda3d636f1..0000000000000 --- a/tests/ui/error-codes/E0396.rs +++ /dev/null @@ -1,20 +0,0 @@ -const REG_ADDR: *mut u8 = 0x5f3759df as *mut u8; - -const VALUE: u8 = unsafe { *REG_ADDR }; -//~^ ERROR dereferencing raw mutable pointers in constants is unstable - -const unsafe fn unreachable() -> ! { - use std::convert::Infallible; - - const INFALLIBLE: *mut Infallible = &[] as *const [Infallible] as *const _ as _; - match *INFALLIBLE {} - //~^ ERROR dereferencing raw mutable pointers in constant functions is unstable - //~| ERROR dereferencing raw mutable pointers in constant functions is unstable - - const BAD: () = unsafe { match *INFALLIBLE {} }; - //~^ ERROR dereferencing raw mutable pointers in constants is unstable - //~| ERROR dereferencing raw mutable pointers in constants is unstable -} - -fn main() { -} diff --git a/tests/ui/error-codes/E0396.stderr b/tests/ui/error-codes/E0396.stderr deleted file mode 100644 index 8bc14139d63b1..0000000000000 --- a/tests/ui/error-codes/E0396.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error[E0658]: dereferencing raw mutable pointers in constants is unstable - --> $DIR/E0396.rs:3:28 - | -LL | const VALUE: u8 = unsafe { *REG_ADDR }; - | ^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: dereferencing raw mutable pointers in constants is unstable - --> $DIR/E0396.rs:14:36 - | -LL | const BAD: () = unsafe { match *INFALLIBLE {} }; - | ^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: dereferencing raw mutable pointers in constants is unstable - --> $DIR/E0396.rs:14:36 - | -LL | const BAD: () = unsafe { match *INFALLIBLE {} }; - | ^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/E0396.rs:10:11 - | -LL | match *INFALLIBLE {} - | ^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/E0396.rs:10:11 - | -LL | match *INFALLIBLE {} - | ^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/error-codes/E0799.rs b/tests/ui/error-codes/E0799.rs new file mode 100644 index 0000000000000..a1e5b5326691f --- /dev/null +++ b/tests/ui/error-codes/E0799.rs @@ -0,0 +1,4 @@ +fn test() -> impl Sized + use
{} +//~^ ERROR E0799 + +fn main() {} diff --git a/tests/ui/error-codes/E0799.stderr b/tests/ui/error-codes/E0799.stderr new file mode 100644 index 0000000000000..3639424e466f0 --- /dev/null +++ b/tests/ui/error-codes/E0799.stderr @@ -0,0 +1,9 @@ +error[E0799]: expected type or const parameter, found function `main` + --> $DIR/E0799.rs:1:31 + | +LL | fn test() -> impl Sized + use
{} + | ^^^^ not a type or const parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0799`. diff --git a/tests/ui/error-codes/E0800.rs b/tests/ui/error-codes/E0800.rs new file mode 100644 index 0000000000000..6112157feca5d --- /dev/null +++ b/tests/ui/error-codes/E0800.rs @@ -0,0 +1,4 @@ +fn test() -> impl Sized + use {} +//~^ ERROR E0800 + +fn main() {} diff --git a/tests/ui/error-codes/E0800.stderr b/tests/ui/error-codes/E0800.stderr new file mode 100644 index 0000000000000..282981a91732e --- /dev/null +++ b/tests/ui/error-codes/E0800.stderr @@ -0,0 +1,9 @@ +error[E0800]: cannot find type or const parameter `Missing` in this scope + --> $DIR/E0800.rs:1:31 + | +LL | fn test() -> impl Sized + use {} + | ^^^^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0800`. diff --git a/tests/ui/extern/extern-static-size-overflow.rs b/tests/ui/extern/extern-static-size-overflow.rs index a96ce0cf47e08..f33e482aa6653 100644 --- a/tests/ui/extern/extern-static-size-overflow.rs +++ b/tests/ui/extern/extern-static-size-overflow.rs @@ -4,31 +4,13 @@ struct ReallyBig { } // The limit for "too big for the current architecture" is dependent on the target pointer size -// however it's artificially limited on 64 bits -// logic copied from rustc_target::abi::TargetDataLayout::obj_size_bound() +// but is artificially limited due to LLVM's internal architecture +// logic based on rustc_target::abi::TargetDataLayout::obj_size_bound() const fn max_size() -> usize { - #[cfg(target_pointer_width = "16")] - { - 1 << 15 - } - - #[cfg(target_pointer_width = "32")] - { - 1 << 31 - } - - #[cfg(target_pointer_width = "64")] - { - 1 << 47 - } - - #[cfg(not(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" - )))] - { - isize::MAX as usize + if usize::BITS < 61 { + 1 << (usize::BITS - 1) + } else { + 1 << 61 } } diff --git a/tests/ui/extern/extern-static-size-overflow.stderr b/tests/ui/extern/extern-static-size-overflow.stderr index 1c926399591c2..c6490e96a8e6f 100644 --- a/tests/ui/extern/extern-static-size-overflow.stderr +++ b/tests/ui/extern/extern-static-size-overflow.stderr @@ -1,17 +1,17 @@ -error: extern static is too large for the current architecture - --> $DIR/extern-static-size-overflow.rs:38:5 +error: extern static is too large for the target architecture + --> $DIR/extern-static-size-overflow.rs:20:5 | LL | static BAZ: [u8; max_size()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: extern static is too large for the current architecture - --> $DIR/extern-static-size-overflow.rs:39:5 +error: extern static is too large for the target architecture + --> $DIR/extern-static-size-overflow.rs:21:5 | LL | static UWU: [usize; usize::MAX]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: extern static is too large for the current architecture - --> $DIR/extern-static-size-overflow.rs:40:5 +error: extern static is too large for the target architecture + --> $DIR/extern-static-size-overflow.rs:22:5 | LL | static A: ReallyBig; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.rs b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.rs new file mode 100644 index 0000000000000..79ceb05662bc4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.rs @@ -0,0 +1,15 @@ +trait Foo { + fn foo(self: *const Self); //~ ERROR `*const Self` cannot be used as the type of `self` +} + +struct Bar; + +impl Foo for Bar { + fn foo(self: *const Self) {} //~ ERROR `*const Bar` cannot be used as the type of `self` +} + +impl Bar { + fn bar(self: *mut Self) {} //~ ERROR `*mut Bar` cannot be used as the type of `self` +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr new file mode 100644 index 0000000000000..3bb93cf2ea0b1 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr @@ -0,0 +1,36 @@ +error[E0658]: `*const Bar` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature + --> $DIR/feature-gate-arbitrary-self-types-pointers.rs:8:18 + | +LL | fn foo(self: *const Self) {} + | ^^^^^^^^^^^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0658]: `*mut Bar` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature + --> $DIR/feature-gate-arbitrary-self-types-pointers.rs:12:18 + | +LL | fn bar(self: *mut Self) {} + | ^^^^^^^^^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature + --> $DIR/feature-gate-arbitrary-self-types-pointers.rs:2:18 + | +LL | fn foo(self: *const Self); + | ^^^^^^^^^^^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr index 711025ff93b44..856e059533139 100644 --- a/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr +++ b/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr @@ -1,33 +1,33 @@ -error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature +error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:4:18 | LL | fn foo(self: *const Self) {} | ^^^^^^^^^^^ | = note: see issue #44874 for more information - = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature +error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18 | LL | fn bar(self: *const Self) {} | ^^^^^^^^^^^ | = note: see issue #44874 for more information - = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature +error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18 | LL | fn bar(self: *const Self); | ^^^^^^^^^^^ | = note: see issue #44874 for more information - = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) diff --git a/tests/ui/feature-gates/feature-gate-const-arg-path.rs b/tests/ui/feature-gates/feature-gate-const-arg-path.rs deleted file mode 100644 index 0938c5733a297..0000000000000 --- a/tests/ui/feature-gates/feature-gate-const-arg-path.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ check-pass - -// this doesn't really have any user facing impact.... - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-const_refs_to_cell.rs b/tests/ui/feature-gates/feature-gate-const_refs_to_cell.rs deleted file mode 100644 index bd908676c8bf8..0000000000000 --- a/tests/ui/feature-gates/feature-gate-const_refs_to_cell.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ check-pass - -#![feature(const_refs_to_cell)] - -const FOO: () = { - let x = std::cell::Cell::new(42); - let y = &x; -}; - -fn main() { - FOO; -} diff --git a/tests/ui/feature-gates/feature-gate-if-let-rescope.rs b/tests/ui/feature-gates/feature-gate-if-let-rescope.rs new file mode 100644 index 0000000000000..bd1efd4fb7c1f --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-if-let-rescope.rs @@ -0,0 +1,27 @@ +// This test shows the code that could have been accepted by enabling #![feature(if_let_rescope)] + +struct A; +struct B<'a, T>(&'a mut T); + +impl A { + fn f(&mut self) -> Option> { + Some(B(self)) + } +} + +impl<'a, T> Drop for B<'a, T> { + fn drop(&mut self) { + // this is needed to keep NLL's hands off and to ensure + // the inner mutable borrow stays alive + } +} + +fn main() { + let mut a = A; + if let None = a.f().as_ref() { + unreachable!() + } else { + a.f().unwrap(); + //~^ ERROR cannot borrow `a` as mutable more than once at a time + }; +} diff --git a/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr b/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr new file mode 100644 index 0000000000000..ff1846ae0b1f5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr @@ -0,0 +1,18 @@ +error[E0499]: cannot borrow `a` as mutable more than once at a time + --> $DIR/feature-gate-if-let-rescope.rs:24:9 + | +LL | if let None = a.f().as_ref() { + | ----- + | | + | first mutable borrow occurs here + | a temporary with access to the first borrow is created here ... +... +LL | a.f().unwrap(); + | ^ second mutable borrow occurs here +LL | +LL | }; + | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs new file mode 100644 index 0000000000000..d694531d53abe --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -0,0 +1,15 @@ +#![allow(dead_code, incomplete_features)] + +use std::pin::Pin; + +struct Foo; + +fn foo(_: Pin<&mut Foo>) { +} + +fn bar(mut x: Pin<&mut Foo>) { + foo(x); + foo(x); //~ ERROR use of moved value: `x` +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr new file mode 100644 index 0000000000000..6c9029d817674 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -0,0 +1,21 @@ +error[E0382]: use of moved value: `x` + --> $DIR/feature-gate-pin_ergonomics.rs:12:9 + | +LL | fn bar(mut x: Pin<&mut Foo>) { + | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait +LL | foo(x); + | - value moved here +LL | foo(x); + | ^ value used here after move + | +note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary + --> $DIR/feature-gate-pin_ergonomics.rs:7:11 + | +LL | fn foo(_: Pin<&mut Foo>) { + | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/feature-gates/feature-gate-repr-simd.rs b/tests/ui/feature-gates/feature-gate-repr-simd.rs index c527404f57270..65ade97c7e1c3 100644 --- a/tests/ui/feature-gates/feature-gate-repr-simd.rs +++ b/tests/ui/feature-gates/feature-gate-repr-simd.rs @@ -1,9 +1,9 @@ #[repr(simd)] //~ error: SIMD types are experimental -struct Foo(u64, u64); +struct Foo([u64; 2]); #[repr(C)] //~ ERROR conflicting representation hints //~^ WARN this was previously accepted #[repr(simd)] //~ error: SIMD types are experimental -struct Bar(u64, u64); +struct Bar([u64; 2]); fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs index 667bc9f8ddf18..7ae4a8d911bad 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs @@ -2,6 +2,6 @@ #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable #[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable -#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable +#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 8177d5ef6bedb..8c3a8eb2df875 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -16,7 +16,8 @@ LL | #[rustc_error] = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable +error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable + (note that the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized) --> $DIR/feature-gate-rustc-attrs-1.rs:5:1 | LL | #[rustc_nonnull_optimization_guaranteed] diff --git a/tests/ui/feature-gates/feature-gate-simd-ffi.rs b/tests/ui/feature-gates/feature-gate-simd-ffi.rs index abffa4a10010d..2ee935e07ffa4 100644 --- a/tests/ui/feature-gates/feature-gate-simd-ffi.rs +++ b/tests/ui/feature-gates/feature-gate-simd-ffi.rs @@ -3,7 +3,7 @@ #[repr(simd)] #[derive(Copy, Clone)] -struct LocalSimd(u8, u8); +struct LocalSimd([u8; 2]); extern "C" { fn baz() -> LocalSimd; //~ ERROR use of SIMD type diff --git a/tests/ui/feature-gates/feature-gate-simd.rs b/tests/ui/feature-gates/feature-gate-simd.rs index de5f645e6fd0b..e7aef5a97f2ee 100644 --- a/tests/ui/feature-gates/feature-gate-simd.rs +++ b/tests/ui/feature-gates/feature-gate-simd.rs @@ -2,10 +2,7 @@ #[repr(simd)] //~ ERROR SIMD types are experimental struct RGBA { - r: f32, - g: f32, - b: f32, - a: f32 + rgba: [f32; 4], } pub fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unqualified-local-imports.rs b/tests/ui/feature-gates/feature-gate-unqualified-local-imports.rs new file mode 100644 index 0000000000000..29929e40f89bc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unqualified-local-imports.rs @@ -0,0 +1,6 @@ +//@ check-pass + +#![allow(unqualified_local_imports)] +//~^ WARNING unknown lint: `unqualified_local_imports` + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unqualified-local-imports.stderr b/tests/ui/feature-gates/feature-gate-unqualified-local-imports.stderr new file mode 100644 index 0000000000000..22cd3bf4c6faf --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unqualified-local-imports.stderr @@ -0,0 +1,13 @@ +warning: unknown lint: `unqualified_local_imports` + --> $DIR/feature-gate-unqualified-local-imports.rs:3:1 + | +LL | #![allow(unqualified_local_imports)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `unqualified_local_imports` lint is unstable + = help: add `#![feature(unqualified_local_imports)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: `#[warn(unknown_lints)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index ca60bc62b5183..afffb3b144375 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs @@ -164,4 +164,28 @@ mod repr { //~| NOTE not a struct, enum, or union } + +#[repr(Rust)] +//~^ ERROR: attribute should be applied to a struct, enum, or union +mod repr_rust { +//~^ NOTE not a struct, enum, or union + mod inner { #![repr(Rust)] } + //~^ ERROR: attribute should be applied to a struct, enum, or union + //~| NOTE not a struct, enum, or union + + #[repr(Rust)] fn f() { } + //~^ ERROR: attribute should be applied to a struct, enum, or union + //~| NOTE not a struct, enum, or union + + struct S; + + #[repr(Rust)] type T = S; + //~^ ERROR: attribute should be applied to a struct, enum, or union + //~| NOTE not a struct, enum, or union + + #[repr(Rust)] impl S { } + //~^ ERROR: attribute should be applied to a struct, enum, or union + //~| NOTE not a struct, enum, or union +} + fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index ac2bf78157d27..fe764ff49255e 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -107,6 +107,21 @@ LL | | LL | | } | |_- not a struct, enum, or union +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:168:8 + | +LL | #[repr(Rust)] + | ^^^^ +LL | +LL | / mod repr_rust { +LL | | +LL | | mod inner { #![repr(Rust)] } +LL | | +... | +LL | | +LL | | } + | |_- not a struct, enum, or union + error: attribute should be applied to an `extern crate` item --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 | @@ -329,7 +344,31 @@ error[E0517]: attribute should be applied to a struct, enum, or union LL | #[repr(C)] impl S { } | ^ ---------- not a struct, enum, or union -error: aborting due to 39 previous errors +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:172:25 + | +LL | mod inner { #![repr(Rust)] } + | --------------------^^^^---- not a struct, enum, or union + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:176:12 + | +LL | #[repr(Rust)] fn f() { } + | ^^^^ ---------- not a struct, enum, or union + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:182:12 + | +LL | #[repr(Rust)] type T = S; + | ^^^^ ----------- not a struct, enum, or union + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:186:12 + | +LL | #[repr(Rust)] impl S { } + | ^^^^ ---------- not a struct, enum, or union + +error: aborting due to 44 previous errors Some errors have detailed explanations: E0517, E0518, E0658. For more information about an error, try `rustc --explain E0517`. diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs new file mode 100644 index 0000000000000..b19e67d5284d0 --- /dev/null +++ b/tests/ui/float/classify-runtime-const.rs @@ -0,0 +1,130 @@ +//@ run-pass +//@ revisions: opt noopt ctfe +//@[opt] compile-flags: -O +//@[noopt] compile-flags: -Zmir-opt-level=0 +// ignore-tidy-linelength + +// This tests the float classification functions, for regular runtime code and for const evaluation. + +#![feature(f16_const)] +#![feature(f128_const)] +#![feature(const_float_classify)] + +use std::num::FpCategory::*; + +#[cfg(not(ctfe))] +use std::hint::black_box; +#[cfg(ctfe)] +#[allow(unused)] +const fn black_box(x: T) -> T { x } + +#[cfg(not(ctfe))] +macro_rules! assert_test { + ($a:expr, NonDet) => { + { + // Compute `a`, but do not compare with anything as the result is non-deterministic. + let _val = $a; + } + }; + ($a:expr, $b:ident) => { + { + // Let-bind to avoid promotion. + // No black_box here! That can mask x87 failures. + let a = $a; + let b = $b; + assert_eq!(a, b, "{} produces wrong result", stringify!($a)); + } + }; +} +#[cfg(ctfe)] +macro_rules! assert_test { + ($a:expr, NonDet) => { + { + // Compute `a`, but do not compare with anything as the result is non-deterministic. + const _: () = { let _val = $a; }; + } + }; + ($a:expr, $b:ident) => { + { + const _: () = assert!(matches!($a, $b)); + } + }; +} + +macro_rules! suite { + ( $tyname:ident => $( $tt:tt )* ) => { + fn f32() { + #[allow(unused)] + type $tyname = f32; + suite_inner!(f32 => $($tt)*); + } + + fn f64() { + #[allow(unused)] + type $tyname = f64; + suite_inner!(f64 => $($tt)*); + } + } +} + +macro_rules! suite_inner { + ( + $ty:ident => [$( $fn:ident ),*]: + $(@cfg: $attr:meta)? + $val:expr => [$($out:ident),*], + + $( $tail:tt )* + ) => { + $(#[cfg($attr)])? + { + // No black_box here! That can mask x87 failures. + $( assert_test!($ty::$fn($val), $out); )* + } + suite_inner!($ty => [$($fn),*]: $($tail)*) + }; + + ( $ty:ident => [$( $fn:ident ),*]:) => {}; +} + +// The result of the `is_sign` methods are not checked for correctness, since we do not +// guarantee anything about the signedness of NaNs. See +// https://rust-lang.github.io/rfcs/3514-float-semantics.html. + +suite! { T => // type alias for the type we are testing + [ classify, is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative]: + black_box(0.0) / black_box(0.0) => + [ Nan, true, false, false, false, NonDet, NonDet], + black_box(0.0) / black_box(-0.0) => + [ Nan, true, false, false, false, NonDet, NonDet], + black_box(0.0) * black_box(T::INFINITY) => + [ Nan, true, false, false, false, NonDet, NonDet], + black_box(0.0) * black_box(T::NEG_INFINITY) => + [ Nan, true, false, false, false, NonDet, NonDet], + 1.0 => [ Normal, false, false, true, true, true, false], + -1.0 => [ Normal, false, false, true, true, false, true], + 0.0 => [ Zero, false, false, true, false, true, false], + -0.0 => [ Zero, false, false, true, false, false, true], + 1.0 / black_box(0.0) => + [ Infinite, false, true, false, false, true, false], + -1.0 / black_box(0.0) => + [ Infinite, false, true, false, false, false, true], + 2.0 * black_box(T::MAX) => + [ Infinite, false, true, false, false, true, false], + -2.0 * black_box(T::MAX) => + [ Infinite, false, true, false, false, false, true], + 1.0 / black_box(T::MAX) => + [Subnormal, false, false, true, false, true, false], + -1.0 / black_box(T::MAX) => + [Subnormal, false, false, true, false, false, true], + // This specific expression causes trouble on x87 due to + // . + @cfg: not(all(target_arch = "x86", not(target_feature = "sse2"))) + { let x = black_box(T::MAX); x * x } => + [ Infinite, false, true, false, false, true, false], +} + +fn main() { + f32(); + f64(); + // FIXME(f16_f128): also test f16 and f128 +} diff --git a/tests/ui/float/conv-bits-runtime-const.rs b/tests/ui/float/conv-bits-runtime-const.rs new file mode 100644 index 0000000000000..e85a889d2c240 --- /dev/null +++ b/tests/ui/float/conv-bits-runtime-const.rs @@ -0,0 +1,168 @@ +//@ compile-flags: -Zmir-opt-level=0 +//@ run-pass + +// This tests the float classification functions, for regular runtime code and for const evaluation. + +#![feature(const_float_classify)] +#![feature(f16)] +#![feature(f128)] +#![feature(f16_const)] +#![feature(f128_const)] +#![allow(unused_macro_rules)] + +use std::hint::black_box; + +macro_rules! both_assert { + ($a:expr) => { + { + const _: () = assert!($a); + // `black_box` prevents promotion, and MIR opts are disabled above, so this is truly + // going through LLVM. + assert!(black_box($a)); + } + }; + ($a:expr, $b:expr) => { + { + const _: () = assert!($a == $b); + assert_eq!(black_box($a), black_box($b)); + } + }; +} + +fn has_broken_floats() -> bool { + // i586 targets are broken due to . + cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) +} + +#[cfg(target_arch = "x86_64")] +fn f16(){ + both_assert!((1f16).to_bits(), 0x3c00); + both_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00); + both_assert!((12.5f16).to_bits(), 0x4a40); + both_assert!(u16::from_le_bytes(12.5f16.to_le_bytes()), 0x4a40); + both_assert!((1337f16).to_bits(), 0x6539); + both_assert!(u16::from_ne_bytes(1337f16.to_ne_bytes()), 0x6539); + both_assert!((-14.25f16).to_bits(), 0xcb20); + both_assert!(f16::from_bits(0x3c00), 1.0); + both_assert!(f16::from_be_bytes(0x3c00u16.to_be_bytes()), 1.0); + both_assert!(f16::from_bits(0x4a40), 12.5); + both_assert!(f16::from_le_bytes(0x4a40u16.to_le_bytes()), 12.5); + both_assert!(f16::from_bits(0x5be0), 252.0); + both_assert!(f16::from_ne_bytes(0x5be0u16.to_ne_bytes()), 252.0); + both_assert!(f16::from_bits(0xcb20), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u16 = f16::NAN.to_bits() ^ 0x0155; + const SIGNALING_NAN: u16 = f16::NAN.to_bits() ^ 0x02AA; + + both_assert!(f16::from_bits(QUIET_NAN).is_nan()); + both_assert!(f16::from_bits(SIGNALING_NAN).is_nan()); + both_assert!(f16::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + both_assert!(f16::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + +fn f32() { + both_assert!((1f32).to_bits(), 0x3f800000); + both_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000); + both_assert!((12.5f32).to_bits(), 0x41480000); + both_assert!(u32::from_le_bytes(12.5f32.to_le_bytes()), 0x41480000); + both_assert!((1337f32).to_bits(), 0x44a72000); + both_assert!(u32::from_ne_bytes(1337f32.to_ne_bytes()), 0x44a72000); + both_assert!((-14.25f32).to_bits(), 0xc1640000); + both_assert!(f32::from_bits(0x3f800000), 1.0); + both_assert!(f32::from_be_bytes(0x3f800000u32.to_be_bytes()), 1.0); + both_assert!(f32::from_bits(0x41480000), 12.5); + both_assert!(f32::from_le_bytes(0x41480000u32.to_le_bytes()), 12.5); + both_assert!(f32::from_bits(0x44a72000), 1337.0); + both_assert!(f32::from_ne_bytes(0x44a72000u32.to_ne_bytes()), 1337.0); + both_assert!(f32::from_bits(0xc1640000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA; + const SIGNALING_NAN: u32 = f32::NAN.to_bits() ^ 0x0055_5555; + + both_assert!(f32::from_bits(QUIET_NAN).is_nan()); + both_assert!(f32::from_bits(SIGNALING_NAN).is_nan()); + both_assert!(f32::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + both_assert!(f32::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + +fn f64() { + both_assert!((1f64).to_bits(), 0x3ff0000000000000); + both_assert!(u64::from_be_bytes(1f64.to_be_bytes()), 0x3ff0000000000000); + both_assert!((12.5f64).to_bits(), 0x4029000000000000); + both_assert!(u64::from_le_bytes(12.5f64.to_le_bytes()), 0x4029000000000000); + both_assert!((1337f64).to_bits(), 0x4094e40000000000); + both_assert!(u64::from_ne_bytes(1337f64.to_ne_bytes()), 0x4094e40000000000); + both_assert!((-14.25f64).to_bits(), 0xc02c800000000000); + both_assert!(f64::from_bits(0x3ff0000000000000), 1.0); + both_assert!(f64::from_be_bytes(0x3ff0000000000000u64.to_be_bytes()), 1.0); + both_assert!(f64::from_bits(0x4029000000000000), 12.5); + both_assert!(f64::from_le_bytes(0x4029000000000000u64.to_le_bytes()), 12.5); + both_assert!(f64::from_bits(0x4094e40000000000), 1337.0); + both_assert!(f64::from_ne_bytes(0x4094e40000000000u64.to_ne_bytes()), 1337.0); + both_assert!(f64::from_bits(0xc02c800000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; + const SIGNALING_NAN: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; + + both_assert!(f64::from_bits(QUIET_NAN).is_nan()); + both_assert!(f64::from_bits(SIGNALING_NAN).is_nan()); + both_assert!(f64::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + both_assert!(f64::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + +#[cfg(target_arch = "x86_64")] +fn f128() { + both_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000); + both_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000); + both_assert!((12.5f128).to_bits(), 0x40029000000000000000000000000000); + both_assert!(u128::from_le_bytes(12.5f128.to_le_bytes()), 0x40029000000000000000000000000000); + both_assert!((1337f128).to_bits(), 0x40094e40000000000000000000000000); + both_assert!(u128::from_ne_bytes(1337f128.to_ne_bytes()), 0x40094e40000000000000000000000000); + both_assert!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); + both_assert!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0); + both_assert!(f128::from_be_bytes(0x3fff0000000000000000000000000000u128.to_be_bytes()), 1.0); + both_assert!(f128::from_bits(0x40029000000000000000000000000000), 12.5); + both_assert!(f128::from_le_bytes(0x40029000000000000000000000000000u128.to_le_bytes()), 12.5); + both_assert!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0); + assert_eq!(f128::from_ne_bytes(0x40094e40000000000000000000000000u128.to_ne_bytes()), 1337.0); + both_assert!(f128::from_bits(0xc002c800000000000000000000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u128 = f128::NAN.to_bits() | 0x0000_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA; + const SIGNALING_NAN: u128 = f128::NAN.to_bits() ^ 0x0000_5555_5555_5555_5555_5555_5555_5555; + + both_assert!(f128::from_bits(QUIET_NAN).is_nan()); + both_assert!(f128::from_bits(SIGNALING_NAN).is_nan()); + both_assert!(f128::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + both_assert!(f128::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + +fn main() { + f32(); + f64(); + + #[cfg(target_arch = "x86_64")] + { + f16(); + f128(); + } +} diff --git a/tests/ui/numbers-arithmetic/issue-105626.rs b/tests/ui/float/int-to-float-miscompile-issue-105626.rs similarity index 85% rename from tests/ui/numbers-arithmetic/issue-105626.rs rename to tests/ui/float/int-to-float-miscompile-issue-105626.rs index f942cf1283d0d..8d4a7c308e7fe 100644 --- a/tests/ui/numbers-arithmetic/issue-105626.rs +++ b/tests/ui/float/int-to-float-miscompile-issue-105626.rs @@ -11,6 +11,7 @@ fn main() { assert_ne!((n as f64) as f32, n as f32); // FIXME: these assertions fail if only x87 is enabled + // see also https://github.com/rust-lang/rust/issues/114479 assert_eq!(n as i64 as f32, r); assert_eq!(n as u64 as f32, r); } diff --git a/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs b/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs index fef9f24d462d8..57e8b2286497c 100644 --- a/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs +++ b/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs @@ -2,6 +2,9 @@ // This test verifies that temporaries created for `while`'s and `if` // conditions are dropped after the condition is evaluated. +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] + struct Temporary; static mut DROPPED: isize = 0; diff --git a/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.rs b/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.rs index 500633edf12de..a05d20ffbd280 100644 --- a/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.rs +++ b/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.rs @@ -2,6 +2,10 @@ // The `foo` module attempts to maintains an invariant that each `S` // has a unique `u64` id. + +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use self::foo::S; mod foo { use std::cell::{UnsafeCell}; diff --git a/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr b/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr index 692d98bc53c82..8924800ef2796 100644 --- a/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr +++ b/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr @@ -1,5 +1,5 @@ error[E0451]: field `secret_uid` of struct `S` is private - --> $DIR/functional-struct-update-respects-privacy.rs:28:49 + --> $DIR/functional-struct-update-respects-privacy.rs:32:49 | LL | let s_2 = foo::S { b: format!("ess two"), ..s_1 }; // FRU ... | ^^^ field `secret_uid` is private diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr index c14021e009bd1..9831348de7569 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -3,6 +3,17 @@ error: expected a pattern range bound, found an expression | LL | 0..5+1 => errors_only.push(x), | ^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 5+1; +LL ~ match x as i32 { +LL ~ 0..VAL => errors_only.push(x), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | 0..const { 5+1 } => errors_only.push(x), + | +++++++ + error[E0408]: variable `n` is not bound in all patterns --> $DIR/range_pat_interactions1.rs:10:25 diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr index 136296fa5b0f0..1b5e875cccb68 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr @@ -1,9 +1,3 @@ -error: expected a pattern range bound, found an expression - --> $DIR/range_pat_interactions2.rs:10:18 - | -LL | 0..=(5+1) => errors_only.push(x), - | ^^^ arbitrary expressions are not allowed in patterns - error: range pattern bounds cannot have parentheses --> $DIR/range_pat_interactions2.rs:10:17 | @@ -16,6 +10,23 @@ LL - 0..=(5+1) => errors_only.push(x), LL + 0..=5+1 => errors_only.push(x), | +error: expected a pattern range bound, found an expression + --> $DIR/range_pat_interactions2.rs:10:18 + | +LL | 0..=(5+1) => errors_only.push(x), + | ^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 5+1; +LL ~ match x as i32 { +LL ~ 0..=(VAL) => errors_only.push(x), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | 0..=(const { 5+1 }) => errors_only.push(x), + | +++++++ + + error[E0658]: inline-const in pattern position is experimental --> $DIR/range_pat_interactions2.rs:15:20 | diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr index 12d886a002454..fd6f4b34241aa 100644 --- a/tests/ui/impl-trait/equality.stderr +++ b/tests/ui/impl-trait/equality.stderr @@ -30,8 +30,8 @@ LL | n + sum_to(n - 1) | = help: the trait `Add` is not implemented for `u32` = help: the following other types implement trait `Add`: - `&'a u32` implements `Add` - `&u32` implements `Add<&u32>` + `&u32` implements `Add` + `&u32` implements `Add` `u32` implements `Add<&u32>` `u32` implements `Add` diff --git a/tests/ui/impl-trait/issues/issue-62742.rs b/tests/ui/impl-trait/issues/issue-62742.rs index 56c63a1daa867..c64278c2c5bec 100644 --- a/tests/ui/impl-trait/issues/issue-62742.rs +++ b/tests/ui/impl-trait/issues/issue-62742.rs @@ -2,7 +2,8 @@ use std::marker::PhantomData; fn a() { WrongImpl::foo(0i32); - //~^ ERROR overflow assigning `_` to `[_]` + //~^ ERROR the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied + //~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied } fn b() { diff --git a/tests/ui/impl-trait/issues/issue-62742.stderr b/tests/ui/impl-trait/issues/issue-62742.stderr index 7a1bcfc70d54f..94822e41ccd67 100644 --- a/tests/ui/impl-trait/issues/issue-62742.stderr +++ b/tests/ui/impl-trait/issues/issue-62742.stderr @@ -1,11 +1,43 @@ -error[E0275]: overflow assigning `_` to `[_]` +error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied --> $DIR/issue-62742.rs:4:16 | LL | WrongImpl::foo(0i32); - | ^^^ + | ^^^ function or associated item cannot be called on `SafeImpl<_, RawImpl<_>>` due to unsatisfied trait bounds +... +LL | pub struct RawImpl(PhantomData); + | --------------------- doesn't satisfy `RawImpl<_>: Raw<_>` +... +LL | pub struct SafeImpl>(PhantomData<(A, T)>); + | ----------------------------------------- function or associated item `foo` not found for this struct + | +note: trait bound `RawImpl<_>: Raw<_>` was not satisfied + --> $DIR/issue-62742.rs:35:20 + | +LL | impl> SafeImpl { + | ^^^^^^ -------------- + | | + | unsatisfied trait bound introduced here +note: the trait `Raw` must be implemented + --> $DIR/issue-62742.rs:19:1 + | +LL | pub trait Raw { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied + --> $DIR/issue-62742.rs:4:5 + | +LL | WrongImpl::foo(0i32); + | ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` + | + = help: the trait `Raw<[_]>` is implemented for `RawImpl<_>` +note: required by a bound in `SafeImpl` + --> $DIR/issue-62742.rs:33:35 + | +LL | pub struct SafeImpl>(PhantomData<(A, T)>); + | ^^^^^^ required by this bound in `SafeImpl` error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied - --> $DIR/issue-62742.rs:9:22 + --> $DIR/issue-62742.rs:10:22 | LL | WrongImpl::<()>::foo(0i32); | ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds @@ -17,20 +49,20 @@ LL | pub struct SafeImpl>(PhantomData<(A, T)>); | ----------------------------------------- function or associated item `foo` not found for this struct | note: trait bound `RawImpl<()>: Raw<()>` was not satisfied - --> $DIR/issue-62742.rs:34:20 + --> $DIR/issue-62742.rs:35:20 | LL | impl> SafeImpl { | ^^^^^^ -------------- | | | unsatisfied trait bound introduced here note: the trait `Raw` must be implemented - --> $DIR/issue-62742.rs:18:1 + --> $DIR/issue-62742.rs:19:1 | LL | pub trait Raw { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied - --> $DIR/issue-62742.rs:9:5 + --> $DIR/issue-62742.rs:10:5 | LL | WrongImpl::<()>::foo(0i32); | ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>` @@ -38,12 +70,12 @@ LL | WrongImpl::<()>::foo(0i32); = help: the trait `Raw<[()]>` is implemented for `RawImpl<()>` = help: for that trait implementation, expected `[()]`, found `()` note: required by a bound in `SafeImpl` - --> $DIR/issue-62742.rs:32:35 + --> $DIR/issue-62742.rs:33:35 | LL | pub struct SafeImpl>(PhantomData<(A, T)>); | ^^^^^^ required by this bound in `SafeImpl` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0275, E0277, E0599. -For more information about an error, try `rustc --explain E0275`. +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/normalize-tait-in-const.rs b/tests/ui/impl-trait/normalize-tait-in-const.rs index e3f53e5f8a82a..134b202d65582 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.rs +++ b/tests/ui/impl-trait/normalize-tait-in-const.rs @@ -2,7 +2,6 @@ #![feature(type_alias_impl_trait)] #![feature(const_trait_impl)] -#![feature(const_refs_to_cell)] use std::marker::Destruct; diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index b20dabe7b25ac..e0d193b5d4027 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,17 +1,17 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:27:42 + --> $DIR/normalize-tait-in-const.rs:26:42 | LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:27:69 + --> $DIR/normalize-tait-in-const.rs:26:69 | LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^^^^^^ error[E0015]: cannot call non-const closure in constant functions - --> $DIR/normalize-tait-in-const.rs:28:5 + --> $DIR/normalize-tait-in-const.rs:27:5 | LL | fun(filter_positive()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL + #![feature(effects)] | error[E0493]: destructor of `F` cannot be evaluated at compile-time - --> $DIR/normalize-tait-in-const.rs:27:79 + --> $DIR/normalize-tait-in-const.rs:26:79 | LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^ the destructor for this type cannot be evaluated in constant functions diff --git a/tests/ui/impl-trait/opaque-hidden-inferred-rpitit.rs b/tests/ui/impl-trait/opaque-hidden-inferred-rpitit.rs new file mode 100644 index 0000000000000..1582cca5cd258 --- /dev/null +++ b/tests/ui/impl-trait/opaque-hidden-inferred-rpitit.rs @@ -0,0 +1,16 @@ +//@ check-pass + +// Make sure that the `opaque_hidden_inferred_bound` lint doesn't fire on +// RPITITs with no hidden type. + +trait T0 {} + +trait T1 { + type A: Send; +} + +trait T2 { + fn foo() -> impl T1; +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs index 17b517abd74e4..d1ec48df48c7b 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs @@ -1,8 +1,8 @@ fn missing() -> impl Sized + use {} -//~^ ERROR cannot find type `T` in this scope +//~^ ERROR cannot find type or const parameter `T` in this scope fn missing_self() -> impl Sized + use {} -//~^ ERROR cannot find type `Self` in this scope +//~^ ERROR cannot find type or const parameter `Self` in this scope struct MyType; impl MyType { @@ -11,6 +11,9 @@ impl MyType { } fn hello() -> impl Sized + use {} -//~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function +//~^ ERROR expected type or const parameter, found function `hello` + +fn arg(x: ()) -> impl Sized + use {} +//~^ ERROR expected type or const parameter, found local variable `x` fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.stderr b/tests/ui/impl-trait/precise-capturing/bad-params.stderr index 06ccf35694811..07ada8da30019 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0800]: cannot find type or const parameter `T` in this scope --> $DIR/bad-params.rs:1:34 | LL | fn missing() -> impl Sized + use {} @@ -9,7 +9,7 @@ help: you might be missing a type parameter LL | fn missing() -> impl Sized + use {} | +++ -error[E0411]: cannot find type `Self` in this scope +error[E0411]: cannot find type or const parameter `Self` in this scope --> $DIR/bad-params.rs:4:39 | LL | fn missing_self() -> impl Sized + use {} @@ -17,7 +17,19 @@ LL | fn missing_self() -> impl Sized + use {} | | | `Self` not allowed in a function -error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias +error[E0799]: expected type or const parameter, found function `hello` + --> $DIR/bad-params.rs:13:32 + | +LL | fn hello() -> impl Sized + use {} + | ^^^^^ not a type or const parameter + +error[E0799]: expected type or const parameter, found local variable `x` + --> $DIR/bad-params.rs:16:35 + | +LL | fn arg(x: ()) -> impl Sized + use {} + | ^ not a type or const parameter + +error[E0799]: `Self` can't be captured in `use<...>` precise captures list, since it is an alias --> $DIR/bad-params.rs:9:48 | LL | impl MyType { @@ -25,13 +37,7 @@ LL | impl MyType { LL | fn self_is_not_param() -> impl Sized + use {} | ^^^^ -error: expected type or const parameter in `use<...>` precise captures list, found function - --> $DIR/bad-params.rs:13:32 - | -LL | fn hello() -> impl Sized + use {} - | ^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0411, E0412. +Some errors have detailed explanations: E0411, E0799, E0800. For more information about an error, try `rustc --explain E0411`. diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024-but-fine.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-but-fine.rs new file mode 100644 index 0000000000000..e30f785b0ae33 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-but-fine.rs @@ -0,0 +1,15 @@ +//@ check-pass + +#![deny(impl_trait_overcaptures)] + +struct Ctxt<'tcx>(&'tcx ()); + +// In `compute`, we don't care that we're "overcapturing" `'tcx` +// in edition 2024, because it can be shortened at the call site +// and we know it outlives `'_`. + +impl<'tcx> Ctxt<'tcx> { + fn compute(&self) -> impl Sized + '_ {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs new file mode 100644 index 0000000000000..71a91fe319e8d --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs @@ -0,0 +1,16 @@ +// Make sure we don't ICE when an RPITIT captures more method args than the +// trait definition, which is not allowed. Due to the default lifetime capture +// rules of RPITITs, this is only doable if we use precise capturing. + +pub trait Foo { + fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; + //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits +} + +impl Foo for () { + fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} + //~^ ERROR return type captures more lifetimes than trait definition + //~| WARN impl trait in impl method signature does not match trait method signature +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr new file mode 100644 index 0000000000000..339e2e6335e2d --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr @@ -0,0 +1,42 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:53 + | +LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: return type captures more lifetimes than trait definition + --> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40 + | +LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} + | --- ^^^^^^^^^^^^^^^^ + | | + | this lifetime was captured + | +note: hidden type must only reference lifetimes captured by this impl trait + --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:40 + | +LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: hidden type inferred to be `impl Sized + 'im` + +warning: impl trait in impl method signature does not match trait method signature + --> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40 + | +LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; + | ---------------------- return type from trait method defined here +... +LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} + | ^^^^^^^^^^^^^^^^ + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + = note: we are soliciting feedback, see issue #121718 for more information + = note: `#[warn(refining_impl_trait_reachable)]` on by default +help: replace the return type so that it matches the trait + | +LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized {} + | ~~~~~~~~~~ + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs index 72ce617693e40..3f435f0f443b4 100644 --- a/tests/ui/impl-trait/where-allowed.rs +++ b/tests/ui/impl-trait/where-allowed.rs @@ -42,7 +42,7 @@ fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds -// Allowed +// Allowed (but it's still ambiguous; nothing constrains the RPIT in this body). fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } //~^ ERROR: type annotations needed @@ -79,7 +79,6 @@ fn in_impl_Trait_in_parameters(_: impl Iterator) { panic!( // Allowed fn in_impl_Trait_in_return() -> impl IntoIterator { vec![vec![0; 10], vec![12; 7], vec![8; 3]] - //~^ ERROR: no function or associated item named `into_vec` found for slice `[_]` } // Disallowed diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 1fb69db98c162..2770a6cc40e59 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in associated types is unstable - --> $DIR/where-allowed.rs:122:16 + --> $DIR/where-allowed.rs:121:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | type Out = impl Debug; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:159:23 + --> $DIR/where-allowed.rs:158:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | type InTypeAlias = impl Debug; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:162:39 + --> $DIR/where-allowed.rs:161:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:86:32 + --> $DIR/where-allowed.rs:85:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | struct InBraceStructField { x: impl Debug } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:90:41 + --> $DIR/where-allowed.rs:89:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ @@ -159,7 +159,7 @@ LL | struct InAdtInBraceStructField { x: Vec } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:94:27 + --> $DIR/where-allowed.rs:93:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | struct InTupleStructField(impl Debug); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:99:25 + --> $DIR/where-allowed.rs:98:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ @@ -175,7 +175,7 @@ LL | InBraceVariant { x: impl Debug }, = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:101:20 + --> $DIR/where-allowed.rs:100:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ @@ -183,7 +183,7 @@ LL | InTupleVariant(impl Debug), = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `extern fn` parameters - --> $DIR/where-allowed.rs:143:33 + --> $DIR/where-allowed.rs:142:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ @@ -191,7 +191,7 @@ LL | fn in_foreign_parameters(_: impl Debug); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `extern fn` return types - --> $DIR/where-allowed.rs:146:31 + --> $DIR/where-allowed.rs:145:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ @@ -199,7 +199,7 @@ LL | fn in_foreign_return() -> impl Debug; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `fn` pointer return types - --> $DIR/where-allowed.rs:162:39 + --> $DIR/where-allowed.rs:161:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -207,7 +207,7 @@ LL | type InReturnInTypeAlias = fn() -> impl Debug; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in traits - --> $DIR/where-allowed.rs:167:16 + --> $DIR/where-allowed.rs:166:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ @@ -215,7 +215,7 @@ LL | impl PartialEq for () { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:172:24 + --> $DIR/where-allowed.rs:171:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ @@ -223,7 +223,7 @@ LL | impl PartialEq<()> for impl Debug { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:177:6 + --> $DIR/where-allowed.rs:176:6 | LL | impl impl Debug { | ^^^^^^^^^^ @@ -231,7 +231,7 @@ LL | impl impl Debug { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:183:24 + --> $DIR/where-allowed.rs:182:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ @@ -239,7 +239,7 @@ LL | impl InInherentImplAdt { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:189:11 + --> $DIR/where-allowed.rs:188:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ @@ -247,7 +247,7 @@ LL | where impl Debug: Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:196:15 + --> $DIR/where-allowed.rs:195:15 | LL | where Vec: Debug | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | where Vec: Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:203:24 + --> $DIR/where-allowed.rs:202:24 | LL | where T: PartialEq | ^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | where T: PartialEq = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds - --> $DIR/where-allowed.rs:210:17 + --> $DIR/where-allowed.rs:209:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | where T: Fn(impl Debug) = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds - --> $DIR/where-allowed.rs:217:22 + --> $DIR/where-allowed.rs:216:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | where T: Fn() -> impl Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:223:40 + --> $DIR/where-allowed.rs:222:40 | LL | struct InStructGenericParamDefault(T); | ^^^^^^^^^^ @@ -287,7 +287,7 @@ LL | struct InStructGenericParamDefault(T); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:227:36 + --> $DIR/where-allowed.rs:226:36 | LL | enum InEnumGenericParamDefault { Variant(T) } | ^^^^^^^^^^ @@ -295,7 +295,7 @@ LL | enum InEnumGenericParamDefault { Variant(T) } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:231:38 + --> $DIR/where-allowed.rs:230:38 | LL | trait InTraitGenericParamDefault {} | ^^^^^^^^^^ @@ -303,7 +303,7 @@ LL | trait InTraitGenericParamDefault {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:235:41 + --> $DIR/where-allowed.rs:234:41 | LL | type InTypeAliasGenericParamDefault = T; | ^^^^^^^^^^ @@ -311,7 +311,7 @@ LL | type InTypeAliasGenericParamDefault = T; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:239:11 + --> $DIR/where-allowed.rs:238:11 | LL | impl T {} | ^^^^^^^^^^ @@ -319,7 +319,7 @@ LL | impl T {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:246:40 + --> $DIR/where-allowed.rs:245:40 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^ @@ -327,7 +327,7 @@ LL | fn in_method_generic_param_default(_: T) {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/where-allowed.rs:252:29 + --> $DIR/where-allowed.rs:251:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ @@ -335,7 +335,7 @@ LL | let _in_local_variable: impl Fn() = || {}; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in closure return types - --> $DIR/where-allowed.rs:254:46 + --> $DIR/where-allowed.rs:253:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ @@ -363,7 +363,7 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:239:7 + --> $DIR/where-allowed.rs:238:7 | LL | impl T {} | ^^^^^^^^^^^^^^ @@ -373,25 +373,15 @@ LL | impl T {} = note: `#[deny(invalid_type_param_default)]` on by default error[E0118]: no nominal type found for inherent implementation - --> $DIR/where-allowed.rs:239:1 + --> $DIR/where-allowed.rs:238:1 | LL | impl T {} | ^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead -error[E0599]: no function or associated item named `into_vec` found for slice `[_]` in the current scope - --> $DIR/where-allowed.rs:81:5 - | -LL | vec![vec![0; 10], vec![12; 7], vec![8; 3]] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item not found in `[_]` - | -help: there is an associated function `to_vec` with a similar name - --> $SRC_DIR/alloc/src/slice.rs:LL:COL - = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0053]: method `in_trait_impl_return` has an incompatible type for trait - --> $DIR/where-allowed.rs:129:34 + --> $DIR/where-allowed.rs:128:34 | LL | type Out = impl Debug; | ---------- the expected opaque type @@ -400,7 +390,7 @@ LL | fn in_trait_impl_return() -> impl Debug { () } | ^^^^^^^^^^ expected opaque type, found a different opaque type | note: type in trait - --> $DIR/where-allowed.rs:119:34 + --> $DIR/where-allowed.rs:118:34 | LL | fn in_trait_impl_return() -> Self::Out; | ^^^^^^^^^ @@ -413,7 +403,7 @@ LL | fn in_trait_impl_return() -> <() as DummyTrait>::Out { () } | ~~~~~~~~~~~~~~~~~~~~~~~ error: unconstrained opaque type - --> $DIR/where-allowed.rs:122:16 + --> $DIR/where-allowed.rs:121:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -421,7 +411,7 @@ LL | type Out = impl Debug; = note: `Out` must be used in combination with a concrete type within the same impl error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:246:36 + --> $DIR/where-allowed.rs:245:36 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^^^^^ @@ -429,13 +419,13 @@ LL | fn in_method_generic_param_default(_: T) {} = 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 #36887 -error: aborting due to 50 previous errors +error: aborting due to 49 previous errors -Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0599, E0658, E0666. +Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0658, E0666. For more information about an error, try `rustc --explain E0053`. Future incompatibility report: Future breakage diagnostic: error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:239:7 + --> $DIR/where-allowed.rs:238:7 | LL | impl T {} | ^^^^^^^^^^^^^^ @@ -446,7 +436,7 @@ LL | impl T {} Future breakage diagnostic: error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:246:36 + --> $DIR/where-allowed.rs:245:36 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^^^^^ diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-2.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-2.rs new file mode 100644 index 0000000000000..ca8b8b7e4d92b --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-2.rs @@ -0,0 +1,13 @@ +//@ check-pass +//@ known-bug: #25860 + +static UNIT: &'static &'static () = &&(); + +fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T, _: &()) -> &'a T { v } + +fn bad<'a, T>(x: &'a T) -> &'static T { + let f: fn(_, &'a T, &()) -> &'static T = foo; + f(UNIT, x, &()) +} + +fn main() {} diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.rs new file mode 100644 index 0000000000000..226a6fa30163c --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.rs @@ -0,0 +1,13 @@ +// Regression test for #129021. + +static UNIT: &'static &'static () = &&(); + +fn foo<'a: 'a, 'b: 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v } + +fn bad<'a, T>(x: &'a T) -> &'static T { + let f: fn(_, &'a T) -> &'static T = foo; + //~^ ERROR lifetime may not live long enough + f(UNIT, x) +} + +fn main() {} diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.stderr b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.stderr new file mode 100644 index 0000000000000..84d2a6d2b6a62 --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-on-nested-references-plus-variance-early-bound.rs:8:12 + | +LL | fn bad<'a, T>(x: &'a T) -> &'static T { + | -- lifetime `'a` defined here +LL | let f: fn(_, &'a T) -> &'static T = foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.rs new file mode 100644 index 0000000000000..f30689901893c --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.rs @@ -0,0 +1,19 @@ +// Regression test for #129021. + +trait ToArg { + type Arg; +} +impl ToArg for U { + type Arg = T; +} + +fn extend_inner<'a, 'b>(x: &'a str) -> <&'b &'a () as ToArg<&'b str>>::Arg { x } +fn extend<'a, 'b>(x: &'a str) -> &'b str { + (extend_inner as fn(_) -> _)(x) + //~^ ERROR lifetime may not live long enough +} + +fn main() { + let y = extend(&String::from("Hello World")); + println!("{}", y); +} diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.stderr b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.stderr new file mode 100644 index 0000000000000..4cdb959786a56 --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-on-nested-references-plus-variance-unnormalized.rs:12:5 + | +LL | fn extend<'a, 'b>(x: &'a str) -> &'b str { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | (extend_inner as fn(_) -> _)(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 1 previous error + diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs index f3401f34eec73..6de81cba7281a 100644 --- a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs @@ -1,8 +1,4 @@ -//@ check-pass -//@ known-bug: #25860 - -// Should fail. The combination of variance and implied bounds for nested -// references allows us to infer a longer lifetime than we can prove. +// Regression test for #129021. static UNIT: &'static &'static () = &&(); @@ -10,6 +6,7 @@ fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v } fn bad<'a, T>(x: &'a T) -> &'static T { let f: fn(_, &'a T) -> &'static T = foo; + //~^ ERROR lifetime may not live long enough f(UNIT, x) } diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.stderr b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.stderr new file mode 100644 index 0000000000000..c96fa92937b0c --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-on-nested-references-plus-variance.rs:8:12 + | +LL | fn bad<'a, T>(x: &'a T) -> &'static T { + | -- lifetime `'a` defined here +LL | let f: fn(_, &'a T) -> &'static T = foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/inference/auxiliary/inference_unstable_iterator.rs b/tests/ui/inference/auxiliary/inference_unstable_iterator.rs index 04bc0b1a8ac4a..8ba6fc89f1606 100644 --- a/tests/ui/inference/auxiliary/inference_unstable_iterator.rs +++ b/tests/ui/inference/auxiliary/inference_unstable_iterator.rs @@ -1,5 +1,5 @@ #![feature(staged_api)] -#![feature(arbitrary_self_types)] +#![feature(arbitrary_self_types_pointers)] #![stable(feature = "ipu_iterator", since = "1.0.0")] diff --git a/tests/ui/inference/auxiliary/inference_unstable_itertools.rs b/tests/ui/inference/auxiliary/inference_unstable_itertools.rs index fa1efbcfefc5d..32ca3a4511961 100644 --- a/tests/ui/inference/auxiliary/inference_unstable_itertools.rs +++ b/tests/ui/inference/auxiliary/inference_unstable_itertools.rs @@ -1,4 +1,4 @@ -#![feature(arbitrary_self_types)] +#![feature(arbitrary_self_types_pointers)] pub trait IpuItertools { fn ipu_flatten(&self) -> u32 { diff --git a/tests/ui/inference/need_type_info/type-alias-indirect.stderr b/tests/ui/inference/need_type_info/type-alias-indirect.stderr index 5c5b4c149c170..535c0044aec03 100644 --- a/tests/ui/inference/need_type_info/type-alias-indirect.stderr +++ b/tests/ui/inference/need_type_info/type-alias-indirect.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/type-alias-indirect.rs:14:5 | LL | IndirectAlias::new(); - | ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` + | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` error: aborting due to 1 previous error diff --git a/tests/ui/inference/need_type_info/type-alias.stderr b/tests/ui/inference/need_type_info/type-alias.stderr index fd9bcf2fe3f39..2c39a3f56466f 100644 --- a/tests/ui/inference/need_type_info/type-alias.stderr +++ b/tests/ui/inference/need_type_info/type-alias.stderr @@ -2,19 +2,19 @@ error[E0282]: type annotations needed --> $DIR/type-alias.rs:12:5 | LL | DirectAlias::new() - | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `DirectAlias` + | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` error[E0282]: type annotations needed --> $DIR/type-alias.rs:18:5 | LL | IndirectAlias::new(); - | ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` + | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` error[E0282]: type annotations needed --> $DIR/type-alias.rs:32:5 | LL | DirectButWithDefaultAlias::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `DirectButWithDefaultAlias` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` error: aborting due to 3 previous errors diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs new file mode 100644 index 0000000000000..a9795d1569c86 --- /dev/null +++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs @@ -0,0 +1,25 @@ +fn main() { + let _ = ['a'; { break 2; 1 }]; + //~^ ERROR `break` outside of a loop or labeled block + //~| HELP consider labeling this block to be able to break within it + + const { + { + //~^ HELP consider labeling this block to be able to break within it + break; + //~^ ERROR `break` outside of a loop or labeled block + } + }; + + const { + break; + //~^ ERROR `break` outside of a loop or labeled block + }; + + { + const { + break; + //~^ ERROR `break` outside of a loop or labeled block + } + } +} diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr new file mode 100644 index 0000000000000..300cd45ad6912 --- /dev/null +++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr @@ -0,0 +1,39 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:15:9 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:21:13 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:2:21 + | +LL | let _ = ['a'; { break 2; 1 }]; + | ^^^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL | let _ = ['a'; 'block: { break 'block 2; 1 }]; + | +++++++ ++++++ + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:9:13 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL | +LL ~ break 'block; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/inline-const/const-expr-lifetime-err.rs b/tests/ui/inline-const/const-expr-lifetime-err.rs index df1e5fcb47352..8e8e01467287a 100644 --- a/tests/ui/inline-const/const-expr-lifetime-err.rs +++ b/tests/ui/inline-const/const-expr-lifetime-err.rs @@ -1,5 +1,3 @@ -#![feature(const_mut_refs)] - use std::marker::PhantomData; #[derive(PartialEq, Eq)] diff --git a/tests/ui/inline-const/const-expr-lifetime-err.stderr b/tests/ui/inline-const/const-expr-lifetime-err.stderr index f97e2d25e6c25..be3fc8d28c51e 100644 --- a/tests/ui/inline-const/const-expr-lifetime-err.stderr +++ b/tests/ui/inline-const/const-expr-lifetime-err.stderr @@ -1,5 +1,5 @@ error[E0597]: `y` does not live long enough - --> $DIR/const-expr-lifetime-err.rs:22:30 + --> $DIR/const-expr-lifetime-err.rs:20:30 | LL | fn foo<'a>() { | -- lifetime `'a` defined here diff --git a/tests/ui/inline-const/const-expr-lifetime.rs b/tests/ui/inline-const/const-expr-lifetime.rs index 071e724a0faa3..61c507f9791bf 100644 --- a/tests/ui/inline-const/const-expr-lifetime.rs +++ b/tests/ui/inline-const/const-expr-lifetime.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(const_mut_refs)] - use std::marker::PhantomData; // rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid" diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.rs b/tests/ui/inline-const/const-match-pat-lifetime-err.rs index ff0a9dbf110c4..7f450ebe6fccf 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime-err.rs +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.rs @@ -1,4 +1,3 @@ -#![feature(const_mut_refs)] #![feature(inline_const_pat)] use std::marker::PhantomData; diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr index 98ce6cfae7b38..95fe7085e5027 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr @@ -1,5 +1,5 @@ error[E0597]: `y` does not live long enough - --> $DIR/const-match-pat-lifetime-err.rs:28:29 + --> $DIR/const-match-pat-lifetime-err.rs:27:29 | LL | fn match_invariant_ref<'a>() { | -- lifetime `'a` defined here @@ -15,7 +15,7 @@ LL | } | - `y` dropped here while still borrowed error: lifetime may not live long enough - --> $DIR/const-match-pat-lifetime-err.rs:38:12 + --> $DIR/const-match-pat-lifetime-err.rs:37:12 | LL | fn match_covariant_ref<'a>() { | -- lifetime `'a` defined here diff --git a/tests/ui/inline-const/const-match-pat-lifetime.rs b/tests/ui/inline-const/const-match-pat-lifetime.rs index 590c426c77379..7f1011ea2400d 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime.rs +++ b/tests/ui/inline-const/const-match-pat-lifetime.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(const_mut_refs)] #![feature(inline_const_pat)] use std::marker::PhantomData; diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr index 15fa3f6ee115f..b8b7d6e1a5e93 100644 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr @@ -1,5 +1,5 @@ warning: number of conditions in decision (7) exceeds limit (6), so MC/DC analysis will not count this expression - --> $DIR/mcdc-condition-limit.rs:29:8 + --> $DIR/mcdc-condition-limit.rs:28:8 | LL | if a && b && c && d && e && f && g { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.rs b/tests/ui/instrument-coverage/mcdc-condition-limit.rs index eb19ddec78fd5..91ff6381df766 100644 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.rs +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.rs @@ -1,5 +1,4 @@ //@ edition: 2021 -//@ min-llvm-version: 18 //@ revisions: good bad //@ check-pass //@ compile-flags: -Cinstrument-coverage -Zcoverage-options=mcdc -Zno-profiler-runtime diff --git a/tests/ui/invalid-compile-flags/print-without-arg.rs b/tests/ui/invalid-compile-flags/print-without-arg.rs new file mode 100644 index 0000000000000..a762cb22275ee --- /dev/null +++ b/tests/ui/invalid-compile-flags/print-without-arg.rs @@ -0,0 +1 @@ +//@ compile-flags: --print diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr new file mode 100644 index 0000000000000..a18d2779cade9 --- /dev/null +++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr @@ -0,0 +1,5 @@ +error: Argument to option 'print' missing + Usage: + --print [crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|all-target-specs-json|native-static-libs|stack-protector-strategies|link-args|deployment-target] + Compiler information to print on stdout + diff --git a/tests/ui/issues/issue-10734.rs b/tests/ui/issues/issue-10734.rs index 8daa401748c7c..6d815aeca076e 100644 --- a/tests/ui/issues/issue-10734.rs +++ b/tests/ui/issues/issue-10734.rs @@ -1,6 +1,9 @@ //@ run-pass #![allow(non_upper_case_globals)] +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] + static mut drop_count: usize = 0; struct Foo { diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr index 8205ee0c38d53..5603dc18b635f 100644 --- a/tests/ui/issues/issue-11771.stderr +++ b/tests/ui/issues/issue-11771.stderr @@ -6,14 +6,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - `&'a f128` implements `Add` - `&'a f16` implements `Add` - `&'a f32` implements `Add` - `&'a f64` implements `Add` - `&'a i128` implements `Add` - `&'a i16` implements `Add` - `&'a i32` implements `Add` - `&'a i64` implements `Add` + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` and 56 others error[E0277]: cannot add `()` to `{integer}` @@ -24,14 +24,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - `&'a f128` implements `Add` - `&'a f16` implements `Add` - `&'a f32` implements `Add` - `&'a f64` implements `Add` - `&'a i128` implements `Add` - `&'a i16` implements `Add` - `&'a i32` implements `Add` - `&'a i64` implements `Add` + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-15858.rs b/tests/ui/issues/issue-15858.rs index 2d4aac01fbe8e..27887d49e3e8a 100644 --- a/tests/ui/issues/issue-15858.rs +++ b/tests/ui/issues/issue-15858.rs @@ -1,4 +1,6 @@ //@ run-pass +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] static mut DROP_RAN: bool = false; trait Bar { diff --git a/tests/ui/issues/issue-15858.stderr b/tests/ui/issues/issue-15858.stderr index f36bcc21bd7fb..0c082cc086218 100644 --- a/tests/ui/issues/issue-15858.stderr +++ b/tests/ui/issues/issue-15858.stderr @@ -1,5 +1,5 @@ warning: method `do_something` is never used - --> $DIR/issue-15858.rs:5:8 + --> $DIR/issue-15858.rs:7:8 | LL | trait Bar { | --- method in this trait diff --git a/tests/ui/issues/issue-16151.rs b/tests/ui/issues/issue-16151.rs index 20a3b5a04da23..b18108e0a8ad8 100644 --- a/tests/ui/issues/issue-16151.rs +++ b/tests/ui/issues/issue-16151.rs @@ -1,5 +1,8 @@ //@ run-pass +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use std::mem; static mut DROP_COUNT: usize = 0; diff --git a/tests/ui/issues/issue-24352.stderr b/tests/ui/issues/issue-24352.stderr index 2e7dc254d914d..3e0f812b5c757 100644 --- a/tests/ui/issues/issue-24352.stderr +++ b/tests/ui/issues/issue-24352.stderr @@ -6,8 +6,8 @@ LL | 1.0f64 - 1 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - `&'a f64` implements `Sub` - `&f64` implements `Sub<&f64>` + `&f64` implements `Sub` + `&f64` implements `Sub` `f64` implements `Sub<&f64>` `f64` implements `Sub` help: consider using a floating-point literal by writing it with `.0` diff --git a/tests/ui/issues/issue-39367.rs b/tests/ui/issues/issue-39367.rs index dd16d4da1bdd2..937d6c4b9e0b0 100644 --- a/tests/ui/issues/issue-39367.rs +++ b/tests/ui/issues/issue-39367.rs @@ -20,6 +20,7 @@ fn arena() -> &'static ArenaSet> { static mut ONCE: Once = Once::new(); ONCE.call_once(|| { + //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] DATA = transmute ::>>, *const ArenaSet>> (Box::new(__static_ref_initialize())); diff --git a/tests/ui/issues/issue-39367.stderr b/tests/ui/issues/issue-39367.stderr new file mode 100644 index 0000000000000..333c9f9634a31 --- /dev/null +++ b/tests/ui/issues/issue-39367.stderr @@ -0,0 +1,17 @@ +warning: creating a shared reference to mutable static is discouraged + --> $DIR/issue-39367.rs:22:13 + | +LL | / ONCE.call_once(|| { +LL | | +LL | | DATA = transmute +LL | | ::>>, *const ArenaSet>> +LL | | (Box::new(__static_ref_initialize())); +LL | | }); + | |______________^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = note: `#[warn(static_mut_refs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-4734.rs b/tests/ui/issues/issue-4734.rs index 938d7064789de..58aa0179693e7 100644 --- a/tests/ui/issues/issue-4734.rs +++ b/tests/ui/issues/issue-4734.rs @@ -3,7 +3,8 @@ // Ensures that destructors are run for expressions of the form "e;" where // `e` is a type which requires a destructor. - +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] #![allow(path_statements)] struct A { n: isize } diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/issues/issue-50582.stderr index 7203fdeb0bbca..af7a36f62fb88 100644 --- a/tests/ui/issues/issue-50582.stderr +++ b/tests/ui/issues/issue-50582.stderr @@ -16,14 +16,14 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - `&'a f128` implements `Add` - `&'a f16` implements `Add` - `&'a f32` implements `Add` - `&'a f64` implements `Add` - `&'a i128` implements `Add` - `&'a i16` implements `Add` - `&'a i32` implements `Add` - `&'a i64` implements `Add` + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-54410.rs b/tests/ui/issues/issue-54410.rs index 208be6f221c25..e3e8ca985b970 100644 --- a/tests/ui/issues/issue-54410.rs +++ b/tests/ui/issues/issue-54410.rs @@ -5,5 +5,4 @@ extern "C" { fn main() { println!("{:p}", unsafe { &symbol }); - //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] } diff --git a/tests/ui/issues/issue-54410.stderr b/tests/ui/issues/issue-54410.stderr index 6cc5cd95e2f7d..97e5990750e3c 100644 --- a/tests/ui/issues/issue-54410.stderr +++ b/tests/ui/issues/issue-54410.stderr @@ -6,21 +6,6 @@ LL | pub static mut symbol: [i8]; | = help: the trait `Sized` is not implemented for `[i8]` -warning: creating a shared reference to mutable static is discouraged - --> $DIR/issue-54410.rs:7:31 - | -LL | println!("{:p}", unsafe { &symbol }); - | ^^^^^^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer - | -LL | println!("{:p}", unsafe { addr_of!(symbol) }); - | ~~~~~~~~~ + - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-63983.stderr b/tests/ui/issues/issue-63983.stderr index f90c81116264a..3539732451ce2 100644 --- a/tests/ui/issues/issue-63983.stderr +++ b/tests/ui/issues/issue-63983.stderr @@ -12,6 +12,11 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia | LL | MyEnum::Struct => "", | ^^^^^^^^^^^^^^ not a unit struct, unit variant or constant + | +help: the struct variant's field is being ignored + | +LL | MyEnum::Struct { s: _ } => "", + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-6892.rs b/tests/ui/issues/issue-6892.rs index aff00cf60bacd..7d99aef4ac5c1 100644 --- a/tests/ui/issues/issue-6892.rs +++ b/tests/ui/issues/issue-6892.rs @@ -3,6 +3,8 @@ // Ensures that destructors are run for expressions of the form "let _ = e;" // where `e` is a type which requires a destructor. +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] struct Foo; struct Bar { x: isize } diff --git a/tests/ui/issues/issue-8860.rs b/tests/ui/issues/issue-8860.rs index 67e9a276ae487..3af61576fe1a2 100644 --- a/tests/ui/issues/issue-8860.rs +++ b/tests/ui/issues/issue-8860.rs @@ -1,4 +1,6 @@ //@ run-pass +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] #![allow(dead_code)] static mut DROP: isize = 0; diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr index a7685e4938d88..3d3bbab881926 100644 --- a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr @@ -33,7 +33,7 @@ LL | println!("{}", scores.sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:14:10 @@ -66,7 +66,7 @@ LL | .sum::(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:23:14 @@ -99,7 +99,7 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:27:38 diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr index 189f089ba51a7..1f1f7c99e5610 100644 --- a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -8,7 +8,7 @@ LL | let x = Some(()).iter().map(|()| 1).sum::(); | = help: the trait `Sum<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sum`: - `f32` implements `Sum<&'a f32>` + `f32` implements `Sum<&f32>` `f32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29 diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index f72a9f702dcec..bc35fcd489df5 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -33,7 +33,7 @@ LL | println!("{}", scores.sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:12:10 @@ -65,7 +65,7 @@ LL | .sum::(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:25:14 @@ -104,7 +104,7 @@ LL | .sum::(), | = help: the trait `Sum` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:33:14 @@ -134,7 +134,7 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:38:38 @@ -162,7 +162,7 @@ LL | println!("{}", vec![(), ()].iter().sum::()); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:39:33 diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr index aad020e4ec97a..5892596dc6adc 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/kindck/kindck-impl-type-params.stderr @@ -112,13 +112,13 @@ LL | struct Foo; // does not impl Copy | error: lifetime may not live long enough - --> $DIR/kindck-impl-type-params.rs:30:13 + --> $DIR/kindck-impl-type-params.rs:30:19 | LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let t: S<&'a isize> = S(marker::PhantomData); LL | let a = &t as &dyn Gettable<&'a isize>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: aborting due to 7 previous errors diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs index aeacbc784462d..166321798de30 100644 --- a/tests/ui/layout/debug.rs +++ b/tests/ui/layout/debug.rs @@ -49,7 +49,7 @@ union P2 { x: (u32, u32) } //~ ERROR: layout_of #[repr(simd)] #[derive(Copy, Clone)] -struct F32x4(f32, f32, f32, f32); +struct F32x4([f32; 4]); #[rustc_layout(debug)] #[repr(packed(1))] @@ -76,3 +76,8 @@ impl S { #[rustc_layout(debug)] type Impossible = (str, str); //~ ERROR: cannot be known at compilation time + +// Test that computing the layout of an empty union doesn't ICE. +#[rustc_layout(debug)] +union EmptyUnion {} //~ ERROR: has an unknown layout +//~^ ERROR: unions cannot have zero fields diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index 5162a771b4df7..c9715a8e14632 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -1,3 +1,9 @@ +error: unions cannot have zero fields + --> $DIR/debug.rs:82:1 + | +LL | union EmptyUnion {} + | ^^^^^^^^^^^^^^^^^^^ + error: layout_of(E) = Layout { size: Size(12 bytes), align: AbiAndPrefAlign { @@ -566,12 +572,18 @@ LL | type Impossible = (str, str); = help: the trait `Sized` is not implemented for `str` = note: only the last element of a tuple may have a dynamically sized type +error: the type `EmptyUnion` has an unknown layout + --> $DIR/debug.rs:82:1 + | +LL | union EmptyUnion {} + | ^^^^^^^^^^^^^^^^ + error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases --> $DIR/debug.rs:74:5 | LL | const C: () = (); | ^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/invalid-unsized-const-eval.rs b/tests/ui/layout/invalid-unsized-const-eval.rs new file mode 100644 index 0000000000000..2dec0b0faacf2 --- /dev/null +++ b/tests/ui/layout/invalid-unsized-const-eval.rs @@ -0,0 +1,14 @@ +// issue: #124182 + +//! This test used to trip an assertion in const eval, because `layout_of(LazyLock)` +//! returned `Ok` with an unsized layout when a sized layout was expected. +//! It was fixed by making `layout_of` always return `Err` for types that +//! contain unsized fields in unexpected locations. + +struct LazyLock { + data: (dyn Sync, ()), //~ ERROR the size for values of type +} + +static EMPTY_SET: LazyLock = todo!(); + +fn main() {} diff --git a/tests/ui/layout/invalid-unsized-const-eval.stderr b/tests/ui/layout/invalid-unsized-const-eval.stderr new file mode 100644 index 0000000000000..bf65782b7a805 --- /dev/null +++ b/tests/ui/layout/invalid-unsized-const-eval.stderr @@ -0,0 +1,12 @@ +error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time + --> $DIR/invalid-unsized-const-eval.rs:9:11 + | +LL | data: (dyn Sync, ()), + | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Sync + 'static)` + = note: only the last element of a tuple may have a dynamically sized type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/crashes/127737.rs b/tests/ui/layout/invalid-unsized-const-prop.rs similarity index 65% rename from tests/crashes/127737.rs rename to tests/ui/layout/invalid-unsized-const-prop.rs index 2ee8c769858a8..2f1c398c35a41 100644 --- a/tests/crashes/127737.rs +++ b/tests/ui/layout/invalid-unsized-const-prop.rs @@ -1,6 +1,10 @@ -//@ known-bug: #127737 +// issue: #127737 +//@ check-pass //@ compile-flags: -Zmir-opt-level=5 --crate-type lib +//! This test is very similar to `invalid-unsized-const-eval.rs`, but also requires +//! checking for unsized types in the last field of each enum variant. + pub trait TestTrait { type MyType; fn func() -> Option diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.rs b/tests/ui/layout/invalid-unsized-in-always-sized-tail.rs new file mode 100644 index 0000000000000..5df97338710dd --- /dev/null +++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.rs @@ -0,0 +1,17 @@ +// issue: rust-lang/rust#126939 + +//! This used to ICE, because the layout algorithm did not check for unsized types +//! in the struct tail of always-sized types (i.e. those that cannot be unsized) +//! and incorrectly returned an unsized layout. + +struct MySlice(T); +type MySliceBool = MySlice<[bool]>; + +struct P2 { + b: MySliceBool, + //~^ ERROR: the size for values of type `[bool]` cannot be known at compilation time +} + +static CHECK: () = assert!(align_of::() == 1); + +fn main() {} diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr new file mode 100644 index 0000000000000..3f565d6ee5ba8 --- /dev/null +++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr @@ -0,0 +1,23 @@ +error[E0277]: the size for values of type `[bool]` cannot be known at compilation time + --> $DIR/invalid-unsized-in-always-sized-tail.rs:11:8 + | +LL | b: MySliceBool, + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[bool]` +note: required by an implicit `Sized` bound in `MySlice` + --> $DIR/invalid-unsized-in-always-sized-tail.rs:7:16 + | +LL | struct MySlice(T); + | ^ required by the implicit `Sized` requirement on this type parameter in `MySlice` +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` + --> $DIR/invalid-unsized-in-always-sized-tail.rs:7:16 + | +LL | struct MySlice(T); + | ^ - ...if indirection were used here: `Box` + | | + | this could be changed to `T: ?Sized`... + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/size-of-val-raw-too-big.rs b/tests/ui/layout/size-of-val-raw-too-big.rs index 8d82c78d95397..dfca6d6eb764f 100644 --- a/tests/ui/layout/size-of-val-raw-too-big.rs +++ b/tests/ui/layout/size-of-val-raw-too-big.rs @@ -1,7 +1,7 @@ //@ build-fail //@ compile-flags: --crate-type lib //@ only-32bit Layout computation rejects this layout for different reasons on 64-bit. -//@ error-pattern: too big for the current architecture +//@ error-pattern: too big for the target architecture #![feature(core_intrinsics)] #![allow(internal_features)] diff --git a/tests/ui/layout/size-of-val-raw-too-big.stderr b/tests/ui/layout/size-of-val-raw-too-big.stderr index aa9abd644faaf..886bba9ec9d34 100644 --- a/tests/ui/layout/size-of-val-raw-too-big.stderr +++ b/tests/ui/layout/size-of-val-raw-too-big.stderr @@ -1,4 +1,4 @@ -error: values of the type `Example` are too big for the current architecture +error: values of the type `Example` are too big for the target architecture error: aborting due to 1 previous error diff --git a/tests/ui/layout/too-big-with-padding.rs b/tests/ui/layout/too-big-with-padding.rs index 76703100145ad..8423ad2e1d607 100644 --- a/tests/ui/layout/too-big-with-padding.rs +++ b/tests/ui/layout/too-big-with-padding.rs @@ -10,7 +10,7 @@ #[repr(C, align(2))] pub struct Example([u8; 0x7fffffff]); -pub fn lib(_x: Example) {} //~ERROR: too big for the current architecture +pub fn lib(_x: Example) {} //~ERROR: too big for the target architecture #[lang = "sized"] pub trait Sized {} diff --git a/tests/ui/layout/too-big-with-padding.stderr b/tests/ui/layout/too-big-with-padding.stderr index 71309788dac86..fc3b4db049ac3 100644 --- a/tests/ui/layout/too-big-with-padding.stderr +++ b/tests/ui/layout/too-big-with-padding.stderr @@ -1,4 +1,4 @@ -error: values of the type `Example` are too big for the current architecture +error: values of the type `Example` are too big for the target architecture --> $DIR/too-big-with-padding.rs:13:1 | LL | pub fn lib(_x: Example) {} diff --git a/tests/ui/layout/trivial-bounds-sized.rs b/tests/ui/layout/trivial-bounds-sized.rs new file mode 100644 index 0000000000000..a32539f80fa4f --- /dev/null +++ b/tests/ui/layout/trivial-bounds-sized.rs @@ -0,0 +1,51 @@ +//@ check-pass + +//! With trivial bounds, it is possible to have ADTs with unsized fields +//! in arbitrary places. Test that we do not ICE for such types. + +#![feature(trivial_bounds)] +#![expect(trivial_bounds)] + +struct Struct +where + [u8]: Sized, + [i16]: Sized, +{ + a: [u8], + b: [i16], + c: f32, +} + +union Union +where + [u8]: Copy, + [i16]: Copy, +{ + a: [u8], + b: [i16], + c: f32, +} + +enum Enum +where + [u8]: Sized, + [i16]: Sized, +{ + V1([u8], [i16]), + V2([i16], f32), +} + +// This forces layout computation via the `variant_size_differences` lint. +// FIXME: This could be made more robust, possibly with a variant of `rustc_layout` +// that doesn't error. +enum Check +where + [u8]: Copy, + [i16]: Copy, +{ + Struct(Struct), + Union(Union), + Enum(Enum), +} + +fn main() {} diff --git a/tests/crashes/123134.rs b/tests/ui/layout/unsatisfiable-sized-ungated.rs similarity index 55% rename from tests/crashes/123134.rs rename to tests/ui/layout/unsatisfiable-sized-ungated.rs index 61c043db763f5..d9c1f739bdbfa 100644 --- a/tests/crashes/123134.rs +++ b/tests/ui/layout/unsatisfiable-sized-ungated.rs @@ -1,4 +1,9 @@ -//@ known-bug: #123134 +//@ check-pass +// issue: #123134 + +//! This is a variant of `trivial-bounds-sized.rs` that compiles without any +//! feature gates and used to trigger a delayed bug. + trait Api: Sized { type Device: ?Sized; } @@ -7,7 +12,7 @@ struct OpenDevice where A::Device: Sized, { - device: A::Device, + device: A::Device, // <- this is the type that ends up being unsized. queue: (), } @@ -31,6 +36,8 @@ impl Adapter for T { fn open() -> OpenDevice where ::Device: Sized, + // ^ the bound expands to `<::A as Api>::Device: Sized`, which + // is not considered trivial due to containing the type parameter `T` { unreachable!() } diff --git a/tests/ui/lazy-type-alias/trailing-where-clause.stderr b/tests/ui/lazy-type-alias/trailing-where-clause.stderr index 9fabbe91d25a4..93cd3145928b7 100644 --- a/tests/ui/lazy-type-alias/trailing-where-clause.stderr +++ b/tests/ui/lazy-type-alias/trailing-where-clause.stderr @@ -9,7 +9,7 @@ LL | let _: Alias<()>; `String` implements `From<&mut str>` `String` implements `From<&str>` `String` implements `From>` - `String` implements `From>` + `String` implements `From>` `String` implements `From` note: required by a bound in `Alias` --> $DIR/trailing-where-clause.rs:8:13 diff --git a/tests/ui/lexer/prefixed-lifetime.rs b/tests/ui/lexer/prefixed-lifetime.rs new file mode 100644 index 0000000000000..6191b97d57697 --- /dev/null +++ b/tests/ui/lexer/prefixed-lifetime.rs @@ -0,0 +1,10 @@ +//@ edition: 2021 + +macro_rules! w { + ($($tt:tt)*) => {}; +} + +w!('foo#lifetime); +//~^ ERROR prefix `'foo` is unknown + +fn main() {} diff --git a/tests/ui/lexer/prefixed-lifetime.stderr b/tests/ui/lexer/prefixed-lifetime.stderr new file mode 100644 index 0000000000000..39e8b5a2a570a --- /dev/null +++ b/tests/ui/lexer/prefixed-lifetime.stderr @@ -0,0 +1,14 @@ +error: prefix `'foo` is unknown + --> $DIR/prefixed-lifetime.rs:7:4 + | +LL | w!('foo#lifetime); + | ^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | w!('foo #lifetime); + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr index 598f142419137..e4cd54ac33741 100644 --- a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr +++ b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr @@ -7,7 +7,7 @@ LL | let refcell = RefCell::new(&mut foo); | ^^^^^^^^ borrowed value does not live long enough LL | LL | let read = &refcell as &RefCell; - | -------- cast requires that `foo` is borrowed for `'static` + | ------------------------------ cast requires that `foo` is borrowed for `'static` ... LL | } | - `foo` dropped here while still borrowed @@ -19,7 +19,7 @@ LL | fn inner(mut foo: &[u8]) { | - let's call the lifetime of this reference `'1` ... LL | let read = &refcell as &RefCell; - | ^^^^^^^^ cast requires that `'1` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static` error: aborting due to 2 previous errors diff --git a/tests/ui/lifetimes/issue-95023.rs b/tests/ui/lifetimes/issue-95023.rs index 8461d92fc33e4..1faae50d9f158 100644 --- a/tests/ui/lifetimes/issue-95023.rs +++ b/tests/ui/lifetimes/issue-95023.rs @@ -9,6 +9,5 @@ impl Fn(&isize) for Error { //~^ ERROR associated function in `impl` without body //~| ERROR method `foo` is not a member of trait `Fn` [E0407] //~| ERROR associated type `B` not found for `Self` [E0220] - //~| ERROR: associated type `B` not found for `Self` } fn main() {} diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr index 310dee5140603..cbc0eeebee113 100644 --- a/tests/ui/lifetimes/issue-95023.stderr +++ b/tests/ui/lifetimes/issue-95023.stderr @@ -56,15 +56,7 @@ error[E0220]: associated type `B` not found for `Self` LL | fn foo(&self) -> Self::B<{ N }>; | ^ help: `Self` has the following associated type: `Output` -error[E0220]: associated type `B` not found for `Self` - --> $DIR/issue-95023.rs:8:44 - | -LL | fn foo(&self) -> Self::B<{ N }>; - | ^ help: `Self` has the following associated type: `Output` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0046, E0183, E0220, E0229, E0277, E0407. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/lifetimes/raw/gen-lt.e2024.stderr b/tests/ui/lifetimes/raw/gen-lt.e2024.stderr new file mode 100644 index 0000000000000..232453df8ef65 --- /dev/null +++ b/tests/ui/lifetimes/raw/gen-lt.e2024.stderr @@ -0,0 +1,8 @@ +error: lifetimes cannot use keyword names + --> $DIR/gen-lt.rs:11:11 + | +LL | fn gen_lt<'gen>() {} + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/raw/gen-lt.rs b/tests/ui/lifetimes/raw/gen-lt.rs new file mode 100644 index 0000000000000..4f3ede5b4a2eb --- /dev/null +++ b/tests/ui/lifetimes/raw/gen-lt.rs @@ -0,0 +1,14 @@ +//@ revisions: e2021 e2024 + +//@[e2021] edition:2021 +//@[e2024] edition:2024 +//@[e2024] compile-flags: -Zunstable-options + +//@[e2021] check-pass + +fn raw_gen_lt<'r#gen>() {} + +fn gen_lt<'gen>() {} +//[e2024]~^ ERROR lifetimes cannot use keyword names + +fn main() {} diff --git a/tests/ui/lifetimes/raw/lifetimes-eq.rs b/tests/ui/lifetimes/raw/lifetimes-eq.rs new file mode 100644 index 0000000000000..dddafb829ba85 --- /dev/null +++ b/tests/ui/lifetimes/raw/lifetimes-eq.rs @@ -0,0 +1,8 @@ +//@ edition: 2021 +//@ check-pass + +// Test that `'r#a` is `'a`. + +fn test<'r#a>(x: &'a ()) {} + +fn main() {} diff --git a/tests/ui/lifetimes/raw/macro-lt.rs b/tests/ui/lifetimes/raw/macro-lt.rs new file mode 100644 index 0000000000000..d1167b00467c4 --- /dev/null +++ b/tests/ui/lifetimes/raw/macro-lt.rs @@ -0,0 +1,12 @@ +//@ check-pass +//@ edition: 2021 + +macro_rules! lifetime { + ($lt:lifetime) => { + fn hello<$lt>() {} + } +} + +lifetime!('r#struct); + +fn main() {} diff --git a/tests/ui/lifetimes/raw/multiple-prefixes.rs b/tests/ui/lifetimes/raw/multiple-prefixes.rs new file mode 100644 index 0000000000000..f335373d8a7e7 --- /dev/null +++ b/tests/ui/lifetimes/raw/multiple-prefixes.rs @@ -0,0 +1,6 @@ +//@ edition: 2021 + +fn test(x: &'r#r#r ()) {} +//~^ ERROR expected type, found `#` + +fn main() {} diff --git a/tests/ui/lifetimes/raw/multiple-prefixes.stderr b/tests/ui/lifetimes/raw/multiple-prefixes.stderr new file mode 100644 index 0000000000000..8d5479e0a4fc5 --- /dev/null +++ b/tests/ui/lifetimes/raw/multiple-prefixes.stderr @@ -0,0 +1,8 @@ +error: expected type, found `#` + --> $DIR/multiple-prefixes.rs:3:17 + | +LL | fn test(x: &'r#r#r ()) {} + | ^ expected type + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/raw/prim-lt.rs b/tests/ui/lifetimes/raw/prim-lt.rs new file mode 100644 index 0000000000000..ca45efb65fd36 --- /dev/null +++ b/tests/ui/lifetimes/raw/prim-lt.rs @@ -0,0 +1,8 @@ +//@ check-pass +//@ edition: 2021 + +// Checks a primitive name can be defined as a lifetime. + +fn foo<'r#i32>() {} + +fn main() {} diff --git a/tests/ui/lifetimes/raw/simple.rs b/tests/ui/lifetimes/raw/simple.rs new file mode 100644 index 0000000000000..6f70a27220300 --- /dev/null +++ b/tests/ui/lifetimes/raw/simple.rs @@ -0,0 +1,21 @@ +//@ check-pass +//@ edition: 2021 + +fn foo<'r#struct>() {} + +fn hr() where for<'r#struct> T: Into<&'r#struct ()> {} + +trait Foo<'r#struct> {} + +trait Bar<'r#struct> { + fn method(&'r#struct self) {} + fn method2(self: &'r#struct Self) {} +} + +fn labeled() { + 'r#struct: loop { + break 'r#struct; + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/raw/static-lt.rs b/tests/ui/lifetimes/raw/static-lt.rs new file mode 100644 index 0000000000000..1fec7097dab26 --- /dev/null +++ b/tests/ui/lifetimes/raw/static-lt.rs @@ -0,0 +1,8 @@ +//@ check-pass +//@ edition: 2021 + +// Makes sure that `'r#static` is `'static` + +const FOO: &'r#static str = "hello, world"; + +fn main() {} diff --git a/tests/ui/lifetimes/raw/three-tokens.rs b/tests/ui/lifetimes/raw/three-tokens.rs new file mode 100644 index 0000000000000..2ae54ebbcb537 --- /dev/null +++ b/tests/ui/lifetimes/raw/three-tokens.rs @@ -0,0 +1,12 @@ +//@ edition: 2015 +//@ check-pass +// Ensure that we parse `'r#lt` as three tokens in edition 2015. + +macro_rules! ed2015 { + ('r # lt) => {}; + ($lt:lifetime) => { compile_error!() }; +} + +ed2015!('r#lt); + +fn main() {} diff --git a/tests/ui/limits/huge-array-simple-32.rs b/tests/ui/limits/huge-array-simple-32.rs index 6ff981cd160ab..db75cc57e9a22 100644 --- a/tests/ui/limits/huge-array-simple-32.rs +++ b/tests/ui/limits/huge-array-simple-32.rs @@ -4,6 +4,6 @@ #![allow(arithmetic_overflow)] fn main() { - let _fat: [u8; (1<<31)+(1<<15)] = //~ ERROR too big for the current architecture + let _fat: [u8; (1<<31)+(1<<15)] = //~ ERROR too big for the target architecture [0; (1u32<<31) as usize +(1u32<<15) as usize]; } diff --git a/tests/ui/limits/huge-array-simple-32.stderr b/tests/ui/limits/huge-array-simple-32.stderr index 1b86b02297f34..33979915feb23 100644 --- a/tests/ui/limits/huge-array-simple-32.stderr +++ b/tests/ui/limits/huge-array-simple-32.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; 2147516416]` are too big for the current architecture +error: values of the type `[u8; 2147516416]` are too big for the target architecture --> $DIR/huge-array-simple-32.rs:7:9 | LL | let _fat: [u8; (1<<31)+(1<<15)] = diff --git a/tests/ui/limits/huge-array-simple-64.rs b/tests/ui/limits/huge-array-simple-64.rs index 13b284503bf52..d2838e0d41e70 100644 --- a/tests/ui/limits/huge-array-simple-64.rs +++ b/tests/ui/limits/huge-array-simple-64.rs @@ -4,6 +4,6 @@ #![allow(arithmetic_overflow)] fn main() { - let _fat: [u8; (1<<61)+(1<<31)] = //~ ERROR too big for the current architecture + let _fat: [u8; (1<<61)+(1<<31)] = //~ ERROR too big for the target architecture [0; (1u64<<61) as usize +(1u64<<31) as usize]; } diff --git a/tests/ui/limits/huge-array-simple-64.stderr b/tests/ui/limits/huge-array-simple-64.stderr index 8d395c3c6a959..46df288d4f78a 100644 --- a/tests/ui/limits/huge-array-simple-64.stderr +++ b/tests/ui/limits/huge-array-simple-64.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; 2305843011361177600]` are too big for the current architecture +error: values of the type `[u8; 2305843011361177600]` are too big for the target architecture --> $DIR/huge-array-simple-64.rs:7:9 | LL | let _fat: [u8; (1<<61)+(1<<31)] = diff --git a/tests/ui/limits/huge-array.stderr b/tests/ui/limits/huge-array.stderr index 2ebaf17a138cd..ce0c0d650c2f8 100644 --- a/tests/ui/limits/huge-array.stderr +++ b/tests/ui/limits/huge-array.stderr @@ -1,4 +1,4 @@ -error: values of the type `[[u8; 1518599999]; 1518600000]` are too big for the current architecture +error: values of the type `[[u8; 1518599999]; 1518600000]` are too big for the target architecture --> $DIR/huge-array.rs:4:9 | LL | let s: [T; 1518600000] = [t; 1518600000]; diff --git a/tests/ui/limits/huge-enum.rs b/tests/ui/limits/huge-enum.rs index cf6e637388c7f..5664d0ba51667 100644 --- a/tests/ui/limits/huge-enum.rs +++ b/tests/ui/limits/huge-enum.rs @@ -6,9 +6,9 @@ type BIG = Option<[u32; (1<<29)-1]>; #[cfg(target_pointer_width = "64")] -type BIG = Option<[u32; (1<<45)-1]>; +type BIG = Option<[u32; (1<<59)-1]>; fn main() { let big: BIG = None; - //~^ ERROR are too big for the current architecture + //~^ ERROR are too big for the target architecture } diff --git a/tests/ui/limits/huge-enum.stderr b/tests/ui/limits/huge-enum.stderr index fcd40607af461..18168b3fa5cf7 100644 --- a/tests/ui/limits/huge-enum.stderr +++ b/tests/ui/limits/huge-enum.stderr @@ -1,4 +1,4 @@ -error: values of the type `Option` are too big for the current architecture +error: values of the type `Option` are too big for the target architecture --> $DIR/huge-enum.rs:12:9 | LL | let big: BIG = None; diff --git a/tests/ui/limits/issue-56762.rs b/tests/ui/limits/huge-static.rs similarity index 65% rename from tests/ui/limits/issue-56762.rs rename to tests/ui/limits/huge-static.rs index 17b3ad8b01e2d..4709b46e59d15 100644 --- a/tests/ui/limits/issue-56762.rs +++ b/tests/ui/limits/huge-static.rs @@ -1,6 +1,9 @@ -//@ only-x86_64 +//@ only-64bit -const HUGE_SIZE: usize = !0usize / 8; +// This test validates we gracefully fail computing a const or static of absurdly large size. +// The oddly-specific number is because of LLVM measuring object sizes in bits. + +const HUGE_SIZE: usize = 1 << 61; pub struct TooBigArray { diff --git a/tests/ui/limits/issue-56762.stderr b/tests/ui/limits/huge-static.stderr similarity index 70% rename from tests/ui/limits/issue-56762.stderr rename to tests/ui/limits/huge-static.stderr index 3a6c3559ac195..684efeeb4a3b7 100644 --- a/tests/ui/limits/issue-56762.stderr +++ b/tests/ui/limits/huge-static.stderr @@ -1,14 +1,14 @@ error[E0080]: could not evaluate static initializer - --> $DIR/issue-56762.rs:16:1 + --> $DIR/huge-static.rs:19:1 | LL | static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843009213693951]` are too big for the current architecture + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843009213693952]` are too big for the target architecture error[E0080]: could not evaluate static initializer - --> $DIR/issue-56762.rs:19:1 + --> $DIR/huge-static.rs:22:1 | LL | static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843009213693951]` are too big for the current architecture + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843009213693952]` are too big for the target architecture error: aborting due to 2 previous errors diff --git a/tests/ui/limits/huge-struct.rs b/tests/ui/limits/huge-struct.rs index b9e90b3e9d1ae..f7ce4f26db18d 100644 --- a/tests/ui/limits/huge-struct.rs +++ b/tests/ui/limits/huge-struct.rs @@ -1,7 +1,9 @@ +// ignore-tidy-linelength //@ build-fail //@ normalize-stderr-test: "S32" -> "SXX" //@ normalize-stderr-test: "S1M" -> "SXX" -//@ error-pattern: too big for the current +//@ normalize-stderr-32bit: "values of the type `[^`]+` are too big" -> "values of the type $$REALLY_TOO_BIG are too big" +//@ normalize-stderr-64bit: "values of the type `[^`]+` are too big" -> "values of the type $$REALLY_TOO_BIG are too big" struct S32 { v0: T, @@ -44,6 +46,6 @@ struct S1M { val: S1k> } fn main() { let fat: Option>>> = None; - //~^ ERROR are too big for the current architecture + //~^ ERROR are too big for the target architecture } diff --git a/tests/ui/limits/huge-struct.stderr b/tests/ui/limits/huge-struct.stderr index 782db20c7f345..b10455ffd2dca 100644 --- a/tests/ui/limits/huge-struct.stderr +++ b/tests/ui/limits/huge-struct.stderr @@ -1,5 +1,5 @@ -error: values of the type `SXX>>` are too big for the current architecture - --> $DIR/huge-struct.rs:46:9 +error: values of the type $REALLY_TOO_BIG are too big for the target architecture + --> $DIR/huge-struct.rs:48:9 | LL | let fat: Option>>> = None; | ^^^ diff --git a/tests/ui/limits/issue-15919-32.stderr b/tests/ui/limits/issue-15919-32.stderr index abd65ff3c9eb7..f162838d37d8b 100644 --- a/tests/ui/limits/issue-15919-32.stderr +++ b/tests/ui/limits/issue-15919-32.stderr @@ -1,4 +1,4 @@ -error: values of the type `[usize; usize::MAX]` are too big for the current architecture +error: values of the type `[usize; usize::MAX]` are too big for the target architecture --> $DIR/issue-15919-32.rs:5:9 | LL | let x = [0usize; 0xffff_ffff]; diff --git a/tests/ui/limits/issue-15919-64.stderr b/tests/ui/limits/issue-15919-64.stderr index d1f0cc39c1884..cd443f2065bbd 100644 --- a/tests/ui/limits/issue-15919-64.stderr +++ b/tests/ui/limits/issue-15919-64.stderr @@ -1,4 +1,4 @@ -error: values of the type `[usize; usize::MAX]` are too big for the current architecture +error: values of the type `[usize; usize::MAX]` are too big for the target architecture --> $DIR/issue-15919-64.rs:5:9 | LL | let x = [0usize; 0xffff_ffff_ffff_ffff]; diff --git a/tests/ui/limits/issue-17913.rs b/tests/ui/limits/issue-17913.rs index 325923f32f376..24fd3b542e6af 100644 --- a/tests/ui/limits/issue-17913.rs +++ b/tests/ui/limits/issue-17913.rs @@ -1,6 +1,6 @@ //@ build-fail //@ normalize-stderr-test: "\[&usize; \d+\]" -> "[&usize; usize::MAX]" -//@ error-pattern: too big for the current architecture +//@ error-pattern: too big for the target architecture #[cfg(target_pointer_width = "64")] fn main() { diff --git a/tests/ui/limits/issue-17913.stderr b/tests/ui/limits/issue-17913.stderr index 893730cbbd261..e9c3c14e18143 100644 --- a/tests/ui/limits/issue-17913.stderr +++ b/tests/ui/limits/issue-17913.stderr @@ -1,4 +1,4 @@ -error: values of the type `[&usize; usize::MAX]` are too big for the current architecture +error: values of the type `[&usize; usize::MAX]` are too big for the target architecture --> $SRC_DIR/alloc/src/boxed.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/limits/issue-55878.rs b/tests/ui/limits/issue-55878.rs index 4d91a173240da..81696e226fd07 100644 --- a/tests/ui/limits/issue-55878.rs +++ b/tests/ui/limits/issue-55878.rs @@ -2,7 +2,7 @@ //@ normalize-stderr-64bit: "18446744073709551615" -> "SIZE" //@ normalize-stderr-32bit: "4294967295" -> "SIZE" -//@ error-pattern: are too big for the current architecture +//@ error-pattern: are too big for the target architecture fn main() { println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>()); } diff --git a/tests/ui/limits/issue-55878.stderr b/tests/ui/limits/issue-55878.stderr index 97ca0f4fb592c..0a5f17be80473 100644 --- a/tests/ui/limits/issue-55878.stderr +++ b/tests/ui/limits/issue-55878.stderr @@ -1,7 +1,7 @@ error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | - = note: values of the type `[u8; usize::MAX]` are too big for the current architecture + = note: values of the type `[u8; usize::MAX]` are too big for the target architecture | note: inside `std::mem::size_of::<[u8; usize::MAX]>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/limits/issue-69485-var-size-diffs-too-large.rs b/tests/ui/limits/issue-69485-var-size-diffs-too-large.rs index 9c150c119d069..6133183a55cf1 100644 --- a/tests/ui/limits/issue-69485-var-size-diffs-too-large.rs +++ b/tests/ui/limits/issue-69485-var-size-diffs-too-large.rs @@ -3,7 +3,7 @@ //@ compile-flags: -Zmir-opt-level=0 fn main() { - Bug::V([0; !0]); //~ ERROR are too big for the current + Bug::V([0; !0]); //~ ERROR are too big for the target } enum Bug { diff --git a/tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr b/tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr index 7b9b8f76d0c88..7fa0ab95981a7 100644 --- a/tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr +++ b/tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; usize::MAX]` are too big for the current architecture +error: values of the type `[u8; usize::MAX]` are too big for the target architecture --> $DIR/issue-69485-var-size-diffs-too-large.rs:6:5 | LL | Bug::V([0; !0]); diff --git a/tests/ui/limits/issue-75158-64.stderr b/tests/ui/limits/issue-75158-64.stderr index 06aad9616cb7a..a3772e509ed67 100644 --- a/tests/ui/limits/issue-75158-64.stderr +++ b/tests/ui/limits/issue-75158-64.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; usize::MAX]` are too big for the current architecture +error: values of the type `[u8; usize::MAX]` are too big for the target architecture error: aborting due to 1 previous error diff --git a/tests/ui/link-section.rs b/tests/ui/link-section.rs index 1a791b88ef957..a8de8c2e1e77d 100644 --- a/tests/ui/link-section.rs +++ b/tests/ui/link-section.rs @@ -1,5 +1,8 @@ //@ run-pass +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + #![allow(non_upper_case_globals)] #[cfg(not(target_vendor = "apple"))] #[link_section = ".moretext"] diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs index ed11947f59e74..cc93f61e28f37 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs @@ -2,6 +2,8 @@ //! them at runtime, so deny mutable statics with #[linkage]. #![feature(linkage)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] fn main() { #[rustfmt::skip] diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr b/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr index ad9997690475b..50d5d8121969f 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr @@ -1,5 +1,5 @@ error: extern mutable statics are not allowed with `#[linkage]` - --> $DIR/linkage-attr-mutable-static.rs:9:9 + --> $DIR/linkage-attr-mutable-static.rs:11:9 | LL | #[linkage = "extern_weak"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/clashing-extern-fn-recursion.rs b/tests/ui/lint/clashing-extern-fn-recursion.rs index 40bef400594f6..ab311d398f92f 100644 --- a/tests/ui/lint/clashing-extern-fn-recursion.rs +++ b/tests/ui/lint/clashing-extern-fn-recursion.rs @@ -92,6 +92,7 @@ mod ref_recursion_once_removed { reffy: &'a Reffy2<'a>, } + #[repr(C)] struct Reffy2<'a> { reffy: &'a Reffy1<'a>, } @@ -107,6 +108,7 @@ mod ref_recursion_once_removed { reffy: &'a Reffy2<'a>, } + #[repr(C)] struct Reffy2<'a> { reffy: &'a Reffy1<'a>, } diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 728dfabb393e0..a12fe81eecdaf 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -1,7 +1,6 @@ //@ check-pass //@ aux-build:external_extern_fn.rs #![crate_type = "lib"] -#![warn(clashing_extern_declarations)] mod redeclared_different_signature { mod a { @@ -132,7 +131,7 @@ mod banana { mod three { // This _should_ trigger the lint, because repr(packed) should generate a struct that has a // different layout. - #[repr(packed)] + #[repr(C, packed)] struct Banana { weight: u32, length: u16, @@ -143,6 +142,79 @@ mod banana { //~^ WARN `weigh_banana` redeclared with a different signature } } + + mod four { + // This _should_ trigger the lint, because the type is not repr(C). + struct Banana { + weight: u32, + length: u16, + } + #[allow(improper_ctypes)] + extern "C" { + fn weigh_banana(count: *const Banana) -> u64; + //~^ WARN `weigh_banana` redeclared with a different signature + } + } +} + +// 3-field structs can't be distinguished by ScalarPair, side-stepping some shortucts +// the logic used to (incorrectly) take. +mod banana3 { + mod one { + #[repr(C)] + struct Banana { + weight: u32, + length: u16, + color: u8, + } + extern "C" { + fn weigh_banana3(count: *const Banana) -> u64; + } + } + + mod two { + #[repr(C)] + struct Banana { + weight: u32, + length: u16, + color: u8, + } // note: distinct type + // This should not trigger the lint because two::Banana is structurally equivalent to + // one::Banana. + extern "C" { + fn weigh_banana3(count: *const Banana) -> u64; + } + } + + mod three { + // This _should_ trigger the lint, because repr(packed) should generate a struct that has a + // different layout. + #[repr(C, packed)] + struct Banana { + weight: u32, + length: u16, + color: u8, + } + #[allow(improper_ctypes)] + extern "C" { + fn weigh_banana3(count: *const Banana) -> u64; + //~^ WARN `weigh_banana3` redeclared with a different signature + } + } + + mod four { + // This _should_ trigger the lint, because the type is not repr(C). + struct Banana { + weight: u32, + length: u16, + color: u8, + } + #[allow(improper_ctypes)] + extern "C" { + fn weigh_banana3(count: *const Banana) -> u64; + //~^ WARN `weigh_banana3` redeclared with a different signature + } + } } mod sameish_members { @@ -223,27 +295,6 @@ mod transparent { } } -#[allow(improper_ctypes)] -mod zst { - mod transparent { - #[repr(transparent)] - struct TransparentZst(()); - extern "C" { - fn zst() -> (); - fn transparent_zst() -> TransparentZst; - } - } - - mod not_transparent { - struct NotTransparentZst(()); - extern "C" { - // These shouldn't warn since all return types are zero sized - fn zst() -> NotTransparentZst; - fn transparent_zst() -> NotTransparentZst; - } - } -} - mod missing_return_type { mod a { extern "C" { @@ -384,6 +435,7 @@ mod unknown_layout { extern "C" { pub fn generic(l: Link); } + #[repr(C)] pub struct Link { pub item: T, pub next: *const Link, @@ -394,6 +446,7 @@ mod unknown_layout { extern "C" { pub fn generic(l: Link); } + #[repr(C)] pub struct Link { pub item: T, pub next: *const Link, diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index f75ff6d05a15c..b30dd476a1d74 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -1,5 +1,5 @@ warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:429:55 + --> $DIR/clashing-extern-fn.rs:482:55 | LL | fn hidden_niche_transparent_no_niche() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -9,7 +9,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:433:46 + --> $DIR/clashing-extern-fn.rs:486:46 | LL | fn hidden_niche_unsafe_cell() -> Option>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -18,7 +18,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option $DIR/clashing-extern-fn.rs:14:13 + --> $DIR/clashing-extern-fn.rs:13:13 | LL | fn clash(x: u8); | ---------------- `clash` previously declared here @@ -28,14 +28,10 @@ LL | fn clash(x: u64); | = note: expected `unsafe extern "C" fn(u8)` found `unsafe extern "C" fn(u64)` -note: the lint level is defined here - --> $DIR/clashing-extern-fn.rs:4:9 - | -LL | #![warn(clashing_extern_declarations)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(clashing_extern_declarations)]` on by default warning: `extern_link_name` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:52:9 + --> $DIR/clashing-extern-fn.rs:51:9 | LL | #[link_name = "extern_link_name"] | --------------------------------- `extern_link_name` previously declared here @@ -47,7 +43,7 @@ LL | fn extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature - --> $DIR/clashing-extern-fn.rs:55:9 + --> $DIR/clashing-extern-fn.rs:54:9 | LL | fn some_other_new_name(x: i16); | ------------------------------- `some_other_new_name` previously declared here @@ -59,7 +55,7 @@ LL | #[link_name = "some_other_new_name"] found `unsafe extern "C" fn(u32)` warning: `other_both_names_different` redeclares `link_name_same` with a different signature - --> $DIR/clashing-extern-fn.rs:59:9 + --> $DIR/clashing-extern-fn.rs:58:9 | LL | #[link_name = "link_name_same"] | ------------------------------- `link_name_same` previously declared here @@ -71,7 +67,7 @@ LL | #[link_name = "link_name_same"] found `unsafe extern "C" fn(u32)` warning: `different_mod` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:72:9 + --> $DIR/clashing-extern-fn.rs:71:9 | LL | fn different_mod(x: u8); | ------------------------ `different_mod` previously declared here @@ -83,7 +79,7 @@ LL | fn different_mod(x: u64); found `unsafe extern "C" fn(u64)` warning: `variadic_decl` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:82:9 + --> $DIR/clashing-extern-fn.rs:81:9 | LL | fn variadic_decl(x: u8, ...); | ----------------------------- `variadic_decl` previously declared here @@ -95,7 +91,19 @@ LL | fn variadic_decl(x: u8); found `unsafe extern "C" fn(u8)` warning: `weigh_banana` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:142:13 + --> $DIR/clashing-extern-fn.rs:141:13 + | +LL | fn weigh_banana(count: *const Banana) -> u64; + | --------------------------------------------- `weigh_banana` previously declared here +... +LL | fn weigh_banana(count: *const Banana) -> u64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn(*const banana::one::Banana) -> u64` + found `unsafe extern "C" fn(*const banana::three::Banana) -> u64` + +warning: `weigh_banana` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:154:13 | LL | fn weigh_banana(count: *const Banana) -> u64; | --------------------------------------------- `weigh_banana` previously declared here @@ -103,11 +111,35 @@ LL | fn weigh_banana(count: *const Banana) -> u64; LL | fn weigh_banana(count: *const Banana) -> u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn(*const one::Banana) -> u64` - found `unsafe extern "C" fn(*const three::Banana) -> u64` + = note: expected `unsafe extern "C" fn(*const banana::one::Banana) -> u64` + found `unsafe extern "C" fn(*const banana::four::Banana) -> u64` + +warning: `weigh_banana3` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:200:13 + | +LL | fn weigh_banana3(count: *const Banana) -> u64; + | ---------------------------------------------- `weigh_banana3` previously declared here +... +LL | fn weigh_banana3(count: *const Banana) -> u64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn(*const banana3::one::Banana) -> u64` + found `unsafe extern "C" fn(*const banana3::three::Banana) -> u64` + +warning: `weigh_banana3` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:214:13 + | +LL | fn weigh_banana3(count: *const Banana) -> u64; + | ---------------------------------------------- `weigh_banana3` previously declared here +... +LL | fn weigh_banana3(count: *const Banana) -> u64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn(*const banana3::one::Banana) -> u64` + found `unsafe extern "C" fn(*const banana3::four::Banana) -> u64` warning: `draw_point` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:171:13 + --> $DIR/clashing-extern-fn.rs:243:13 | LL | fn draw_point(p: Point); | ------------------------ `draw_point` previously declared here @@ -119,7 +151,7 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:197:13 + --> $DIR/clashing-extern-fn.rs:269:13 | LL | fn origin() -> Point3; | ---------------------- `origin` previously declared here @@ -131,7 +163,7 @@ LL | fn origin() -> Point3; found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:220:13 + --> $DIR/clashing-extern-fn.rs:292:13 | LL | fn transparent_incorrect() -> T; | -------------------------------- `transparent_incorrect` previously declared here @@ -143,7 +175,7 @@ LL | fn transparent_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:259:13 + --> $DIR/clashing-extern-fn.rs:310:13 | LL | fn missing_return_type() -> usize; | ---------------------------------- `missing_return_type` previously declared here @@ -155,7 +187,7 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:277:13 + --> $DIR/clashing-extern-fn.rs:328:13 | LL | fn non_zero_usize() -> core::num::NonZero; | ------------------------------------------------- `non_zero_usize` previously declared here @@ -167,7 +199,7 @@ LL | fn non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:279:13 + --> $DIR/clashing-extern-fn.rs:330:13 | LL | fn non_null_ptr() -> core::ptr::NonNull; | ----------------------------------------------- `non_null_ptr` previously declared here @@ -179,7 +211,7 @@ LL | fn non_null_ptr() -> *const usize; found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:373:13 + --> $DIR/clashing-extern-fn.rs:424:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -191,7 +223,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:375:13 + --> $DIR/clashing-extern-fn.rs:426:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here @@ -203,7 +235,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; found `unsafe extern "C" fn() -> *const isize` warning: `hidden_niche_transparent_no_niche` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:429:13 + --> $DIR/clashing-extern-fn.rs:482:13 | LL | fn hidden_niche_transparent_no_niche() -> usize; | ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here @@ -215,7 +247,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option Option` warning: `hidden_niche_unsafe_cell` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:433:13 + --> $DIR/clashing-extern-fn.rs:486:13 | LL | fn hidden_niche_unsafe_cell() -> usize; | --------------------------------------- `hidden_niche_unsafe_cell` previously declared here @@ -226,5 +258,5 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: 19 warnings emitted +warning: 22 warnings emitted diff --git a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr index 8c5426a60cb72..2d8c6e996439d 100644 --- a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr +++ b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr @@ -9,6 +9,10 @@ note: the lint level is defined here | LL | #![deny(elided_named_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider specifying it explicitly + | +LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 { + | +++++++ error: aborting due to 1 previous error diff --git a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr index c465aab1a03d2..3c01375d50191 100644 --- a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr +++ b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr @@ -9,6 +9,10 @@ note: the lint level is defined here | LL | #[warn(elided_named_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider specifying it explicitly + | +LL | fn bar(x: &'static u8) -> &'static u8 { + | +++++++ error: elided lifetime has a name --> $DIR/not-tied-to-crate.rs:11:31 @@ -21,6 +25,10 @@ note: the lint level is defined here | LL | #[deny(elided_named_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider specifying it explicitly + | +LL | fn baz(x: &'static u8) -> &'static u8 { + | +++++++ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/lint/elided-named-lifetimes/static.stderr b/tests/ui/lint/elided-named-lifetimes/static.stderr index d2e9776cb4f0e..fa2a2d3460fea 100644 --- a/tests/ui/lint/elided-named-lifetimes/static.stderr +++ b/tests/ui/lint/elided-named-lifetimes/static.stderr @@ -9,24 +9,43 @@ note: the lint level is defined here | LL | #![deny(elided_named_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider specifying it explicitly + | +LL | fn ampersand(x: &'static u8) -> &'static u8 { + | +++++++ error: elided lifetime has a name --> $DIR/static.rs:23:32 | LL | fn brackets(x: &'static u8) -> Brackets { | ^^^^^^^^ this elided lifetime gets resolved as `'static` + | +help: consider specifying it explicitly + | +LL | fn brackets(x: &'static u8) -> Brackets<'static> { + | +++++++++ error: elided lifetime has a name --> $DIR/static.rs:30:34 | LL | fn comma(x: &'static u8) -> Comma { | ^ this elided lifetime gets resolved as `'static` + | +help: consider specifying it explicitly + | +LL | fn comma(x: &'static u8) -> Comma<'static, u8> { + | ++++++++ error: elided lifetime has a name --> $DIR/static.rs:35:35 | LL | fn underscore(x: &'static u8) -> &'_ u8 { | ^^ this elided lifetime gets resolved as `'static` + | +help: consider specifying it explicitly + | +LL | fn underscore(x: &'static u8) -> &'static u8 { + | ~~~~~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/lint/expect-unused-imports.rs b/tests/ui/lint/expect-unused-imports.rs new file mode 100644 index 0000000000000..fc5b1bf2a0fe6 --- /dev/null +++ b/tests/ui/lint/expect-unused-imports.rs @@ -0,0 +1,9 @@ +//@ check-pass + +#![deny(unused_imports)] +#![deny(unfulfilled_lint_expectations)] + +#[expect(unused_imports)] +use std::{io, fs}; + +fn main() {} diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.rs b/tests/ui/lint/extern-C-fnptr-lints-slices.rs new file mode 100644 index 0000000000000..0c35eb37a4890 --- /dev/null +++ b/tests/ui/lint/extern-C-fnptr-lints-slices.rs @@ -0,0 +1,9 @@ +#[deny(improper_ctypes_definitions)] + +// It's an improper ctype (a slice) arg in an extern "C" fnptr. + +pub type F = extern "C" fn(&[u8]); +//~^ ERROR: `extern` fn uses type `[u8]`, which is not FFI-safe + + +fn main() {} diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr new file mode 100644 index 0000000000000..d13f93ca96f22 --- /dev/null +++ b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr @@ -0,0 +1,16 @@ +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/extern-C-fnptr-lints-slices.rs:5:14 + | +LL | pub type F = extern "C" fn(&[u8]); + | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent +note: the lint level is defined here + --> $DIR/extern-C-fnptr-lints-slices.rs:1:8 + | +LL | #[deny(improper_ctypes_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/lint-ctypes-non-recursion-limit.rs b/tests/ui/lint/lint-ctypes-non-recursion-limit.rs new file mode 100644 index 0000000000000..61e95dc5a464c --- /dev/null +++ b/tests/ui/lint/lint-ctypes-non-recursion-limit.rs @@ -0,0 +1,32 @@ +//@ check-pass + +#![recursion_limit = "5"] +#![allow(unused)] +#![deny(improper_ctypes)] + +#[repr(C)] +struct F1(*const ()); +#[repr(C)] +struct F2(*const ()); +#[repr(C)] +struct F3(*const ()); +#[repr(C)] +struct F4(*const ()); +#[repr(C)] +struct F5(*const ()); +#[repr(C)] +struct F6(*const ()); + +#[repr(C)] +struct B { + f1: F1, + f2: F2, + f3: F3, + f4: F4, + f5: F5, + f6: F6, +} + +extern "C" fn foo(_: B) {} + +fn main() {} diff --git a/tests/ui/lint/lint-missing-doc-crate.rs b/tests/ui/lint/lint-missing-doc-crate.rs new file mode 100644 index 0000000000000..afda73cbc603a --- /dev/null +++ b/tests/ui/lint/lint-missing-doc-crate.rs @@ -0,0 +1,4 @@ +// This test checks that we lint on the crate when it's missing a documentation. +// +//@ compile-flags: -Dmissing-docs --crate-type=lib +//~ ERROR missing documentation for the crate diff --git a/tests/ui/lint/lint-missing-doc-crate.stderr b/tests/ui/lint/lint-missing-doc-crate.stderr new file mode 100644 index 0000000000000..8efd3a17263fe --- /dev/null +++ b/tests/ui/lint/lint-missing-doc-crate.stderr @@ -0,0 +1,10 @@ +error: missing documentation for the crate + --> $DIR/lint-missing-doc-crate.rs:4:47 + | +LL | + | ^ + | + = note: requested on the command line with `-D missing-docs` + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/lint-missing-doc-expect.rs b/tests/ui/lint/lint-missing-doc-expect.rs new file mode 100644 index 0000000000000..991f65003dc26 --- /dev/null +++ b/tests/ui/lint/lint-missing-doc-expect.rs @@ -0,0 +1,13 @@ +// Make sure that `#[expect(missing_docs)]` is always correctly fulfilled. + +//@ check-pass +//@ revisions: lib bin test +//@ [lib]compile-flags: --crate-type lib +//@ [bin]compile-flags: --crate-type bin +//@ [test]compile-flags: --test + +#[expect(missing_docs)] +pub fn foo() {} + +#[cfg(bin)] +fn main() {} diff --git a/tests/ui/lint/lint-missing-doc-test.rs b/tests/ui/lint/lint-missing-doc-test.rs new file mode 100644 index 0000000000000..d86ec3525df36 --- /dev/null +++ b/tests/ui/lint/lint-missing-doc-test.rs @@ -0,0 +1,10 @@ +//! This test checks that denying the missing_docs lint does not trigger +//! on the generated test harness. + +//@ check-pass +//@ compile-flags: --test + +#![forbid(missing_docs)] + +#[test] +fn test() {} diff --git a/tests/ui/lint/lints-on-stmt-not-overridden-130142.rs b/tests/ui/lint/lints-on-stmt-not-overridden-130142.rs new file mode 100644 index 0000000000000..8b514f2128347 --- /dev/null +++ b/tests/ui/lint/lints-on-stmt-not-overridden-130142.rs @@ -0,0 +1,19 @@ +// Regression test for issue #130142 + +// Checks that we emit no warnings when a lint's level +// is overridden by an expect or allow attr on a Stmt node + +//@ check-pass + +#[must_use] +pub fn must_use_result() -> i32 { + 42 +} + +fn main() { + #[expect(unused_must_use)] + must_use_result(); + + #[allow(unused_must_use)] + must_use_result(); +} diff --git a/tests/ui/lint/non-local-defs/cargo-update.rs b/tests/ui/lint/non-local-defs/cargo-update.rs index 3c62a655a9f61..8b8c15795d376 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.rs +++ b/tests/ui/lint/non-local-defs/cargo-update.rs @@ -10,8 +10,6 @@ // of the `cargo update` suggestion we assert it here. //@ error-pattern: `cargo update -p non_local_macro` -#![warn(non_local_definitions)] - extern crate non_local_macro; struct LocalStruct; diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr index 4dd41519455c6..77ee28b48cc7f 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.stderr +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/cargo-update.rs:19:1 + --> $DIR/cargo-update.rs:17:1 | LL | non_local_macro::non_local_impl!(LocalStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -10,15 +10,10 @@ LL | non_local_macro::non_local_impl!(LocalStruct); | = note: the macro `non_local_macro::non_local_impl` defines the non-local `impl`, and may need to be changed = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/cargo-update.rs:13:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 1 warning emitted diff --git a/tests/ui/lint/non-local-defs/consts.rs b/tests/ui/lint/non-local-defs/consts.rs index e7ee611529b96..d8a497e43e502 100644 --- a/tests/ui/lint/non-local-defs/consts.rs +++ b/tests/ui/lint/non-local-defs/consts.rs @@ -2,8 +2,6 @@ //@ edition:2021 //@ rustc-env:CARGO_CRATE_NAME=non_local_def -#![warn(non_local_definitions)] - struct Test; trait Uto {} diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr index ed7bd56fe4a54..7f76056c0210c 100644 --- a/tests/ui/lint/non-local-defs/consts.stderr +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:15:5 + --> $DIR/consts.rs:13:5 | LL | const Z: () = { | ----------- @@ -8,23 +8,18 @@ LL | const Z: () = { | move the `impl` block outside of this constant `Z` ... LL | impl Uto for &Test {} - | ^^^^^---^^^^^----- - | | | - | | `&'_ Test` is not local + | ^^^^^---^^^^^^---- + | | | + | | `Test` is not local | `Uto` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/consts.rs:5:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:26:5 + --> $DIR/consts.rs:24:5 | LL | static A: u32 = { | ------------- move the `impl` block outside of this static `A` @@ -34,13 +29,12 @@ LL | impl Uto2 for Test {} | | `Test` is not local | `Uto2` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:34:5 + --> $DIR/consts.rs:32:5 | LL | const B: u32 = { | ------------ move the `impl` block outside of this constant `B` @@ -50,13 +44,12 @@ LL | impl Uto3 for Test {} | | `Test` is not local | `Uto3` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:45:5 + --> $DIR/consts.rs:43:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -65,11 +58,11 @@ LL | impl Test { | | | `Test` is not local | - = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:52:9 + --> $DIR/consts.rs:50:9 | LL | const { | ___________- @@ -84,11 +77,11 @@ LL | | 1 LL | | }; | |_____- move the `impl` block outside of this inline constant `` and up 2 bodies | - = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:61:9 + --> $DIR/consts.rs:59:9 | LL | const _: u32 = { | ------------ move the `impl` block outside of this constant `_` and up 2 bodies @@ -97,12 +90,12 @@ LL | impl Test { | | | `Test` is not local | - = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:74:9 + --> $DIR/consts.rs:72:9 | LL | let _a = || { | -- move the `impl` block outside of this closure `` and up 2 bodies @@ -112,12 +105,11 @@ LL | impl Uto9 for Test {} | | `Test` is not local | `Uto9` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:81:9 + --> $DIR/consts.rs:79:9 | LL | type A = [u32; { | ____________________- @@ -131,7 +123,6 @@ LL | | LL | | }]; | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.rs b/tests/ui/lint/non-local-defs/exhaustive-trait.rs index 79f8cc4620b97..40d2314460f86 100644 --- a/tests/ui/lint/non-local-defs/exhaustive-trait.rs +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![warn(non_local_definitions)] - struct Dog; fn main() { diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr index 24c9a6b4f01e2..c58ec12aaacaa 100644 --- a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:9:5 + --> $DIR/exhaustive-trait.rs:7:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -9,92 +9,84 @@ LL | impl PartialEq<()> for Dog { | | `Dog` is not local | `PartialEq` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/exhaustive-trait.rs:4:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:16:5 + --> $DIR/exhaustive-trait.rs:14:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl PartialEq<()> for &Dog { - | ^^^^^---------^^^^^^^^^---- - | | | - | | `&'_ Dog` is not local + | ^^^^^---------^^^^^^^^^^--- + | | | + | | `Dog` is not local | `PartialEq` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:23:5 + --> $DIR/exhaustive-trait.rs:21:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl PartialEq for () { - | ^^^^^---------^^^^^^^^^^-- - | | | - | | `()` is not local + | ^^^^^---------^---^^^^^^^^ + | | | + | | `Dog` is not local | `PartialEq` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:30:5 + --> $DIR/exhaustive-trait.rs:28:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl PartialEq<&Dog> for () { - | ^^^^^---------^^^^^^^^^^^-- - | | | - | | `()` is not local + | ^^^^^---------^^---^^^^^^^^ + | | | + | | `Dog` is not local | `PartialEq` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:37:5 + --> $DIR/exhaustive-trait.rs:35:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl PartialEq for &Dog { - | ^^^^^---------^^^^^^^^^^---- - | | | - | | `&'_ Dog` is not local + | ^^^^^---------^---^^^^^^^--- + | | | | + | | | `Dog` is not local + | | `Dog` is not local | `PartialEq` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive-trait.rs:44:5 + --> $DIR/exhaustive-trait.rs:42:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl PartialEq<&Dog> for &Dog { - | ^^^^^---------^^^^^^^^^^^---- - | | | - | | `&'_ Dog` is not local + | ^^^^^---------^^---^^^^^^^--- + | | | | + | | | `Dog` is not local + | | `Dog` is not local | `PartialEq` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue diff --git a/tests/ui/lint/non-local-defs/exhaustive.rs b/tests/ui/lint/non-local-defs/exhaustive.rs index f59a85c7ed94f..5036e427060fc 100644 --- a/tests/ui/lint/non-local-defs/exhaustive.rs +++ b/tests/ui/lint/non-local-defs/exhaustive.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![warn(non_local_definitions)] - use std::fmt::Display; trait Trait {} @@ -57,18 +55,13 @@ fn main() { struct InsideMain; + impl Trait for &InsideMain {} impl Trait for *mut InsideMain {} - //~^ WARN non-local `impl` definition impl Trait for *mut [InsideMain] {} - //~^ WARN non-local `impl` definition impl Trait for [InsideMain; 8] {} - //~^ WARN non-local `impl` definition impl Trait for (InsideMain,) {} - //~^ WARN non-local `impl` definition impl Trait for fn(InsideMain) -> () {} - //~^ WARN non-local `impl` definition impl Trait for fn() -> InsideMain {} - //~^ WARN non-local `impl` definition fn inside_inside() { impl Display for InsideMain { diff --git a/tests/ui/lint/non-local-defs/exhaustive.stderr b/tests/ui/lint/non-local-defs/exhaustive.stderr index 6d8c2ec0bc7cf..dd41b2206d842 100644 --- a/tests/ui/lint/non-local-defs/exhaustive.stderr +++ b/tests/ui/lint/non-local-defs/exhaustive.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:12:5 + --> $DIR/exhaustive.rs:10:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -8,16 +8,12 @@ LL | impl Test { | | | `Test` is not local | - = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/exhaustive.rs:4:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:17:5 + --> $DIR/exhaustive.rs:15:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -28,12 +24,11 @@ LL | impl Display for Test { | | `Test` is not local | `Display` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:24:5 + --> $DIR/exhaustive.rs:22:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -43,11 +38,11 @@ LL | impl dyn Trait {} | | | `Trait` is not local | - = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:27:5 + --> $DIR/exhaustive.rs:25:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` @@ -58,124 +53,116 @@ LL | impl Trait for Vec { } | | `Vec` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:30:5 + --> $DIR/exhaustive.rs:28:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl Trait for &dyn Trait {} - | ^^^^^-----^^^^^---------- - | | | - | | `&'_ dyn Trait` is not local + | ^^^^^-----^^^^^^^^^^----- + | | | + | | `Trait` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:33:5 + --> $DIR/exhaustive.rs:31:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl Trait for *mut Test {} - | ^^^^^-----^^^^^--------- - | | | - | | `*mut Test` is not local + | ^^^^^-----^^^^^^^^^^---- + | | | + | | `Test` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:36:5 + --> $DIR/exhaustive.rs:34:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl Trait for *mut [Test] {} - | ^^^^^-----^^^^^----------- - | | | - | | `*mut [Test]` is not local + | ^^^^^-----^^^^^^^^^^^----^ + | | | + | | `Test` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:39:5 + --> $DIR/exhaustive.rs:37:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl Trait for [Test; 8] {} - | ^^^^^-----^^^^^--------- - | | | - | | `[Test; 8]` is not local + | ^^^^^-----^^^^^^----^^^^ + | | | + | | `Test` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:42:5 + --> $DIR/exhaustive.rs:40:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl Trait for (Test,) {} - | ^^^^^-----^^^^^------- - | | | - | | `(Test,)` is not local + | ^^^^^-----^^^^^^----^^ + | | | + | | `Test` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:45:5 + --> $DIR/exhaustive.rs:43:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl Trait for fn(Test) -> () {} - | ^^^^^-----^^^^^-------------- - | | | - | | `fn(: Test) -> ()` is not local + | ^^^^^-----^^^^^^^^----^^^^^^^ + | | | + | | `Test` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:48:5 + --> $DIR/exhaustive.rs:46:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` ... LL | impl Trait for fn() -> Test {} - | ^^^^^-----^^^^^------------ - | | | - | | `fn() -> Test` is not local + | ^^^^^-----^^^^^^^^^^^^^---- + | | | + | | `Test` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:52:9 + --> $DIR/exhaustive.rs:50:9 | LL | let _a = || { | -- move the `impl` block outside of this closure `` and up 2 bodies @@ -185,139 +172,11 @@ LL | impl Trait for Test {} | | `Test` is not local | `Trait` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:60:5 - | -LL | impl Trait for *mut InsideMain {} - | ^^^^^-----^^^^^--------------- - | | | - | | `*mut InsideMain` is not local - | | help: remove `*mut ` to make the `impl` local - | `Trait` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:11:1 - | -LL | fn main() { - | ^^^^^^^^^ -... -LL | struct InsideMain; - | ----------------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:62:5 - | -LL | impl Trait for *mut [InsideMain] {} - | ^^^^^-----^^^^^----------------- - | | | - | | `*mut [InsideMain]` is not local - | `Trait` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:11:1 - | -LL | fn main() { - | ^^^^^^^^^ -... -LL | struct InsideMain; - | ----------------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:64:5 - | -LL | impl Trait for [InsideMain; 8] {} - | ^^^^^-----^^^^^--------------- - | | | - | | `[InsideMain; 8]` is not local - | `Trait` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:11:1 - | -LL | fn main() { - | ^^^^^^^^^ -... -LL | struct InsideMain; - | ----------------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:66:5 - | -LL | impl Trait for (InsideMain,) {} - | ^^^^^-----^^^^^------------- - | | | - | | `(InsideMain,)` is not local - | `Trait` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:11:1 - | -LL | fn main() { - | ^^^^^^^^^ -... -LL | struct InsideMain; - | ----------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:68:5 - | -LL | impl Trait for fn(InsideMain) -> () {} - | ^^^^^-----^^^^^-------------------- - | | | - | | `fn(: InsideMain) -> ()` is not local - | `Trait` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:11:1 - | -LL | fn main() { - | ^^^^^^^^^ -... -LL | struct InsideMain; - | ----------------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:70:5 - | -LL | impl Trait for fn() -> InsideMain {} - | ^^^^^-----^^^^^------------------ - | | | - | | `fn() -> InsideMain` is not local - | `Trait` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/exhaustive.rs:11:1 - | -LL | fn main() { - | ^^^^^^^^^ -... -LL | struct InsideMain; - | ----------------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:74:9 + --> $DIR/exhaustive.rs:67:9 | LL | fn inside_inside() { | ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies @@ -327,12 +186,11 @@ LL | impl Display for InsideMain { | | `InsideMain` is not local | `Display` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/exhaustive.rs:81:9 + --> $DIR/exhaustive.rs:74:9 | LL | fn inside_inside() { | ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies @@ -342,8 +200,8 @@ LL | impl InsideMain { | | | `InsideMain` is not local | - = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: 20 warnings emitted +warning: 14 warnings emitted diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.rs b/tests/ui/lint/non-local-defs/from-local-for-global.rs index 1d8f4845c2860..6654fcc4f23d7 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.rs +++ b/tests/ui/lint/non-local-defs/from-local-for-global.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![warn(non_local_definitions)] - struct Cat; struct Wrap(T); @@ -18,7 +16,6 @@ fn main() { struct Elephant; impl From>> for () { - //~^ WARN non-local `impl` definition fn from(_: Wrap>) -> Self { todo!() } @@ -32,7 +29,6 @@ impl StillNonLocal for &str {} fn only_global() { struct Foo; impl StillNonLocal for &Foo {} - //~^ WARN non-local `impl` definition } struct GlobalSameFunction; @@ -40,7 +36,6 @@ struct GlobalSameFunction; fn same_function() { struct Local1(GlobalSameFunction); impl From for GlobalSameFunction { - //~^ WARN non-local `impl` definition fn from(x: Local1) -> GlobalSameFunction { x.0 } @@ -48,7 +43,6 @@ fn same_function() { struct Local2(GlobalSameFunction); impl From for GlobalSameFunction { - //~^ WARN non-local `impl` definition fn from(x: Local2) -> GlobalSameFunction { x.0 } @@ -61,8 +55,6 @@ fn diff_function_1() { struct Local(GlobalDifferentFunction); impl From for GlobalDifferentFunction { - // FIXME(Urgau): Should warn but doesn't since we currently consider - // the other impl to be "global", but that's not the case for the type-system fn from(x: Local) -> GlobalDifferentFunction { x.0 } @@ -73,8 +65,6 @@ fn diff_function_2() { struct Local(GlobalDifferentFunction); impl From for GlobalDifferentFunction { - // FIXME(Urgau): Should warn but doesn't since we currently consider - // the other impl to be "global", but that's not the case for the type-system fn from(x: Local) -> GlobalDifferentFunction { x.0 } diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.stderr b/tests/ui/lint/non-local-defs/from-local-for-global.stderr index 04eba8435fc04..6839ebd2c8a3e 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.stderr +++ b/tests/ui/lint/non-local-defs/from-local-for-global.stderr @@ -1,104 +1,17 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:10:5 + --> $DIR/from-local-for-global.rs:8:5 | LL | fn main() { | --------- move the `impl` block outside of this function `main` LL | impl From for () { - | ^^^^^----^^^^^^^^^^-- - | | | - | | `()` is not local + | ^^^^^----^---^^^^^^^^ + | | | + | | `Cat` is not local | `From` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/from-local-for-global.rs:4:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:20:5 - | -LL | impl From>> for () { - | ^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^-- - | | | - | `From` is not local `()` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/from-local-for-global.rs:9:1 - | -LL | fn main() { - | ^^^^^^^^^ -... -LL | struct Elephant; - | --------------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:34:5 - | -LL | impl StillNonLocal for &Foo {} - | ^^^^^-------------^^^^^---- - | | | - | | `&'_ Foo` is not local - | | help: remove `&` to make the `impl` local - | `StillNonLocal` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `only_global` - --> $DIR/from-local-for-global.rs:32:1 - | -LL | fn only_global() { - | ^^^^^^^^^^^^^^^^ -LL | struct Foo; - | ---------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:42:5 - | -LL | impl From for GlobalSameFunction { - | ^^^^^----^^^^^^^^^^^^^------------------ - | | | - | | `GlobalSameFunction` is not local - | `From` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `same_function` - --> $DIR/from-local-for-global.rs:40:1 - | -LL | fn same_function() { - | ^^^^^^^^^^^^^^^^^^ -LL | struct Local1(GlobalSameFunction); - | ------------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/from-local-for-global.rs:50:5 - | -LL | impl From for GlobalSameFunction { - | ^^^^^----^^^^^^^^^^^^^------------------ - | | | - | | `GlobalSameFunction` is not local - | `From` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `same_function` - --> $DIR/from-local-for-global.rs:40:1 - | -LL | fn same_function() { - | ^^^^^^^^^^^^^^^^^^ -... -LL | struct Local2(GlobalSameFunction); - | ------------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: `#[warn(non_local_definitions)]` on by default -warning: 5 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/lint/non-local-defs/generics.rs b/tests/ui/lint/non-local-defs/generics.rs index 13e392c510c64..381b3caacb6b5 100644 --- a/tests/ui/lint/non-local-defs/generics.rs +++ b/tests/ui/lint/non-local-defs/generics.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![warn(non_local_definitions)] - trait Global {} fn main() { @@ -32,7 +30,6 @@ fn fun() { #[derive(Debug)] struct OwO; impl Default for UwU { - //~^ WARN non-local `impl` definition fn default() -> Self { UwU(OwO) } @@ -43,7 +40,6 @@ fn meow() { #[derive(Debug)] struct Cat; impl AsRef for () { - //~^ WARN non-local `impl` definition fn as_ref(&self) -> &Cat { &Cat } } } @@ -54,7 +50,6 @@ fn fun2() { #[derive(Debug, Default)] struct B; impl PartialEq for G { - //~^ WARN non-local `impl` definition fn eq(&self, _: &B) -> bool { true } @@ -69,14 +64,12 @@ fn rawr() { struct Lion; impl From>> for () { - //~^ WARN non-local `impl` definition fn from(_: Wrap>) -> Self { todo!() } } impl From<()> for Wrap { - //~^ WARN non-local `impl` definition fn from(_: ()) -> Self { todo!() } diff --git a/tests/ui/lint/non-local-defs/generics.stderr b/tests/ui/lint/non-local-defs/generics.stderr index 35366ed8ecf94..aefe8921fe2c7 100644 --- a/tests/ui/lint/non-local-defs/generics.stderr +++ b/tests/ui/lint/non-local-defs/generics.stderr @@ -1,165 +1,47 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:11:5 + --> $DIR/generics.rs:9:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Global for Vec { } | ^^^^^^^^^^^^^^^------^^^^^---^^^ | | | | | `Vec` is not local | `Global` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/generics.rs:8:1 - | -LL | fn main() { - | ^^^^^^^^^ -LL | trait Local {}; - | ----------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/generics.rs:4:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:22:5 + --> $DIR/generics.rs:20:5 | +LL | fn bad() { + | -------- move the `impl` block outside of this function `bad` +LL | struct Local; LL | impl Uto7 for Test where Local: std::any::Any {} | ^^^^^----^^^^^---- | | | | | `Test` is not local | `Uto7` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `bad` - --> $DIR/generics.rs:20:1 - | -LL | fn bad() { - | ^^^^^^^^ -LL | struct Local; - | ------------ may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:25:5 + --> $DIR/generics.rs:23:5 | LL | fn bad() { | -------- move the `impl` block outside of this function `bad` ... LL | impl Uto8 for T {} - | ^^^^^^^^----^^^^^- - | | | - | | `T` is not local + | ^^^^^^^^----^^^^^^ + | | | `Uto8` is not local | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:34:5 - | -LL | impl Default for UwU { - | ^^^^^-------^^^^^---^^^^^ - | | | - | | `UwU` is not local - | `Default` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `fun` - --> $DIR/generics.rs:31:1 - | -LL | fn fun() { - | ^^^^^^^^ -LL | #[derive(Debug)] -LL | struct OwO; - | ---------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:45:5 - | -LL | impl AsRef for () { - | ^^^^^-----^^^^^^^^^^-- - | | | - | | `()` is not local - | `AsRef` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `meow` - --> $DIR/generics.rs:42:1 - | -LL | fn meow() { - | ^^^^^^^^^ -LL | #[derive(Debug)] -LL | struct Cat; - | ---------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:56:5 - | -LL | impl PartialEq for G { - | ^^^^^---------^^^^^^^^- - | | | - | | `G` is not local - | `PartialEq` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `fun2` - --> $DIR/generics.rs:53:1 - | -LL | fn fun2() { - | ^^^^^^^^^ -LL | #[derive(Debug, Default)] -LL | struct B; - | -------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:71:5 - | -LL | impl From>> for () { - | ^^^^^----^^^^^^^^^^^^^^^^^^^^^^^-- - | | | - | `From` is not local `()` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `rawr` - --> $DIR/generics.rs:68:1 - | -LL | fn rawr() { - | ^^^^^^^^^ -LL | struct Lion; - | ----------- may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/generics.rs:78:5 - | -LL | impl From<()> for Wrap { - | ^^^^^----^^^^^^^^^----^^^^^^ - | | | - | | `Wrap` is not local - | `From` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `rawr` - --> $DIR/generics.rs:68:1 - | -LL | fn rawr() { - | ^^^^^^^^^ -LL | struct Lion; - | ----------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: 8 warnings emitted +warning: 3 warnings emitted diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.rs b/tests/ui/lint/non-local-defs/inside-macro_rules.rs index 744a1f7a6f1ab..9f21cc89852e2 100644 --- a/tests/ui/lint/non-local-defs/inside-macro_rules.rs +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![warn(non_local_definitions)] - macro_rules! m { () => { trait MacroTrait {} diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr index 89835372c8a53..faab6aea2b318 100644 --- a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/inside-macro_rules.rs:11:13 + --> $DIR/inside-macro_rules.rs:9:13 | LL | fn my_func() { | ------------ move the `impl` block outside of this function `my_func` @@ -13,14 +13,9 @@ LL | m!(); | ---- in this macro invocation | = note: the macro `m` defines the non-local `impl`, and may need to be changed - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/inside-macro_rules.rs:4:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 1 warning emitted diff --git a/tests/ui/lint/non-local-defs/local.rs b/tests/ui/lint/non-local-defs/local.rs index e9dbff1300f28..166ee88c0210c 100644 --- a/tests/ui/lint/non-local-defs/local.rs +++ b/tests/ui/lint/non-local-defs/local.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![warn(non_local_definitions)] - use std::fmt::Debug; trait GlobalTrait {} diff --git a/tests/ui/lint/non-local-defs/macro_rules.rs b/tests/ui/lint/non-local-defs/macro_rules.rs index 20672cf0a3225..ed30a24903d01 100644 --- a/tests/ui/lint/non-local-defs/macro_rules.rs +++ b/tests/ui/lint/non-local-defs/macro_rules.rs @@ -3,8 +3,6 @@ //@ aux-build:non_local_macro.rs //@ rustc-env:CARGO_CRATE_NAME=non_local_def -#![warn(non_local_definitions)] - extern crate non_local_macro; const B: u32 = { diff --git a/tests/ui/lint/non-local-defs/macro_rules.stderr b/tests/ui/lint/non-local-defs/macro_rules.stderr index f9995bf82183c..4e86fc7b987e6 100644 --- a/tests/ui/lint/non-local-defs/macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/macro_rules.stderr @@ -1,5 +1,5 @@ warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/macro_rules.rs:12:5 + --> $DIR/macro_rules.rs:10:5 | LL | macro_rules! m0 { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,14 +7,10 @@ LL | macro_rules! m0 { () => { } }; = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/macro_rules.rs:6:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/macro_rules.rs:18:1 + --> $DIR/macro_rules.rs:16:1 | LL | non_local_macro::non_local_macro_rules!(my_macro); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +22,7 @@ LL | non_local_macro::non_local_macro_rules!(my_macro); = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/macro_rules.rs:23:5 + --> $DIR/macro_rules.rs:21:5 | LL | macro_rules! m { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +32,7 @@ LL | macro_rules! m { () => { } }; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module - --> $DIR/macro_rules.rs:31:13 + --> $DIR/macro_rules.rs:29:13 | LL | macro_rules! m2 { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-local-defs/suggest-moving-inner.rs b/tests/ui/lint/non-local-defs/ref-complex.rs similarity index 76% rename from tests/ui/lint/non-local-defs/suggest-moving-inner.rs rename to tests/ui/lint/non-local-defs/ref-complex.rs index 9360ace4d805b..ce4e0a3dc0a19 100644 --- a/tests/ui/lint/non-local-defs/suggest-moving-inner.rs +++ b/tests/ui/lint/non-local-defs/ref-complex.rs @@ -1,7 +1,5 @@ //@ check-pass -#![warn(non_local_definitions)] - trait Trait {} fn main() { @@ -12,7 +10,6 @@ fn main() { trait HasFoo {} impl Trait for &Vec> - //~^ WARN non-local `impl` definition where T: HasFoo {} diff --git a/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr b/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr deleted file mode 100644 index a214415316f84..0000000000000 --- a/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr +++ /dev/null @@ -1,33 +0,0 @@ -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/suggest-moving-inner.rs:14:5 - | -LL | impl Trait for &Vec> - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^---------------------------------- - | | | - | | `&'_ Vec>` is not local - | `Trait` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/suggest-moving-inner.rs:7:1 - | -LL | fn main() { - | ^^^^^^^^^ -LL | mod below { -LL | pub struct Type(T); - | ------------------ may need to be moved as well -LL | } -LL | struct InsideMain; - | ----------------- may need to be moved as well -LL | trait HasFoo {} - | ------------ may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/suggest-moving-inner.rs:3:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ - -warning: 1 warning emitted - diff --git a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.rs b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.rs index b726398bf9c9a..6e8014f10f85a 100644 --- a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.rs +++ b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.rs @@ -3,8 +3,6 @@ // https://github.com/rust-lang/rust/issues/123573#issue-2229428739 -#![warn(non_local_definitions)] - pub trait Test {} impl<'a, T: 'a> Test for &[T] where &'a T: Test {} @@ -12,5 +10,4 @@ impl<'a, T: 'a> Test for &[T] where &'a T: Test {} fn main() { struct Local {} impl Test for &Local {} - //~^ WARN non-local `impl` definition } diff --git a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr deleted file mode 100644 index 2eb71cecacaaf..0000000000000 --- a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr +++ /dev/null @@ -1,28 +0,0 @@ -warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/trait-solver-overflow-123573.rs:14:5 - | -LL | impl Test for &Local {} - | ^^^^^----^^^^^------ - | | | - | | `&'_ Local` is not local - | | help: remove `&` to make the `impl` local - | `Test` is not local - | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type - = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` -help: move the `impl` block outside of this function `main` - --> $DIR/trait-solver-overflow-123573.rs:12:1 - | -LL | fn main() { - | ^^^^^^^^^ -LL | struct Local {} - | ------------ may need to be moved as well - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/trait-solver-overflow-123573.rs:6:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ - -warning: 1 warning emitted - diff --git a/tests/ui/lint/non-local-defs/weird-exprs.rs b/tests/ui/lint/non-local-defs/weird-exprs.rs index fbf1fd941eecb..1d9cecea0c971 100644 --- a/tests/ui/lint/non-local-defs/weird-exprs.rs +++ b/tests/ui/lint/non-local-defs/weird-exprs.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![warn(non_local_definitions)] - trait Uto {} struct Test; diff --git a/tests/ui/lint/non-local-defs/weird-exprs.stderr b/tests/ui/lint/non-local-defs/weird-exprs.stderr index 49aba904ebb0e..f6ce063929e8f 100644 --- a/tests/ui/lint/non-local-defs/weird-exprs.stderr +++ b/tests/ui/lint/non-local-defs/weird-exprs.stderr @@ -1,29 +1,24 @@ warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:10:5 + --> $DIR/weird-exprs.rs:8:5 | LL | type A = [u32; { | ________________- LL | | impl Uto for *mut Test {} - | | ^^^^^---^^^^^--------- - | | | | - | | | `*mut Test` is not local + | | ^^^^^---^^^^^^^^^^---- + | | | | + | | | `Test` is not local | | `Uto` is not local LL | | ... | LL | | }]; | |_- move the `impl` block outside of this constant expression `` | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/weird-exprs.rs:4:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:18:9 + --> $DIR/weird-exprs.rs:16:9 | LL | Discr = { | _____________- @@ -37,12 +32,11 @@ LL | | LL | | } | |_____- move the `impl` block outside of this constant expression `` | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:27:9 + --> $DIR/weird-exprs.rs:25:9 | LL | let _array = [0i32; { | _________________________- @@ -57,63 +51,61 @@ LL | | 1 LL | | }]; | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:36:9 + --> $DIR/weird-exprs.rs:34:9 | LL | type A = [u32; { | ____________________- LL | | impl Uto for &Test {} - | | ^^^^^---^^^^^----- - | | | | - | | | `&'_ Test` is not local + | | ^^^^^---^^^^^^---- + | | | | + | | | `Test` is not local | | `Uto` is not local LL | | ... | LL | | }]; | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:43:9 + --> $DIR/weird-exprs.rs:41:9 | LL | fn a(_: [u32; { | ___________________- LL | | impl Uto for &(Test,) {} - | | ^^^^^---^^^^^-------- - | | | | - | | | `&'_ (Test,)` is not local + | | ^^^^^---^^^^^^^----^^ + | | | | + | | | `Test` is not local | | `Uto` is not local LL | | ... | LL | | }]) {} | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/weird-exprs.rs:50:9 + --> $DIR/weird-exprs.rs:48:9 | LL | fn b() -> [u32; { | _____________________- LL | | impl Uto for &(Test,Test) {} - | | ^^^^^---^^^^^------------ - | | | | - | | | `&'_ (Test, Test)` is not local + | | ^^^^^---^^^^^^^----^----^ + | | | | | + | | | | `Test` is not local + | | | `Test` is not local | | `Uto` is not local LL | | ... | LL | | }] { todo!() } | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs deleted file mode 100644 index f8aad88eceecf..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -//@ check-pass -#![crate_name = "NonSnakeCase"] - -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs deleted file mode 100644 index c077d81e9e542..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -//@ compile-flags: --crate-name NonSnakeCase -//@ check-pass - -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs deleted file mode 100644 index 278f7cfd3ee48..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -//@ check-pass -#![crate_type = "bin"] -#![crate_name = "NonSnakeCase"] - -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs deleted file mode 100644 index 781c6794fc2aa..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "cdylib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs deleted file mode 100644 index 3f65295f06839..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "dylib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs deleted file mode 100644 index 20c58e66aa626..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "lib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs deleted file mode 100644 index f0f2fa4393ee8..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "proc-macro"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr deleted file mode 100644 index e0091057bc971..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-proc-macro.rs:3:18 - | -LL | #![crate_name = "NonSnakeCase"] - | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-proc-macro.rs:5:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs deleted file mode 100644 index 1a558def3d02e..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "rlib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs deleted file mode 100644 index 2ec53c15eb804..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ only-x86_64-unknown-linux-gnu -#![crate_type = "staticlib"] -#![crate_name = "NonSnakeCase"] -//~^ ERROR crate `NonSnakeCase` should have a snake case name -#![deny(non_snake_case)] - -fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr deleted file mode 100644 index 4ee6d5bd4d46f..0000000000000 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-staticlib.rs:3:18 - | -LL | #![crate_name = "NonSnakeCase"] - | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` - | -note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-staticlib.rs:5:9 - | -LL | #![deny(non_snake_case)] - | ^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr similarity index 77% rename from tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr index a68c0e832b88c..9bccb270627d8 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-lib.rs:3:18 + --> $DIR/lint-non-snake-case-crate.rs:25:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-lib.rs:5:9 + --> $DIR/lint-non-snake-case-crate.rs:27:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr similarity index 77% rename from tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr index 6e9d54bd5bcde..9bccb270627d8 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-rlib.rs:3:18 + --> $DIR/lint-non-snake-case-crate.rs:25:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-rlib.rs:5:9 + --> $DIR/lint-non-snake-case-crate.rs:27:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr similarity index 77% rename from tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr index 4ee1a9cb3ddd5..9bccb270627d8 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-dylib.rs:3:18 + --> $DIR/lint-non-snake-case-crate.rs:25:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-dylib.rs:5:9 + --> $DIR/lint-non-snake-case-crate.rs:27:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr similarity index 76% rename from tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr index f9167aa8df349..9bccb270627d8 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate-cdylib.rs:3:18 + --> $DIR/lint-non-snake-case-crate.rs:25:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate-cdylib.rs:5:9 + --> $DIR/lint-non-snake-case-crate.rs:27:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr new file mode 100644 index 0000000000000..9bccb270627d8 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr @@ -0,0 +1,14 @@ +error: crate `NonSnakeCase` should have a snake case name + --> $DIR/lint-non-snake-case-crate.rs:25:18 + | +LL | #![crate_name = "NonSnakeCase"] + | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-crate.rs:27:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs new file mode 100644 index 0000000000000..57604d99a07b1 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs @@ -0,0 +1,29 @@ +//! Don't lint on binary crate with non-snake-case names. +//! +//! See . + +//@ revisions: bin_ cdylib_ dylib_ lib_ proc_macro_ rlib_ staticlib_ + +// Should not fire on binary crates. +//@[bin_] compile-flags: --crate-type=bin +//@[bin_] check-pass + +// But should fire on non-binary crates. + +//@[cdylib_] ignore-musl (dylibs are not supported) +//@[dylib_] ignore-musl (dylibs are not supported) +//@[dylib_] ignore-wasm (dylib is not supported) +//@[proc_macro_] ignore-wasm (dylib is not supported) + +//@[cdylib_] compile-flags: --crate-type=cdylib +//@[dylib_] compile-flags: --crate-type=dylib +//@[lib_] compile-flags: --crate-type=lib +//@[proc_macro_] compile-flags: --crate-type=proc-macro +//@[rlib_] compile-flags: --crate-type=rlib +//@[staticlib_] compile-flags: --crate-type=staticlib + +#![crate_name = "NonSnakeCase"] +//[cdylib_,dylib_,lib_,proc_macro_,rlib_,staticlib_]~^ ERROR crate `NonSnakeCase` should have a snake case name +#![deny(non_snake_case)] + +fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr new file mode 100644 index 0000000000000..9bccb270627d8 --- /dev/null +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr @@ -0,0 +1,14 @@ +error: crate `NonSnakeCase` should have a snake case name + --> $DIR/lint-non-snake-case-crate.rs:25:18 + | +LL | #![crate_name = "NonSnakeCase"] + | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` + | +note: the lint level is defined here + --> $DIR/lint-non-snake-case-crate.rs:27:9 + | +LL | #![deny(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs index c99317d6aa88f..7d5a3a43ecf0c 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs @@ -37,6 +37,8 @@ mod rustc_warn { #[expect(invalid_nan_comparisons)] //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] + //~| WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] + //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` let _b = x == 5; } } diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr index cd6dae0d761f1..8f25b90b031a7 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr @@ -12,5 +12,13 @@ warning: this lint expectation is unfulfilled LL | #[expect(invalid_nan_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: 2 warnings emitted +warning: this lint expectation is unfulfilled + --> $DIR/expect_tool_lint_rfc_2383.rs:38:18 + | +LL | #[expect(invalid_nan_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 3 warnings emitted diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs index 413833ba351b8..ee715bfd5a398 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs @@ -16,15 +16,22 @@ pub fn normal_test_fn() { #[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")] //~^ WARNING this lint expectation is unfulfilled + //~| WARNING this lint expectation is unfulfilled //~| NOTE this expectation will create a diagnostic with the default lint level + //~| NOTE this expectation will create a diagnostic with the default lint level + //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` let mut v = vec![1, 1, 2, 3, 5]; v.sort(); // Check that lint lists including `unfulfilled_lint_expectations` are also handled correctly #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")] //~^ WARNING this lint expectation is unfulfilled + //~| WARNING this lint expectation is unfulfilled + //~| NOTE the expectation for `unused` should be fulfilled //~| NOTE the expectation for `unused` should be fulfilled //~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + //~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` let value = "I'm unused"; } diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr index bd2df362a77ac..ac126804e0e27 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr @@ -26,13 +26,32 @@ LL | #[expect(unused_mut, reason = "this expectation will create a diagnosti = note: this expectation will create a diagnostic with the default lint level warning: this lint expectation is unfulfilled - --> $DIR/expect_unfulfilled_expectation.rs:24:22 + --> $DIR/expect_unfulfilled_expectation.rs:17:14 + | +LL | #[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")] + | ^^^^^^^^^^ + | + = note: this expectation will create a diagnostic with the default lint level + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: this lint expectation is unfulfilled + --> $DIR/expect_unfulfilled_expectation.rs:27:22 + | +LL | #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the expectation for `unused` should be fulfilled + = note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + +warning: this lint expectation is unfulfilled + --> $DIR/expect_unfulfilled_expectation.rs:27:22 | LL | #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the expectation for `unused` should be fulfilled = note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -warning: 4 warnings emitted +warning: 6 warnings emitted diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_warnings.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_warnings.rs new file mode 100644 index 0000000000000..35d9e02d3c3d9 --- /dev/null +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_warnings.rs @@ -0,0 +1,6 @@ +//@ check-pass + +#![expect(warnings)] + +#[expect(unused)] +fn main() {} diff --git a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr index 29e579464c8de..eaf9edd8e8fee 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr @@ -1,3 +1,11 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/force_warn_expected_lints_fulfilled.rs:8:5 + | +LL | while true { + | ^^^^^^^^^^ help: use `loop` + | + = note: requested on the command line with `--force-warn while-true` + warning: unused variable: `x` --> $DIR/force_warn_expected_lints_fulfilled.rs:18:9 | @@ -28,13 +36,5 @@ warning: unused variable: `this_should_fulfill_the_expectation` LL | let this_should_fulfill_the_expectation = "The `#[allow]` has no power here"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_fulfill_the_expectation` -warning: denote infinite loops with `loop { ... }` - --> $DIR/force_warn_expected_lints_fulfilled.rs:8:5 - | -LL | while true { - | ^^^^^^^^^^ help: use `loop` - | - = note: requested on the command line with `--force-warn while-true` - warning: 5 warnings emitted diff --git a/tests/ui/lint/rust-cold-fn-accept-improper-ctypes.rs b/tests/ui/lint/rust-cold-fn-accept-improper-ctypes.rs new file mode 100644 index 0000000000000..dc929e14527f4 --- /dev/null +++ b/tests/ui/lint/rust-cold-fn-accept-improper-ctypes.rs @@ -0,0 +1,14 @@ +//@ check-pass +#![feature(rust_cold_cc)] + +// extern "rust-cold" is a "Rust" ABI so we accept `repr(Rust)` types as arg/ret without warnings. + +pub extern "rust-cold" fn f(_: ()) -> Result<(), ()> { + Ok(()) +} + +extern "rust-cold" { + pub fn g(_: ()) -> Result<(), ()>; +} + +fn main() {} diff --git a/tests/ui/lint/static-mut-refs.e2021.stderr b/tests/ui/lint/static-mut-refs.e2021.stderr new file mode 100644 index 0000000000000..09f560652e7bf --- /dev/null +++ b/tests/ui/lint/static-mut-refs.e2021.stderr @@ -0,0 +1,143 @@ +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:39:18 + | +LL | let _y = &X; + | ^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = note: `#[warn(static_mut_refs)]` on by default +help: use `&raw const` instead to create a raw pointer + | +LL | let _y = &raw const X; + | ~~~~~~~~~~ + +warning: creating a mutable reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:43:18 + | +LL | let _y = &mut X; + | ^^^^^^ mutable reference to mutable static + | + = note: for more information, see + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives +help: use `&raw mut` instead to create a raw pointer + | +LL | let _y = &raw mut X; + | ~~~~~~~~ + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:51:22 + | +LL | let ref _a = X; + | ^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:55:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | let (_b, _c) = (&raw const X, &Y); + | ~~~~~~~~~~ + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:55:29 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, &raw const Y); + | ~~~~~~~~~~ + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:61:13 + | +LL | foo(&X); + | ^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | foo(&raw const X); + | ~~~~~~~~~~ + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:67:17 + | +LL | let _ = Z.len(); + | ^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:73:33 + | +LL | let _ = format!("{:?}", Z); + | ^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:77:18 + | +LL | let _v = &A.value; + | ^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | let _v = &raw const A.value; + | ~~~~~~~~~~ + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:81:18 + | +LL | let _s = &A.s.value; + | ^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | let _s = &raw const A.s.value; + | ~~~~~~~~~~ + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:85:22 + | +LL | let ref _v = A.value; + | ^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: creating a mutable reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:15:14 + | +LL | &mut ($x.0) + | ^^^^^^ mutable reference to mutable static +... +LL | let _x = bar!(FOO); + | --------- in this macro invocation + | + = note: for more information, see + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives + = note: this warning originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 12 warnings emitted + diff --git a/tests/ui/lint/static-mut-refs.e2024.stderr b/tests/ui/lint/static-mut-refs.e2024.stderr new file mode 100644 index 0000000000000..2d2a4f7afe00f --- /dev/null +++ b/tests/ui/lint/static-mut-refs.e2024.stderr @@ -0,0 +1,143 @@ +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:39:18 + | +LL | let _y = &X; + | ^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = note: `#[deny(static_mut_refs)]` on by default +help: use `&raw const` instead to create a raw pointer + | +LL | let _y = &raw const X; + | ~~~~~~~~~~ + +error: creating a mutable reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:43:18 + | +LL | let _y = &mut X; + | ^^^^^^ mutable reference to mutable static + | + = note: for more information, see + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives +help: use `&raw mut` instead to create a raw pointer + | +LL | let _y = &raw mut X; + | ~~~~~~~~ + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:51:22 + | +LL | let ref _a = X; + | ^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:55:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | let (_b, _c) = (&raw const X, &Y); + | ~~~~~~~~~~ + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:55:29 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, &raw const Y); + | ~~~~~~~~~~ + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:61:13 + | +LL | foo(&X); + | ^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | foo(&raw const X); + | ~~~~~~~~~~ + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:67:17 + | +LL | let _ = Z.len(); + | ^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:73:33 + | +LL | let _ = format!("{:?}", Z); + | ^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:77:18 + | +LL | let _v = &A.value; + | ^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | let _v = &raw const A.value; + | ~~~~~~~~~~ + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:81:18 + | +LL | let _s = &A.s.value; + | ^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer + | +LL | let _s = &raw const A.s.value; + | ~~~~~~~~~~ + +error: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:85:22 + | +LL | let ref _v = A.value; + | ^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +error: creating a mutable reference to mutable static is discouraged + --> $DIR/static-mut-refs.rs:15:14 + | +LL | &mut ($x.0) + | ^^^^^^ mutable reference to mutable static +... +LL | let _x = bar!(FOO); + | --------- in this macro invocation + | + = note: for more information, see + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives + = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 12 previous errors + diff --git a/tests/ui/lint/static-mut-refs.rs b/tests/ui/lint/static-mut-refs.rs new file mode 100644 index 0000000000000..3d84d7dbf40de --- /dev/null +++ b/tests/ui/lint/static-mut-refs.rs @@ -0,0 +1,95 @@ +// Test `static_mut_refs` lint. + +//@ revisions: e2021 e2024 + +//@ [e2021] edition:2021 +//@ [e2021] run-pass + +//@ [e2024] edition:2024 +//@ [e2024] compile-flags: -Zunstable-options + +static mut FOO: (u32, u32) = (1, 2); + +macro_rules! bar { + ($x:expr) => { + &mut ($x.0) + //[e2021]~^ WARN creating a mutable reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR creating a mutable reference to mutable static is discouraged [static_mut_refs] + }; +} + +static mut STATIC: i64 = 1; + +fn main() { + static mut X: i32 = 1; + + static mut Y: i32 = 1; + + struct TheStruct { + pub value: i32, + } + struct MyStruct { + pub value: i32, + pub s: TheStruct, + } + + static mut A: MyStruct = MyStruct { value: 1, s: TheStruct { value: 2 } }; + + unsafe { + let _y = &X; + //[e2021]~^ WARN shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] + + let _y = &mut X; + //[e2021]~^ WARN mutable reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR mutable reference to mutable static is discouraged [static_mut_refs] + + let _z = &raw mut X; + + let _p = &raw const X; + + let ref _a = X; + //[e2021]~^ WARN shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] + + let (_b, _c) = (&X, &Y); + //[e2021]~^ WARN shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] + //[e2021]~^^^ WARN shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] + + foo(&X); + //[e2021]~^ WARN shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] + + static mut Z: &[i32; 3] = &[0, 1, 2]; + + let _ = Z.len(); + //[e2021]~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR creating a shared reference to mutable static is discouraged [static_mut_refs] + + let _ = Z[0]; + + let _ = format!("{:?}", Z); + //[e2021]~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR creating a shared reference to mutable static is discouraged [static_mut_refs] + + let _v = &A.value; + //[e2021]~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR creating a shared reference to mutable static is discouraged [static_mut_refs] + + let _s = &A.s.value; + //[e2021]~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR creating a shared reference to mutable static is discouraged [static_mut_refs] + + let ref _v = A.value; + //[e2021]~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] + //[e2024]~^^ ERROR creating a shared reference to mutable static is discouraged [static_mut_refs] + + let _x = bar!(FOO); + + STATIC += 1; + } +} + +fn foo<'a>(_x: &'a i32) {} diff --git a/tests/ui/lint/unqualified_local_imports.rs b/tests/ui/lint/unqualified_local_imports.rs new file mode 100644 index 0000000000000..9de71471342dc --- /dev/null +++ b/tests/ui/lint/unqualified_local_imports.rs @@ -0,0 +1,38 @@ +//@compile-flags: --edition 2018 +#![feature(unqualified_local_imports)] +#![deny(unqualified_local_imports)] + +mod localmod { + pub struct S; + pub struct T; +} + +// Not a local import, so no lint. +use std::cell::Cell; + +// Implicitly local import, gets lint. +use localmod::S; //~ERROR: unqualified + +// Explicitly local import, no lint. +use self::localmod::T; + +macro_rules! mymacro { + ($cond:expr) => { + if !$cond { + continue; + } + }; +} +// Macro import: no lint, as there is no other way to write it. +pub(crate) use mymacro; + +#[allow(unused)] +enum LocalEnum { + VarA, + VarB, +} + +fn main() { + // Import in a function, no lint. + use LocalEnum::*; +} diff --git a/tests/ui/lint/unqualified_local_imports.stderr b/tests/ui/lint/unqualified_local_imports.stderr new file mode 100644 index 0000000000000..81d12f55949e3 --- /dev/null +++ b/tests/ui/lint/unqualified_local_imports.stderr @@ -0,0 +1,14 @@ +error: `use` of a local item without leading `self::`, `super::`, or `crate::` + --> $DIR/unqualified_local_imports.rs:14:5 + | +LL | use localmod::S; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unqualified_local_imports.rs:3:9 + | +LL | #![deny(unqualified_local_imports)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lto/lto-still-runs-thread-dtors.rs b/tests/ui/lto/lto-still-runs-thread-dtors.rs index 504923a93c279..900368496ebde 100644 --- a/tests/ui/lto/lto-still-runs-thread-dtors.rs +++ b/tests/ui/lto/lto-still-runs-thread-dtors.rs @@ -3,6 +3,9 @@ //@ no-prefer-dynamic //@ needs-threads +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] + use std::thread; static mut HIT: usize = 0; diff --git a/tests/ui/macros/auxiliary/metavar_2018.rs b/tests/ui/macros/auxiliary/metavar_2018.rs new file mode 100644 index 0000000000000..7e8523a9edf1b --- /dev/null +++ b/tests/ui/macros/auxiliary/metavar_2018.rs @@ -0,0 +1,14 @@ +//@ edition: 2018 +#[macro_export] +macro_rules! make_matcher { + ($name:ident, $fragment_type:ident, $d:tt) => { + #[macro_export] + macro_rules! $name { + ($d _:$fragment_type) => { true }; + (const { 0 }) => { false }; + (A | B) => { false }; + } + }; +} +make_matcher!(is_expr_from_2018, expr, $); +make_matcher!(is_pat_from_2018, pat, $); diff --git a/tests/ui/macros/break-last-token-twice.rs b/tests/ui/macros/break-last-token-twice.rs new file mode 100644 index 0000000000000..791f349ab38df --- /dev/null +++ b/tests/ui/macros/break-last-token-twice.rs @@ -0,0 +1,16 @@ +//@ check-pass + +macro_rules! m { + (static $name:ident: $t:ty = $e:expr) => { + let $name: $t = $e; + } +} + +fn main() { + m! { + // Tricky: the trailing `>>=` token here is broken twice: + // - into `>` and `>=` + // - then the `>=` is broken into `>` and `=` + static _x: Vec>= vec![] + } +} diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs new file mode 100644 index 0000000000000..3eec1208b89ae --- /dev/null +++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs @@ -0,0 +1,38 @@ +//@ compile-flags: --edition=2024 -Z unstable-options +//@ aux-build: metavar_2018.rs +//@ known-bug: #130484 +//@ run-pass + +// This test captures the behavior of macro-generating-macros with fragment +// specifiers across edition boundaries. + +#![feature(expr_fragment_specifier_2024)] +#![feature(macro_metavar_expr)] +#![allow(incomplete_features)] + +extern crate metavar_2018; + +use metavar_2018::{is_expr_from_2018, is_pat_from_2018, make_matcher}; + +make_matcher!(is_expr_from_2024, expr, $); +make_matcher!(is_pat_from_2024, pat, $); + +fn main() { + // Check expr + let from_2018 = is_expr_from_2018!(const { 0 }); + dbg!(from_2018); + let from_2024 = is_expr_from_2024!(const { 0 }); + dbg!(from_2024); + + assert!(!from_2018); + assert!(!from_2024); // from_2024 will be true once #130484 is fixed + + // Check pat + let from_2018 = is_pat_from_2018!(A | B); + dbg!(from_2018); + let from_2024 = is_pat_from_2024!(A | B); + dbg!(from_2024); + + assert!(!from_2018); + assert!(!from_2024); // from_2024 will be true once #130484 is fixed +} diff --git a/tests/ui/methods/method-self-arg-trait.rs b/tests/ui/methods/method-self-arg-trait.rs index 63594380753ea..ccffe02328bbf 100644 --- a/tests/ui/methods/method-self-arg-trait.rs +++ b/tests/ui/methods/method-self-arg-trait.rs @@ -1,6 +1,9 @@ //@ run-pass // Test method calls with self as an argument +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + static mut COUNT: u64 = 1; #[derive(Copy, Clone)] diff --git a/tests/ui/methods/method-self-arg.rs b/tests/ui/methods/method-self-arg.rs index d26b9663fd027..2e058ee1077c6 100644 --- a/tests/ui/methods/method-self-arg.rs +++ b/tests/ui/methods/method-self-arg.rs @@ -1,6 +1,9 @@ //@ run-pass // Test method calls with self as an argument +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + static mut COUNT: usize = 1; #[derive(Copy, Clone)] diff --git a/tests/ui/methods/probe-error-on-infinite-deref.rs b/tests/ui/methods/probe-error-on-infinite-deref.rs new file mode 100644 index 0000000000000..85c1c0c09c13e --- /dev/null +++ b/tests/ui/methods/probe-error-on-infinite-deref.rs @@ -0,0 +1,16 @@ +use std::ops::Deref; + +// Make sure that method probe error reporting doesn't get too tangled up +// on this infinite deref impl. See #130224. + +struct Wrap(T); +impl Deref for Wrap { + type Target = Wrap>; + fn deref(&self) -> &Wrap> { todo!() } +} + +fn main() { + Wrap(1).lmao(); + //~^ ERROR reached the recursion limit + //~| ERROR no method named `lmao` +} diff --git a/tests/ui/methods/probe-error-on-infinite-deref.stderr b/tests/ui/methods/probe-error-on-infinite-deref.stderr new file mode 100644 index 0000000000000..57a9ca2eaa80f --- /dev/null +++ b/tests/ui/methods/probe-error-on-infinite-deref.stderr @@ -0,0 +1,21 @@ +error[E0055]: reached the recursion limit while auto-dereferencing `Wrap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + --> $DIR/probe-error-on-infinite-deref.rs:13:13 + | +LL | Wrap(1).lmao(); + | ^^^^ deref recursion limit reached + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`probe_error_on_infinite_deref`) + +error[E0599]: no method named `lmao` found for struct `Wrap<{integer}>` in the current scope + --> $DIR/probe-error-on-infinite-deref.rs:13:13 + | +LL | struct Wrap(T); + | -------------- method `lmao` not found for this struct +... +LL | Wrap(1).lmao(); + | ^^^^ method not found in `Wrap<{integer}>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0055, E0599. +For more information about an error, try `rustc --explain E0055`. diff --git a/tests/ui/methods/receiver-equality.rs b/tests/ui/methods/receiver-equality.rs new file mode 100644 index 0000000000000..891435a425eb9 --- /dev/null +++ b/tests/ui/methods/receiver-equality.rs @@ -0,0 +1,16 @@ +// Tests that we probe receivers invariantly when using path-based method lookup. + +struct B(T); + +impl B { + fn method(self) { + println!("hey"); + } +} + +fn foo(y: B) { + B:: fn(&'a ())>::method(y); + //~^ ERROR no function or associated item named `method` found +} + +fn main() {} diff --git a/tests/ui/methods/receiver-equality.stderr b/tests/ui/methods/receiver-equality.stderr new file mode 100644 index 0000000000000..cea3340e386dc --- /dev/null +++ b/tests/ui/methods/receiver-equality.stderr @@ -0,0 +1,12 @@ +error[E0599]: no function or associated item named `method` found for struct `B fn(&'a ())>` in the current scope + --> $DIR/receiver-equality.rs:12:30 + | +LL | struct B(T); + | ----------- function or associated item `method` not found for this struct +... +LL | B:: fn(&'a ())>::method(y); + | ^^^^^^ function or associated item not found in `B` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr index 69b20d57be829..0e1565e251adc 100644 --- a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr +++ b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr @@ -11,6 +11,7 @@ note: the method `to_string` exists on the type `&u8` = note: the following trait bounds were not satisfied: `*const u8: std::fmt::Display` which is required by `*const u8: ToString` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead error[E0599]: `*mut u8` doesn't implement `std::fmt::Display` --> $DIR/suggest-convert-ptr-to-ref.rs:8:22 @@ -25,6 +26,7 @@ note: the method `to_string` exists on the type `&&mut u8` = note: the following trait bounds were not satisfied: `*mut u8: std::fmt::Display` which is required by `*mut u8: ToString` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope --> $DIR/suggest-convert-ptr-to-ref.rs:9:7 diff --git a/tests/ui/mir/early-otherwise-branch-ice.rs b/tests/ui/mir/early-otherwise-branch-ice.rs new file mode 100644 index 0000000000000..c1938eb75077b --- /dev/null +++ b/tests/ui/mir/early-otherwise-branch-ice.rs @@ -0,0 +1,18 @@ +// Changes in https://github.com/rust-lang/rust/pull/129047 lead to several mir-opt ICE regressions, +// this test is added to make sure this does not regress. + +//@ compile-flags: -C opt-level=3 +//@ check-pass + +#![crate_type = "lib"] + +use std::task::Poll; + +pub fn poll(val: Poll>, u8>>) { + match val { + Poll::Ready(Ok(Some(_trailers))) => {} + Poll::Ready(Err(_err)) => {} + Poll::Ready(Ok(None)) => {} + Poll::Pending => {} + } +} diff --git a/tests/ui/mir/mir_early_return_scope.rs b/tests/ui/mir/mir_early_return_scope.rs index 6dc3f8bc39bbe..42f1cc50d15da 100644 --- a/tests/ui/mir/mir_early_return_scope.rs +++ b/tests/ui/mir/mir_early_return_scope.rs @@ -1,5 +1,7 @@ //@ run-pass #![allow(unused_variables)] +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] static mut DROP: bool = false; struct ConnWrap(Conn); diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs index 5cbfdf2e35a74..daf0a62fc85f3 100644 --- a/tests/ui/mir/mir_let_chains_drop_order.rs +++ b/tests/ui/mir/mir_let_chains_drop_order.rs @@ -1,9 +1,14 @@ //@ run-pass //@ needs-unwind +//@ revisions: edition2021 edition2024 +//@ [edition2021] edition: 2021 +//@ [edition2024] compile-flags: -Z unstable-options +//@ [edition2024] edition: 2024 // See `mir_drop_order.rs` for more information #![feature(let_chains)] +#![cfg_attr(edition2024, feature(if_let_rescope))] #![allow(irrefutable_let_patterns)] use std::cell::RefCell; @@ -39,25 +44,32 @@ fn main() { 0, d( 1, - if let Some(_) = d(2, Some(true)).extra && let DropLogger { .. } = d(3, None) { + if let Some(_) = d(2, Some(true)).extra + && let DropLogger { .. } = d(3, None) + { None } else { Some(true) - } - ).extra + }, + ) + .extra, ), d(4, None), &d(5, None), d(6, None), - if let DropLogger { .. } = d(7, None) && let DropLogger { .. } = d(8, None) { + if let DropLogger { .. } = d(7, None) + && let DropLogger { .. } = d(8, None) + { d(9, None) - } - else { + } else { // 10 is not constructed d(10, None) }, ); + #[cfg(edition2021)] assert_eq!(get(), vec![8, 7, 1, 3, 2]); + #[cfg(edition2024)] + assert_eq!(get(), vec![3, 2, 8, 7, 1]); } assert_eq!(get(), vec![0, 4, 6, 9, 5]); @@ -73,21 +85,26 @@ fn main() { None } else { Some(true) - } - ).extra + }, + ) + .extra, ), d(15, None), &d(16, None), d(17, None), - if let DropLogger { .. } = d(18, None) && let DropLogger { .. } = d(19, None) { + if let DropLogger { .. } = d(18, None) + && let DropLogger { .. } = d(19, None) + { d(20, None) - } - else { + } else { // 10 is not constructed d(21, None) }, - panic::panic_any(InjectedFailure) + panic::panic_any(InjectedFailure), ); }); + #[cfg(edition2021)] assert_eq!(get(), vec![20, 17, 15, 11, 19, 18, 16, 12, 14, 13]); + #[cfg(edition2024)] + assert_eq!(get(), vec![14, 13, 19, 18, 20, 17, 15, 11, 16, 12]); } diff --git a/tests/ui/mir/validate/validate-unsize-cast.rs b/tests/ui/mir/validate/validate-unsize-cast.rs new file mode 100644 index 0000000000000..198af8d2e13a9 --- /dev/null +++ b/tests/ui/mir/validate/validate-unsize-cast.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+Inline,+GVN -Zvalidate-mir + +#![feature(unsize)] + +use std::marker::Unsize; + +pub trait CastTo: Unsize {} + +// Not well-formed! +impl CastTo for T {} +//~^ ERROR the trait bound `T: Unsize` is not satisfied + +pub trait Cast { + fn cast(&self) + where + Self: CastTo; +} +impl Cast for T { + #[inline(always)] + fn cast(&self) + where + Self: CastTo, + { + let x: &U = self; + } +} + +fn main() { + // When we inline this call, then we run GVN, then + // GVN tries to evaluate the `() -> [i32]` unsize. + // That's invalid! + ().cast::<[i32]>(); +} diff --git a/tests/ui/mir/validate/validate-unsize-cast.stderr b/tests/ui/mir/validate/validate-unsize-cast.stderr new file mode 100644 index 0000000000000..cfb47b34e980b --- /dev/null +++ b/tests/ui/mir/validate/validate-unsize-cast.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `T: Unsize` is not satisfied + --> $DIR/validate-unsize-cast.rs:10:42 + | +LL | impl CastTo for T {} + | ^ the trait `Unsize` is not implemented for `T` + | + = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information +note: required by a bound in `CastTo` + --> $DIR/validate-unsize-cast.rs:7:30 + | +LL | pub trait CastTo: Unsize {} + | ^^^^^^^^^ required by this bound in `CastTo` +help: consider further restricting this bound + | +LL | impl, U: ?Sized> CastTo for T {} + | ++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index 92f21a67c3707..c0cac5375230a 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -6,14 +6,14 @@ LL | 1 + Some(1); | = help: the trait `Add>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - `&'a f128` implements `Add` - `&'a f16` implements `Add` - `&'a f32` implements `Add` - `&'a f64` implements `Add` - `&'a i128` implements `Add` - `&'a i16` implements `Add` - `&'a i32` implements `Add` - `&'a i64` implements `Add` + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` and 56 others error[E0277]: cannot subtract `Option<{integer}>` from `usize` @@ -24,8 +24,8 @@ LL | 2 as usize - Some(1); | = help: the trait `Sub>` is not implemented for `usize` = help: the following other types implement trait `Sub`: - `&'a usize` implements `Sub` - `&usize` implements `Sub<&usize>` + `&usize` implements `Sub` + `&usize` implements `Sub` `usize` implements `Sub<&usize>` `usize` implements `Sub` @@ -37,14 +37,14 @@ LL | 3 * (); | = help: the trait `Mul<()>` is not implemented for `{integer}` = help: the following other types implement trait `Mul`: - `&'a f128` implements `Mul` - `&'a f16` implements `Mul` - `&'a f32` implements `Mul` - `&'a f64` implements `Mul` - `&'a i128` implements `Mul` - `&'a i16` implements `Mul` - `&'a i32` implements `Mul` - `&'a i64` implements `Mul` + `&f128` implements `Mul` + `&f128` implements `Mul` + `&f16` implements `Mul` + `&f16` implements `Mul` + `&f32` implements `Mul` + `&f32` implements `Mul` + `&f64` implements `Mul` + `&f64` implements `Mul` and 57 others error[E0277]: cannot divide `{integer}` by `&str` @@ -55,14 +55,14 @@ LL | 4 / ""; | = help: the trait `Div<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Div`: - `&'a f128` implements `Div` - `&'a f16` implements `Div` - `&'a f32` implements `Div` - `&'a f64` implements `Div` - `&'a i128` implements `Div` - `&'a i16` implements `Div` - `&'a i32` implements `Div` - `&'a i64` implements `Div` + `&f128` implements `Div` + `&f128` implements `Div` + `&f16` implements `Div` + `&f16` implements `Div` + `&f32` implements `Div` + `&f32` implements `Div` + `&f64` implements `Div` + `&f64` implements `Div` and 62 others error[E0277]: can't compare `{integer}` with `String` diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index 142a52aef13d0..3d12ba9899bc5 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -4,7 +4,7 @@ error[E0606]: casting `*const U` as `*const V` is invalid LL | u as *const V | ^^^^^^^^^^^^^ | - = note: vtable kinds may not match + = note: the pointers may have different metadata error[E0606]: casting `*const U` as `*const str` is invalid --> $DIR/cast-rfc0401.rs:8:5 @@ -12,7 +12,7 @@ error[E0606]: casting `*const U` as `*const str` is invalid LL | u as *const str | ^^^^^^^^^^^^^^^ | - = note: vtable kinds may not match + = note: the pointers may have different metadata error[E0609]: no field `f` on type `fn() {main}` --> $DIR/cast-rfc0401.rs:65:18 @@ -208,7 +208,7 @@ error[E0606]: casting `*const dyn Foo` as `*const [u16]` is invalid LL | let _ = cf as *const [u16]; | ^^^^^^^^^^^^^^^^^^ | - = note: vtable kinds may not match + = note: the pointers have different metadata error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid --> $DIR/cast-rfc0401.rs:69:13 @@ -216,7 +216,7 @@ error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid LL | let _ = cf as *const dyn Bar; | ^^^^^^^^^^^^^^^^^^^^ | - = note: vtable kinds may not match + = note: the trait objects may have different vtables error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:53:13 diff --git a/tests/ui/mismatched_types/mismatch-args-crash-issue-128848.rs b/tests/ui/mismatched_types/mismatch-args-crash-issue-128848.rs new file mode 100644 index 0000000000000..bfd6d4aeae645 --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-args-crash-issue-128848.rs @@ -0,0 +1,10 @@ +#![feature(fn_traits)] + +// Regression test for https://github.com/rust-lang/rust/issues/128848 + +fn f(a: T, b: T, c: T) { + f.call_once() + //~^ ERROR this method takes 1 argument but 0 arguments were supplied +} + +fn main() {} diff --git a/tests/ui/mismatched_types/mismatch-args-crash-issue-128848.stderr b/tests/ui/mismatched_types/mismatch-args-crash-issue-128848.stderr new file mode 100644 index 0000000000000..899cf435ddf5d --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-args-crash-issue-128848.stderr @@ -0,0 +1,16 @@ +error[E0061]: this method takes 1 argument but 0 arguments were supplied + --> $DIR/mismatch-args-crash-issue-128848.rs:6:7 + | +LL | f.call_once() + | ^^^^^^^^^-- argument #1 of type `(_, _, _)` is missing + | +note: method defined here + --> $SRC_DIR/core/src/ops/function.rs:LL:COL +help: provide the argument + | +LL | f.call_once(/* args */) + | ~~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/mismatched_types/mismatch-args-crash-issue-130400.rs b/tests/ui/mismatched_types/mismatch-args-crash-issue-130400.rs new file mode 100644 index 0000000000000..16c4e639c29ac --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-args-crash-issue-130400.rs @@ -0,0 +1,8 @@ +trait Bar { + fn foo(&mut self) -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + Self::foo() //~ ERROR this function takes 1 argument but 0 arguments were supplied + } +} + +fn main() {} diff --git a/tests/ui/mismatched_types/mismatch-args-crash-issue-130400.stderr b/tests/ui/mismatched_types/mismatch-args-crash-issue-130400.stderr new file mode 100644 index 0000000000000..0e4b94b98e268 --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-args-crash-issue-130400.stderr @@ -0,0 +1,26 @@ +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/mismatch-args-crash-issue-130400.rs:4:9 + | +LL | Self::foo() + | ^^^^^^^^^-- argument #1 is missing + | +note: method defined here + --> $DIR/mismatch-args-crash-issue-130400.rs:2:8 + | +LL | fn foo(&mut self) -> _ { + | ^^^ --------- +help: provide the argument + | +LL | Self::foo(/* value */) + | ~~~~~~~~~~~~~ + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/mismatch-args-crash-issue-130400.rs:2:26 + | +LL | fn foo(&mut self) -> _ { + | ^ not allowed in type signatures + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0061, E0121. +For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.rs b/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.rs new file mode 100644 index 0000000000000..60a3b47010e29 --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.rs @@ -0,0 +1,12 @@ +#![feature(c_variadic)] + +// Regression test that covers all 3 cases of https://github.com/rust-lang/rust/issues/130372 + +unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {} + +pub fn main() { + unsafe { + test_va_copy(); + //~^ ERROR this function takes at least 1 argument but 0 arguments were supplied + } +} diff --git a/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.stderr b/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.stderr new file mode 100644 index 0000000000000..38f769703582c --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.stderr @@ -0,0 +1,19 @@ +error[E0060]: this function takes at least 1 argument but 0 arguments were supplied + --> $DIR/mismatch-args-vargs-issue-130372.rs:9:9 + | +LL | test_va_copy(); + | ^^^^^^^^^^^^-- argument #1 of type `u64` is missing + | +note: function defined here + --> $DIR/mismatch-args-vargs-issue-130372.rs:5:22 + | +LL | unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {} + | ^^^^^^^^^^^^ ------ +help: provide the argument + | +LL | test_va_copy(/* u64 */); + | ~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0060`. diff --git a/tests/ui/never_type/issue-13352.stderr b/tests/ui/never_type/issue-13352.stderr index 7134e4d40a6a7..6818fa860051d 100644 --- a/tests/ui/never_type/issue-13352.stderr +++ b/tests/ui/never_type/issue-13352.stderr @@ -6,8 +6,8 @@ LL | 2_usize + (loop {}); | = help: the trait `Add<()>` is not implemented for `usize` = help: the following other types implement trait `Add`: - `&'a usize` implements `Add` - `&usize` implements `Add<&usize>` + `&usize` implements `Add` + `&usize` implements `Add` `usize` implements `Add<&usize>` `usize` implements `Add` diff --git a/tests/ui/never_type/issue-52443.rs b/tests/ui/never_type/issue-52443.rs index 0498a8a162590..dcda2b9536aa9 100644 --- a/tests/ui/never_type/issue-52443.rs +++ b/tests/ui/never_type/issue-52443.rs @@ -9,6 +9,5 @@ fn main() { [(); { for _ in 0usize.. {}; 0}]; //~^ ERROR `for` is not allowed in a `const` //~| ERROR cannot convert - //~| ERROR mutable references //~| ERROR cannot call } diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr index 02cb9cb22a3f4..adcff6637b0d9 100644 --- a/tests/ui/never_type/issue-52443.stderr +++ b/tests/ui/never_type/issue-52443.stderr @@ -55,16 +55,6 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error[E0658]: mutable references are not allowed in constants - --> $DIR/issue-52443.rs:9:21 - | -LL | [(); { for _ in 0usize.. {}; 0}]; - | ^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/issue-52443.rs:9:21 | @@ -77,7 +67,7 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0015, E0308, E0658. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr index a6d4f9a2a5cb1..1f01d3e82609b 100644 --- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr +++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr @@ -4,14 +4,13 @@ warning: creating a mutable reference to mutable static is discouraged LL | S1 { a: unsafe { &mut X1 } } | ^^^^^^^ mutable reference to mutable static | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior + = note: for more information, see + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of_mut!` instead to create a raw pointer +help: use `&raw mut` instead to create a raw pointer | -LL | S1 { a: unsafe { addr_of_mut!(X1) } } - | ~~~~~~~~~~~~~ + +LL | S1 { a: unsafe { &raw mut X1 } } + | ~~~~~~~~ warning: 1 warning emitted diff --git a/tests/ui/nll/issue-54556-niconii.stderr b/tests/ui/nll/issue-54556-niconii.edition2021.stderr similarity index 96% rename from tests/ui/nll/issue-54556-niconii.stderr rename to tests/ui/nll/issue-54556-niconii.edition2021.stderr index 015d9e1821205..31a03abbc9826 100644 --- a/tests/ui/nll/issue-54556-niconii.stderr +++ b/tests/ui/nll/issue-54556-niconii.edition2021.stderr @@ -1,5 +1,5 @@ error[E0597]: `counter` does not live long enough - --> $DIR/issue-54556-niconii.rs:22:20 + --> $DIR/issue-54556-niconii.rs:30:20 | LL | let counter = Mutex; | ------- binding `counter` declared here diff --git a/tests/ui/nll/issue-54556-niconii.rs b/tests/ui/nll/issue-54556-niconii.rs index cae389e8ccb52..1a7ad17cc84c0 100644 --- a/tests/ui/nll/issue-54556-niconii.rs +++ b/tests/ui/nll/issue-54556-niconii.rs @@ -6,6 +6,14 @@ // of temp drop order, and thus why inserting a semi-colon after the // `if let` expression in `main` works. +//@ revisions: edition2021 edition2024 +//@ [edition2021] edition: 2021 +//@ [edition2024] edition: 2024 +//@ [edition2024] compile-flags: -Z unstable-options +//@ [edition2024] check-pass + +#![cfg_attr(edition2024, feature(if_let_rescope))] + struct Mutex; struct MutexGuard<'a>(&'a Mutex); @@ -19,8 +27,10 @@ impl Mutex { fn main() { let counter = Mutex; - if let Ok(_) = counter.lock() { } //~ ERROR does not live long enough + if let Ok(_) = counter.lock() { } + //[edition2021]~^ ERROR: does not live long enough + // Up until Edition 2021: // With this code as written, the dynamic semantics here implies // that `Mutex::drop` for `counter` runs *before* // `MutexGuard::drop`, which would be unsound since `MutexGuard` @@ -28,4 +38,11 @@ fn main() { // // The goal of #54556 is to explain that within a compiler // diagnostic. + + // From Edition 2024: + // Now `MutexGuard::drop` runs *before* `Mutex::drop` because + // the lifetime of the `MutexGuard` is shortened to cover only + // from `if let` until the end of the consequent block. + // Therefore, Niconii's issue is properly solved thanks to the new + // temporary lifetime rule for `if let`s. } diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr index 92298c6617ff5..a454ed265685c 100644 --- a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr +++ b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr @@ -5,7 +5,7 @@ LL | cx: &dyn DebugContext, | - let's call the lifetime of this reference `'1` ... LL | bar.debug_with(cx); - | ^^ cast requires that `'1` must outlive `'static` + | ^^ coercion requires that `'1` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/nll/issue-69114-static-mut-ty.rs b/tests/ui/nll/issue-69114-static-mut-ty.rs index ce37da053e371..95c787488c08e 100644 --- a/tests/ui/nll/issue-69114-static-mut-ty.rs +++ b/tests/ui/nll/issue-69114-static-mut-ty.rs @@ -1,5 +1,8 @@ // Check that borrowck ensures that `static mut` items have the expected type. +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + static FOO: u8 = 42; static mut BAR: &'static u8 = &FOO; static mut BAR_ELIDED: &u8 = &FOO; diff --git a/tests/ui/nll/issue-69114-static-mut-ty.stderr b/tests/ui/nll/issue-69114-static-mut-ty.stderr index 1b41230d7ba39..eebfdee289620 100644 --- a/tests/ui/nll/issue-69114-static-mut-ty.stderr +++ b/tests/ui/nll/issue-69114-static-mut-ty.stderr @@ -1,5 +1,5 @@ error[E0597]: `n` does not live long enough - --> $DIR/issue-69114-static-mut-ty.rs:19:15 + --> $DIR/issue-69114-static-mut-ty.rs:22:15 | LL | let n = 42; | - binding `n` declared here @@ -14,7 +14,7 @@ LL | } | - `n` dropped here while still borrowed error[E0597]: `n` does not live long enough - --> $DIR/issue-69114-static-mut-ty.rs:27:22 + --> $DIR/issue-69114-static-mut-ty.rs:30:22 | LL | let n = 42; | - binding `n` declared here diff --git a/tests/ui/nll/user-annotations/cast_static_lifetime.stderr b/tests/ui/nll/user-annotations/cast_static_lifetime.stderr index 35eec233ed5c0..efd14fe875dbe 100644 --- a/tests/ui/nll/user-annotations/cast_static_lifetime.stderr +++ b/tests/ui/nll/user-annotations/cast_static_lifetime.stderr @@ -4,10 +4,9 @@ error[E0597]: `x` does not live long enough LL | let x = 22_u32; | - binding `x` declared here LL | let y: &u32 = (&x) as &'static u32; - | ^^^^---------------- + | ^^^^ ------------ type annotation requires that `x` is borrowed for `'static` | | | borrowed value does not live long enough - | type annotation requires that `x` is borrowed for `'static` LL | } | - `x` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr index 3e2706309b342..2ed0fadc06557 100644 --- a/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr +++ b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr @@ -4,10 +4,9 @@ error[E0597]: `x` does not live long enough LL | let x = 22_u32; | - binding `x` declared here LL | let y: &u32 = type_ascribe!(&x, &'static u32); - | --------------^^--------------- - | | | - | | borrowed value does not live long enough - | type annotation requires that `x` is borrowed for `'static` + | ^^ ------------ type annotation requires that `x` is borrowed for `'static` + | | + | borrowed value does not live long enough LL | } | - `x` dropped here while still borrowed diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index a910666bd56ce..ec560fc5ed5c5 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -6,8 +6,8 @@ LL | x + 100.0 | = help: the trait `Add<{float}>` is not implemented for `u8` = help: the following other types implement trait `Add`: - `&'a u8` implements `Add` - `&u8` implements `Add<&u8>` + `&u8` implements `Add` + `&u8` implements `Add` `u8` implements `Add<&u8>` `u8` implements `Add` @@ -19,8 +19,8 @@ LL | x + "foo" | = help: the trait `Add<&str>` is not implemented for `f64` = help: the following other types implement trait `Add`: - `&'a f64` implements `Add` - `&f64` implements `Add<&f64>` + `&f64` implements `Add` + `&f64` implements `Add` `f64` implements `Add<&f64>` `f64` implements `Add` @@ -32,8 +32,8 @@ LL | x + y | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: - `&'a f64` implements `Add` - `&f64` implements `Add<&f64>` + `&f64` implements `Add` + `&f64` implements `Add` `f64` implements `Add<&f64>` `f64` implements `Add` @@ -45,8 +45,8 @@ LL | x - 100.0 | = help: the trait `Sub<{float}>` is not implemented for `u8` = help: the following other types implement trait `Sub`: - `&'a u8` implements `Sub` - `&u8` implements `Sub<&u8>` + `&u8` implements `Sub` + `&u8` implements `Sub` `u8` implements `Sub<&u8>` `u8` implements `Sub` @@ -58,8 +58,8 @@ LL | x - "foo" | = help: the trait `Sub<&str>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - `&'a f64` implements `Sub` - `&f64` implements `Sub<&f64>` + `&f64` implements `Sub` + `&f64` implements `Sub` `f64` implements `Sub<&f64>` `f64` implements `Sub` @@ -71,8 +71,8 @@ LL | x - y | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - `&'a f64` implements `Sub` - `&f64` implements `Sub<&f64>` + `&f64` implements `Sub` + `&f64` implements `Sub` `f64` implements `Sub<&f64>` `f64` implements `Sub` @@ -84,8 +84,8 @@ LL | x * 100.0 | = help: the trait `Mul<{float}>` is not implemented for `u8` = help: the following other types implement trait `Mul`: - `&'a u8` implements `Mul` - `&u8` implements `Mul<&u8>` + `&u8` implements `Mul` + `&u8` implements `Mul` `u8` implements `Mul<&u8>` `u8` implements `Mul` @@ -97,8 +97,8 @@ LL | x * "foo" | = help: the trait `Mul<&str>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - `&'a f64` implements `Mul` - `&f64` implements `Mul<&f64>` + `&f64` implements `Mul` + `&f64` implements `Mul` `f64` implements `Mul<&f64>` `f64` implements `Mul` @@ -110,8 +110,8 @@ LL | x * y | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - `&'a f64` implements `Mul` - `&f64` implements `Mul<&f64>` + `&f64` implements `Mul` + `&f64` implements `Mul` `f64` implements `Mul<&f64>` `f64` implements `Mul` @@ -123,8 +123,8 @@ LL | x / 100.0 | = help: the trait `Div<{float}>` is not implemented for `u8` = help: the following other types implement trait `Div`: - `&'a u8` implements `Div` - `&u8` implements `Div<&u8>` + `&u8` implements `Div` + `&u8` implements `Div` `u8` implements `Div<&u8>` `u8` implements `Div>` `u8` implements `Div` @@ -137,8 +137,8 @@ LL | x / "foo" | = help: the trait `Div<&str>` is not implemented for `f64` = help: the following other types implement trait `Div`: - `&'a f64` implements `Div` - `&f64` implements `Div<&f64>` + `&f64` implements `Div` + `&f64` implements `Div` `f64` implements `Div<&f64>` `f64` implements `Div` @@ -150,8 +150,8 @@ LL | x / y | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: - `&'a f64` implements `Div` - `&f64` implements `Div<&f64>` + `&f64` implements `Div` + `&f64` implements `Div` `f64` implements `Div<&f64>` `f64` implements `Div` diff --git a/tests/ui/numbers-arithmetic/shift-near-oflo.rs b/tests/ui/numbers-arithmetic/shift-near-oflo.rs index 5cca31af0e38e..97227bd843f07 100644 --- a/tests/ui/numbers-arithmetic/shift-near-oflo.rs +++ b/tests/ui/numbers-arithmetic/shift-near-oflo.rs @@ -1,6 +1,9 @@ //@ run-pass //@ compile-flags: -C debug-assertions +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + // Check that we do *not* overflow on a number of edge cases. // (compare with test/run-fail/overflowing-{lsh,rsh}*.rs) diff --git a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr index 8585ac485dbb2..d8bff8614a4e5 100644 --- a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr @@ -6,8 +6,8 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Add`: - `&'a f32` implements `Add` - `&f32` implements `Add<&f32>` + `&f32` implements `Add` + `&f32` implements `Add` `f32` implements `Add<&f32>` `f32` implements `Add` help: consider using a floating-point literal by writing it with `.0` @@ -23,8 +23,8 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: - `&'a f64` implements `Add` - `&f64` implements `Add<&f64>` + `&f64` implements `Add` + `&f64` implements `Add` `f64` implements `Add<&f64>` `f64` implements `Add` help: consider using a floating-point literal by writing it with `.0` @@ -40,8 +40,8 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sub`: - `&'a f32` implements `Sub` - `&f32` implements `Sub<&f32>` + `&f32` implements `Sub` + `&f32` implements `Sub` `f32` implements `Sub<&f32>` `f32` implements `Sub` help: consider using a floating-point literal by writing it with `.0` @@ -57,8 +57,8 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - `&'a f64` implements `Sub` - `&f64` implements `Sub<&f64>` + `&f64` implements `Sub` + `&f64` implements `Sub` `f64` implements `Sub<&f64>` `f64` implements `Sub` help: consider using a floating-point literal by writing it with `.0` @@ -74,8 +74,8 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Mul`: - `&'a f32` implements `Mul` - `&f32` implements `Mul<&f32>` + `&f32` implements `Mul` + `&f32` implements `Mul` `f32` implements `Mul<&f32>` `f32` implements `Mul` help: consider using a floating-point literal by writing it with `.0` @@ -91,8 +91,8 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - `&'a f64` implements `Mul` - `&f64` implements `Mul<&f64>` + `&f64` implements `Mul` + `&f64` implements `Mul` `f64` implements `Mul<&f64>` `f64` implements `Mul` help: consider using a floating-point literal by writing it with `.0` @@ -108,8 +108,8 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Div`: - `&'a f32` implements `Div` - `&f32` implements `Div<&f32>` + `&f32` implements `Div` + `&f32` implements `Div` `f32` implements `Div<&f32>` `f32` implements `Div` help: consider using a floating-point literal by writing it with `.0` @@ -125,8 +125,8 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: - `&'a f64` implements `Div` - `&f64` implements `Div<&f64>` + `&f64` implements `Div` + `&f64` implements `Div` `f64` implements `Div<&f64>` `f64` implements `Div` help: consider using a floating-point literal by writing it with `.0` diff --git a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs new file mode 100644 index 0000000000000..dabaa309c16a1 --- /dev/null +++ b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs @@ -0,0 +1,142 @@ +//@ edition:2021 + +trait Trait {} + +struct IceCream; + +impl IceCream { + fn foo(_: &Trait) {} + //~^ ERROR: trait objects must include the `dyn` keyword + + fn bar(self, _: &'a Trait) {} + //~^ ERROR: trait objects must include the `dyn` keyword + //~| ERROR: use of undeclared lifetime name + + fn alice<'a>(&self, _: &Trait) {} + //~^ ERROR: trait objects must include the `dyn` keyword + + fn bob<'a>(_: &'a Trait) {} + //~^ ERROR: trait objects must include the `dyn` keyword + + fn cat() -> &Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn dog<'a>() -> &Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn kitten() -> &'a Trait { + //~^ ERROR: use of undeclared lifetime name + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn puppy<'a>() -> &'a Trait { + //~^ ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn parrot() -> &mut Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &mut Type + //~^ ERROR: cannot return reference to temporary value + } +} + +trait Sing { + fn foo(_: &Trait); + //~^ ERROR: trait objects must include the `dyn` keyword + + fn bar(_: &'a Trait); + //~^ ERROR: trait objects must include the `dyn` keyword + //~| ERROR: use of undeclared lifetime name + + fn alice<'a>(_: &Trait); + //~^ ERROR: trait objects must include the `dyn` keyword + + fn bob<'a>(_: &'a Trait); + //~^ ERROR: trait objects must include the `dyn` keyword + + fn cat() -> &Trait; + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + + fn dog<'a>() -> &Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn kitten() -> &'a Trait { + //~^ ERROR: use of undeclared lifetime name + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn puppy<'a>() -> &'a Trait { + //~^ ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn parrot() -> &mut Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &mut Type + //~^ ERROR: cannot return reference to temporary value + } +} + +fn foo(_: &Trait) {} +//~^ ERROR: trait objects must include the `dyn` keyword + +fn bar(_: &'a Trait) {} +//~^ ERROR: trait objects must include the `dyn` keyword +//~| ERROR: use of undeclared lifetime name + +fn alice<'a>(_: &Trait) {} +//~^ ERROR: trait objects must include the `dyn` keyword + +fn bob<'a>(_: &'a Trait) {} +//~^ ERROR: trait objects must include the `dyn` keyword + +struct Type; + +impl Trait for Type {} + +fn cat() -> &Trait { +//~^ ERROR: missing lifetime specifier +//~| ERROR: trait objects must include the `dyn` keyword + &Type +} + +fn dog<'a>() -> &Trait { +//~^ ERROR: missing lifetime specifier +//~| ERROR: trait objects must include the `dyn` keyword + &Type +} + +fn kitten() -> &'a Trait { +//~^ ERROR: use of undeclared lifetime name +//~| ERROR: trait objects must include the `dyn` keyword + &Type +} + +fn puppy<'a>() -> &'a Trait { +//~^ ERROR: trait objects must include the `dyn` keyword + &Type +} + +fn parrot() -> &mut Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &mut Type + //~^ ERROR: cannot return reference to temporary value +} + +fn main() {} diff --git a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr new file mode 100644 index 0000000000000..8bdfea7766e38 --- /dev/null +++ b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr @@ -0,0 +1,673 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:11:22 + | +LL | fn bar(self, _: &'a Trait) {} + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn bar<'a>(self, _: &'a Trait) {} + | ++++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> IceCream { + | ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:21:17 + | +LL | fn cat() -> &Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn cat() -> &'static Trait { + | +++++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:27:21 + | +LL | fn dog<'a>() -> &Trait { + | ^ 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 `'a` lifetime + | +LL | fn dog<'a>() -> &'a Trait { + | ++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:33:21 + | +LL | fn kitten() -> &'a Trait { + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn kitten<'a>() -> &'a Trait { + | ++++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> IceCream { + | ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:44:20 + | +LL | fn parrot() -> &mut Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn parrot() -> &'static mut Trait { + | +++++++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:56:16 + | +LL | fn bar(_: &'a Trait); + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn bar<'a>(_: &'a Trait); + | ++++ +help: consider introducing lifetime `'a` here + | +LL | trait Sing<'a> { + | ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:66:17 + | +LL | fn cat() -> &Trait; + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn cat() -> &'static Trait; + | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL - fn cat() -> &Trait; +LL + fn cat() -> Trait; + | + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:70:21 + | +LL | fn dog<'a>() -> &Trait { + | ^ 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 `'a` lifetime + | +LL | fn dog<'a>() -> &'a Trait { + | ++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:76:21 + | +LL | fn kitten() -> &'a Trait { + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn kitten<'a>() -> &'a Trait { + | ++++ +help: consider introducing lifetime `'a` here + | +LL | trait Sing<'a> { + | ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:20 + | +LL | fn parrot() -> &mut Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn parrot() -> &'static mut Trait { + | +++++++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:98:12 + | +LL | fn bar(_: &'a Trait) {} + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:112:13 + | +LL | fn cat() -> &Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn cat() -> &'static Trait { + | +++++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:118:17 + | +LL | fn dog<'a>() -> &Trait { + | ^ 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 `'a` lifetime + | +LL | fn dog<'a>() -> &'a Trait { + | ++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:124:17 + | +LL | fn kitten() -> &'a Trait { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:16 + | +LL | fn parrot() -> &mut Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn parrot() -> &'static mut Trait { + | +++++++ + +error[E0515]: cannot return reference to temporary value + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:47:9 + | +LL | &mut Type + | ^^^^^---- + | | | + | | temporary value created here + | returns a reference to data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:90:9 + | +LL | &mut Type + | ^^^^^---- + | | | + | | temporary value created here + | returns a reference to data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:138:5 + | +LL | &mut Type + | ^^^^^---- + | | | + | | temporary value created here + | returns a reference to data owned by the current function + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:53:16 + | +LL | fn foo(_: &Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn foo(_: &T); + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn foo(_: &impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn foo(_: &dyn Trait); + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:56:19 + | +LL | fn bar(_: &'a Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bar(_: &'a T); + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(_: &'a impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bar(_: &'a dyn Trait); + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:60:22 + | +LL | fn alice<'a>(_: &Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn alice<'a, T: Trait>(_: &T); + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn alice<'a>(_: &impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn alice<'a>(_: &dyn Trait); + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:63:23 + | +LL | fn bob<'a>(_: &'a Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bob<'a, T: Trait>(_: &'a T); + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bob<'a>(_: &'a impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bob<'a>(_: &'a dyn Trait); + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:66:18 + | +LL | fn cat() -> &Trait; + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn cat() -> &impl Trait; + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn cat() -> Box; + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:70:22 + | +LL | fn dog<'a>() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn dog<'a>() -> &impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn dog<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:76:24 + | +LL | fn kitten() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn kitten() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn kitten() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:82:27 + | +LL | fn puppy<'a>() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn puppy<'a>() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn puppy<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:25 + | +LL | fn parrot() -> &mut Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn parrot() -> &mut impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn parrot() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:95:12 + | +LL | fn foo(_: &Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn foo(_: &T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn foo(_: &impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn foo(_: &dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:98:15 + | +LL | fn bar(_: &'a Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bar(_: &'a T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(_: &'a impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bar(_: &'a dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:102:18 + | +LL | fn alice<'a>(_: &Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn alice<'a, T: Trait>(_: &T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn alice<'a>(_: &impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn alice<'a>(_: &dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:105:19 + | +LL | fn bob<'a>(_: &'a Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bob<'a, T: Trait>(_: &'a T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bob<'a>(_: &'a impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bob<'a>(_: &'a dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:112:14 + | +LL | fn cat() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn cat() -> &impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn cat() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:118:18 + | +LL | fn dog<'a>() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn dog<'a>() -> &impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn dog<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:124:20 + | +LL | fn kitten() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn kitten() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn kitten() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:130:23 + | +LL | fn puppy<'a>() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn puppy<'a>() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn puppy<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:21 + | +LL | fn parrot() -> &mut Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn parrot() -> &mut impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn parrot() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:8:16 + | +LL | fn foo(_: &Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn foo(_: &T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn foo(_: &impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn foo(_: &dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:11:25 + | +LL | fn bar(self, _: &'a Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bar(self, _: &'a T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(self, _: &'a impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bar(self, _: &'a dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:15:29 + | +LL | fn alice<'a>(&self, _: &Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn alice<'a, T: Trait>(&self, _: &T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn alice<'a>(&self, _: &impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn alice<'a>(&self, _: &dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:18:23 + | +LL | fn bob<'a>(_: &'a Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bob<'a, T: Trait>(_: &'a T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bob<'a>(_: &'a impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bob<'a>(_: &'a dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:21:18 + | +LL | fn cat() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn cat() -> &impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn cat() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:27:22 + | +LL | fn dog<'a>() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn dog<'a>() -> &impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn dog<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:33:24 + | +LL | fn kitten() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn kitten() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn kitten() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:39:27 + | +LL | fn puppy<'a>() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn puppy<'a>() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn puppy<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:44:25 + | +LL | fn parrot() -> &mut Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn parrot() -> &mut impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn parrot() -> Box { + | ~~~~~~~~~~~~~~ + +error: aborting due to 45 previous errors + +Some errors have detailed explanations: E0106, E0261, E0515, E0782. +For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs index b0822352c9dc6..db00fe05583f0 100644 --- a/tests/ui/offset-of/offset-of-tuple.rs +++ b/tests/ui/offset-of/offset-of-tuple.rs @@ -28,6 +28,7 @@ type ComplexTup = (((u8, u8), u8), u8); fn nested() { offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2` + offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); //~ ERROR no field `1e2` offset_of!(((u8, u16), (u32, u16, u8)), 1.2); offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); //~ ERROR no field `0` diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr index e6b45c0b6b846..dd20859e04e1b 100644 --- a/tests/ui/offset-of/offset-of-tuple.stderr +++ b/tests/ui/offset-of/offset-of-tuple.stderr @@ -29,43 +29,43 @@ LL | { builtin # offset_of((u8, u8), 1 .) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:46:45 + --> $DIR/offset-of-tuple.rs:47:45 | LL | { builtin # offset_of(ComplexTup, 0.0.1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:47:46 + --> $DIR/offset-of-tuple.rs:48:46 | LL | { builtin # offset_of(ComplexTup, 0 .0.1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:48:47 + --> $DIR/offset-of-tuple.rs:49:47 | LL | { builtin # offset_of(ComplexTup, 0 . 0.1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:49:46 + --> $DIR/offset-of-tuple.rs:50:46 | LL | { builtin # offset_of(ComplexTup, 0. 0.1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:50:46 + --> $DIR/offset-of-tuple.rs:51:46 | LL | { builtin # offset_of(ComplexTup, 0.0 .1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:51:47 + --> $DIR/offset-of-tuple.rs:52:47 | LL | { builtin # offset_of(ComplexTup, 0.0 . 1.) }; | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:52:46 + --> $DIR/offset-of-tuple.rs:53:46 | LL | { builtin # offset_of(ComplexTup, 0.0. 1.) }; | ^ @@ -104,43 +104,43 @@ LL | offset_of!((u8, u8), 1 .); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:35:34 + --> $DIR/offset-of-tuple.rs:36:34 | LL | offset_of!(ComplexTup, 0.0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:36:35 + --> $DIR/offset-of-tuple.rs:37:35 | LL | offset_of!(ComplexTup, 0 .0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:37:36 + --> $DIR/offset-of-tuple.rs:38:36 | LL | offset_of!(ComplexTup, 0 . 0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:38:35 + --> $DIR/offset-of-tuple.rs:39:35 | LL | offset_of!(ComplexTup, 0. 0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:39:35 + --> $DIR/offset-of-tuple.rs:40:35 | LL | offset_of!(ComplexTup, 0.0 .1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:40:36 + --> $DIR/offset-of-tuple.rs:41:36 | LL | offset_of!(ComplexTup, 0.0 . 1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:41:35 + --> $DIR/offset-of-tuple.rs:42:35 | LL | offset_of!(ComplexTup, 0.0. 1.); | ^ @@ -196,22 +196,21 @@ LL | builtin # offset_of((u8, u8), 1_u8); error[E0609]: no field `2` on type `(u8, u16)` --> $DIR/offset-of-tuple.rs:30:47 | -LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); - | _____------------------------------------------^- - | | | - | | in this macro invocation -LL | | offset_of!(((u8, u16), (u32, u16, u8)), 1.2); -LL | | offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); -... | +LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); + | ^ + +error[E0609]: no field `1e2` on type `(u8, u16)` + --> $DIR/offset-of-tuple.rs:31:47 | - = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); + | ^^^ error[E0609]: no field `0` on type `u8` - --> $DIR/offset-of-tuple.rs:32:49 + --> $DIR/offset-of-tuple.rs:33:49 | LL | offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); | ^ -error: aborting due to 33 previous errors +error: aborting due to 34 previous errors For more information about this error, try `rustc --explain E0609`. diff --git a/tests/ui/on-unimplemented/sum.stderr b/tests/ui/on-unimplemented/sum.stderr index f8e266a872782..d89cc2f7bf3b9 100644 --- a/tests/ui/on-unimplemented/sum.stderr +++ b/tests/ui/on-unimplemented/sum.stderr @@ -8,7 +8,7 @@ LL | vec![(), ()].iter().sum::(); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - `i32` implements `Sum<&'a i32>` + `i32` implements `Sum<&i32>` `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:4:18 @@ -30,7 +30,7 @@ LL | vec![(), ()].iter().product::(); | = help: the trait `Product<&()>` is not implemented for `i32` = help: the following other types implement trait `Product`: - `i32` implements `Product<&'a i32>` + `i32` implements `Product<&i32>` `i32` implements `Product` note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:7:18 diff --git a/tests/ui/parser/bad-name.rs b/tests/ui/parser/bad-name.rs index 59432a1d9a5b9..fefe9122a08fb 100644 --- a/tests/ui/parser/bad-name.rs +++ b/tests/ui/parser/bad-name.rs @@ -1,5 +1,6 @@ -//@ error-pattern: expected - fn main() { let x.y::.z foo; + //~^ error: field expressions cannot have generic arguments + //~| error: expected a pattern, found an expression + //~| error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo` } diff --git a/tests/ui/parser/bad-name.stderr b/tests/ui/parser/bad-name.stderr index e133d4e4839ce..3fc416dd5311f 100644 --- a/tests/ui/parser/bad-name.stderr +++ b/tests/ui/parser/bad-name.stderr @@ -1,8 +1,20 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` - --> $DIR/bad-name.rs:4:8 +error: field expressions cannot have generic arguments + --> $DIR/bad-name.rs:2:12 | LL | let x.y::.z foo; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^^^^ -error: aborting due to 1 previous error +error: expected a pattern, found an expression + --> $DIR/bad-name.rs:2:7 + | +LL | let x.y::.z foo; + | ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo` + --> $DIR/bad-name.rs:2:22 + | +LL | let x.y::.z foo; + | ^^^ expected one of 9 possible tokens + +error: aborting due to 3 previous errors diff --git a/tests/ui/parser/block-no-opening-brace.rs b/tests/ui/parser/block-no-opening-brace.rs index e90a34104e8f5..2fde37ce6acef 100644 --- a/tests/ui/parser/block-no-opening-brace.rs +++ b/tests/ui/parser/block-no-opening-brace.rs @@ -4,28 +4,46 @@ fn main() {} -fn f1() { +fn in_loop() { loop let x = 0; //~ ERROR expected `{`, found keyword `let` drop(0); - } +} -fn f2() { +fn in_while() { while true let x = 0; //~ ERROR expected `{`, found keyword `let` - } +} -fn f3() { +fn in_for() { for x in 0..1 let x = 0; //~ ERROR expected `{`, found keyword `let` - } +} + -fn f4() { +// FIXME +fn in_try() { try //~ ERROR expected expression, found reserved keyword `try` let x = 0; - } +} -fn f5() { +// FIXME(#80931) +fn in_async() { async let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let` +} + +// FIXME(#78168) +fn in_const() { + let x = const 2; //~ ERROR expected expression, found keyword `const` +} + +// FIXME(#78168) +fn in_const_in_match() { + let x = 2; + match x { + const 2 => {} + //~^ ERROR expected identifier, found keyword `const` + //~| ERROR expected one of `=>`, `if`, or `|`, found `2` } +} diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr index f232f480ce9c2..83360944ed560 100644 --- a/tests/ui/parser/block-no-opening-brace.stderr +++ b/tests/ui/parser/block-no-opening-brace.stderr @@ -38,18 +38,36 @@ LL | { let x = 0; } | + + error: expected expression, found reserved keyword `try` - --> $DIR/block-no-opening-brace.rs:24:5 + --> $DIR/block-no-opening-brace.rs:26:5 | LL | try | ^^^ expected expression error: expected one of `move`, `|`, or `||`, found keyword `let` - --> $DIR/block-no-opening-brace.rs:30:9 + --> $DIR/block-no-opening-brace.rs:33:9 | LL | async | - expected one of `move`, `|`, or `||` LL | let x = 0; | ^^^ unexpected token -error: aborting due to 5 previous errors +error: expected expression, found keyword `const` + --> $DIR/block-no-opening-brace.rs:38:13 + | +LL | let x = const 2; + | ^^^^^ expected expression + +error: expected identifier, found keyword `const` + --> $DIR/block-no-opening-brace.rs:45:9 + | +LL | const 2 => {} + | ^^^^^ expected identifier, found keyword + +error: expected one of `=>`, `if`, or `|`, found `2` + --> $DIR/block-no-opening-brace.rs:45:15 + | +LL | const 2 => {} + | ^ expected one of `=>`, `if`, or `|` + +error: aborting due to 8 previous errors diff --git a/tests/ui/parser/extern-crate-unexpected-token.stderr b/tests/ui/parser/extern-crate-unexpected-token.stderr index f83bb3e3e35ae..951b0274b0d46 100644 --- a/tests/ui/parser/extern-crate-unexpected-token.stderr +++ b/tests/ui/parser/extern-crate-unexpected-token.stderr @@ -3,6 +3,11 @@ error: expected one of `crate` or `{`, found `crte` | LL | extern crte foo; | ^^^^ expected one of `crate` or `{` + | +help: there is a keyword `crate` with a similar name + | +LL | extern crate foo; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs index 5907ac0526044..972e52d75daf0 100644 --- a/tests/ui/parser/fn-header-semantic-fail.rs +++ b/tests/ui/parser/fn-header-semantic-fail.rs @@ -2,8 +2,6 @@ //@ edition:2018 -#![feature(const_extern_fn)] - fn main() { async fn ff1() {} // OK. unsafe fn ff2() {} // OK. diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index b519ddbe2b436..dda42f24b32d0 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -1,5 +1,5 @@ error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:12:5 + --> $DIR/fn-header-semantic-fail.rs:10:5 | LL | const async unsafe extern "C" fn ff5() {} | ^^^^^-^^^^^------------------------------ @@ -8,7 +8,7 @@ LL | const async unsafe extern "C" fn ff5() {} | `const` because of this error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:18:9 + --> $DIR/fn-header-semantic-fail.rs:16:9 | LL | const fn ft3(); | ^^^^^- @@ -17,7 +17,7 @@ LL | const fn ft3(); | help: remove the `const` error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:20:9 + --> $DIR/fn-header-semantic-fail.rs:18:9 | LL | const async unsafe extern "C" fn ft5(); | ^^^^^- @@ -26,7 +26,7 @@ LL | const async unsafe extern "C" fn ft5(); | help: remove the `const` error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:20:9 + --> $DIR/fn-header-semantic-fail.rs:18:9 | LL | const async unsafe extern "C" fn ft5(); | ^^^^^-^^^^^---------------------------- @@ -35,7 +35,7 @@ LL | const async unsafe extern "C" fn ft5(); | `const` because of this error[E0379]: functions in trait impls cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:29:9 + --> $DIR/fn-header-semantic-fail.rs:27:9 | LL | const fn ft3() {} | ^^^^^- @@ -44,7 +44,7 @@ LL | const fn ft3() {} | help: remove the `const` error[E0379]: functions in trait impls cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:31:9 + --> $DIR/fn-header-semantic-fail.rs:29:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^- @@ -53,7 +53,7 @@ LL | const async unsafe extern "C" fn ft5() {} | help: remove the `const` error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:31:9 + --> $DIR/fn-header-semantic-fail.rs:29:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^-^^^^^------------------------------ @@ -62,7 +62,7 @@ LL | const async unsafe extern "C" fn ft5() {} | `const` because of this error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:41:9 + --> $DIR/fn-header-semantic-fail.rs:39:9 | LL | const async unsafe extern "C" fn fi5() {} | ^^^^^-^^^^^------------------------------ @@ -71,7 +71,7 @@ LL | const async unsafe extern "C" fn fi5() {} | `const` because of this error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:46:9 + --> $DIR/fn-header-semantic-fail.rs:44:9 | LL | extern "C" { | ---------- in this `extern` block @@ -79,7 +79,7 @@ LL | async fn fe1(); | ^^^^^ help: remove this qualifier error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/fn-header-semantic-fail.rs:47:9 + --> $DIR/fn-header-semantic-fail.rs:45:9 | LL | unsafe fn fe2(); | ^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | unsafe extern "C" { | ++++++ error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:48:9 + --> $DIR/fn-header-semantic-fail.rs:46:9 | LL | extern "C" { | ---------- in this `extern` block @@ -99,7 +99,7 @@ LL | const fn fe3(); | ^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:49:9 + --> $DIR/fn-header-semantic-fail.rs:47:9 | LL | extern "C" { | ---------- in this `extern` block @@ -108,7 +108,7 @@ LL | extern "C" fn fe4(); | ^^^^^^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:15 + --> $DIR/fn-header-semantic-fail.rs:48:15 | LL | extern "C" { | ---------- in this `extern` block @@ -117,7 +117,7 @@ LL | const async unsafe extern "C" fn fe5(); | ^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:9 + --> $DIR/fn-header-semantic-fail.rs:48:9 | LL | extern "C" { | ---------- in this `extern` block @@ -126,7 +126,7 @@ LL | const async unsafe extern "C" fn fe5(); | ^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:28 + --> $DIR/fn-header-semantic-fail.rs:48:28 | LL | extern "C" { | ---------- in this `extern` block @@ -135,7 +135,7 @@ LL | const async unsafe extern "C" fn fe5(); | ^^^^^^^^^^ help: remove this qualifier error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:9 + --> $DIR/fn-header-semantic-fail.rs:48:9 | LL | const async unsafe extern "C" fn fe5(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,7 +146,7 @@ LL | unsafe extern "C" { | ++++++ error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:50:9 + --> $DIR/fn-header-semantic-fail.rs:48:9 | LL | const async unsafe extern "C" fn fe5(); | ^^^^^-^^^^^---------------------------- diff --git a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.rs b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.rs new file mode 100644 index 0000000000000..ff28548b795fc --- /dev/null +++ b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.rs @@ -0,0 +1,6 @@ +//@ error-pattern: circular modules +// Regression test for #97589: a doc-comment on a circular module bypassed cycle detection + +#![crate_type = "lib"] + +pub mod recursive; diff --git a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.stderr b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.stderr new file mode 100644 index 0000000000000..02d6406775abb --- /dev/null +++ b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.stderr @@ -0,0 +1,8 @@ +error: circular modules: $DIR/recursive.rs -> $DIR/recursive.rs + --> $DIR/recursive.rs:6:1 + | +LL | mod recursive; + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs new file mode 100644 index 0000000000000..3d758be8c0553 --- /dev/null +++ b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs @@ -0,0 +1,6 @@ +//@ ignore-test: this is an auxiliary file for circular-module-with-doc-comment-issue-97589.rs + +//! this comment caused the circular dependency checker to break + +#[path = "recursive.rs"] +mod recursive; diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index e6ef07d13fd8d..a25c277d78a5b 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -3,6 +3,21 @@ error: expected a pattern, found an expression | LL | tmp[0] => {} | ^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == tmp[0] => {} + | ~~~ ++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = tmp[0]; +LL ~ match z { +LL ~ VAL => {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { tmp[0] } => {} + | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr index 79c574ead61c3..c2c0faa21d151 100644 --- a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr +++ b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr @@ -8,10 +8,12 @@ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:4:17 | LL | fn foo(&mur Self) {} - | -----^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn foo(&mut Self) {} + | ~~~ error: unexpected lifetime `'static` in pattern --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:13 @@ -35,16 +37,23 @@ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:25 | LL | fn bar(&'static mur Self) {} - | -------------^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn bar(&'static mut Self) {} + | ~~~ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:14:17 | LL | fn baz(&mur Self @ _) {} | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn baz(&mut Self @ _) {} + | ~~~ error[E0533]: expected unit struct, found self constructor `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:4:17 diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.rs b/tests/ui/parser/misspelled-keywords/assoc-type.rs new file mode 100644 index 0000000000000..a6b694a2abe6b --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/assoc-type.rs @@ -0,0 +1,6 @@ +trait Animal { + Type Result = u8; + //~^ ERROR expected one of +} + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.stderr b/tests/ui/parser/misspelled-keywords/assoc-type.stderr new file mode 100644 index 0000000000000..677da53e3400d --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/assoc-type.stderr @@ -0,0 +1,18 @@ +error: expected one of `!` or `::`, found `Result` + --> $DIR/assoc-type.rs:2:10 + | +LL | trait Animal { + | - while parsing this item list starting here +LL | Type Result = u8; + | ^^^^^^ expected one of `!` or `::` +LL | +LL | } + | - the item list ends here + | +help: write keyword `type` in lowercase + | +LL | type Result = u8; + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/async-move.rs b/tests/ui/parser/misspelled-keywords/async-move.rs new file mode 100644 index 0000000000000..702a905e918c3 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/async-move.rs @@ -0,0 +1,6 @@ +//@ edition: 2018 + +fn main() { + async Move {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr new file mode 100644 index 0000000000000..4be4b56e5056a --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/async-move.stderr @@ -0,0 +1,13 @@ +error: expected one of `move`, `|`, or `||`, found `Move` + --> $DIR/async-move.rs:4:11 + | +LL | async Move {} + | ^^^^ expected one of `move`, `|`, or `||` + | +help: write keyword `move` in lowercase + | +LL | async move {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/const-fn.rs b/tests/ui/parser/misspelled-keywords/const-fn.rs new file mode 100644 index 0000000000000..c4174b6a2efb5 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const-fn.rs @@ -0,0 +1,5 @@ +cnst fn code() {} +//~^ ERROR expected one of + +fn main() { +} diff --git a/tests/ui/parser/misspelled-keywords/const-fn.stderr b/tests/ui/parser/misspelled-keywords/const-fn.stderr new file mode 100644 index 0000000000000..5646b26143c40 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const-fn.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found keyword `fn` + --> $DIR/const-fn.rs:1:6 + | +LL | cnst fn code() {} + | ^^ expected one of `!` or `::` + | +help: there is a keyword `const` with a similar name + | +LL | const fn code() {} + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/const-generics.rs b/tests/ui/parser/misspelled-keywords/const-generics.rs new file mode 100644 index 0000000000000..2df64a87e2776 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const-generics.rs @@ -0,0 +1,4 @@ +fn foo(_arr: [i32; N]) {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/const-generics.stderr b/tests/ui/parser/misspelled-keywords/const-generics.stderr new file mode 100644 index 0000000000000..fd59999ab635f --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const-generics.stderr @@ -0,0 +1,13 @@ +error: expected one of `,`, `:`, `=`, or `>`, found `N` + --> $DIR/const-generics.rs:1:15 + | +LL | fn foo(_arr: [i32; N]) {} + | ^ expected one of `,`, `:`, `=`, or `>` + | +help: there is a keyword `const` with a similar name + | +LL | fn foo(_arr: [i32; N]) {} + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/const.rs b/tests/ui/parser/misspelled-keywords/const.rs new file mode 100644 index 0000000000000..b481408cb62d2 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const.rs @@ -0,0 +1,4 @@ +cons A: u8 = 10; +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/const.stderr b/tests/ui/parser/misspelled-keywords/const.stderr new file mode 100644 index 0000000000000..35e4d731db768 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `A` + --> $DIR/const.rs:1:6 + | +LL | cons A: u8 = 10; + | ^ expected one of `!` or `::` + | +help: there is a keyword `const` with a similar name + | +LL | const A: u8 = 10; + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/for-loop.rs b/tests/ui/parser/misspelled-keywords/for-loop.rs new file mode 100644 index 0000000000000..6aba581cf17fa --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/for-loop.rs @@ -0,0 +1,4 @@ +fn main() { + form i in 1..10 {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/for-loop.stderr b/tests/ui/parser/misspelled-keywords/for-loop.stderr new file mode 100644 index 0000000000000..d2236ab074da7 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/for-loop.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `i` + --> $DIR/for-loop.rs:2:10 + | +LL | form i in 1..10 {} + | ^ expected one of 8 possible tokens + | +help: there is a keyword `for` with a similar name + | +LL | for i in 1..10 {} + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/hrdt.rs b/tests/ui/parser/misspelled-keywords/hrdt.rs new file mode 100644 index 0000000000000..9ca9e1bfbeecc --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/hrdt.rs @@ -0,0 +1,16 @@ +struct Closure { + data: (u8, u16), + func: F, +} + +impl Closure + Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, +//~^ ERROR expected one of +{ + fn call(&self) -> &u8 { + (self.func)(&self.data) + } +} + + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/hrdt.stderr b/tests/ui/parser/misspelled-keywords/hrdt.stderr new file mode 100644 index 0000000000000..5393a730506d9 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/hrdt.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found keyword `for` + --> $DIR/hrdt.rs:7:11 + | +LL | Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, + | ^^^ expected one of 7 possible tokens + | +help: write keyword `where` in lowercase (notice the capitalization difference) + | +LL | where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/impl-block.rs b/tests/ui/parser/misspelled-keywords/impl-block.rs new file mode 100644 index 0000000000000..dc2570c22c5df --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-block.rs @@ -0,0 +1,6 @@ +struct Human; + +ipml Human {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/impl-block.stderr b/tests/ui/parser/misspelled-keywords/impl-block.stderr new file mode 100644 index 0000000000000..d86ae326ce2e3 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-block.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `Human` + --> $DIR/impl-block.rs:3:6 + | +LL | ipml Human {} + | ^^^^^ expected one of `!` or `::` + | +help: there is a keyword `impl` with a similar name + | +LL | impl Human {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/impl-return.rs b/tests/ui/parser/misspelled-keywords/impl-return.rs new file mode 100644 index 0000000000000..c9d1973179e47 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-return.rs @@ -0,0 +1,4 @@ +fn code() -> Impl Display {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/impl-return.stderr b/tests/ui/parser/misspelled-keywords/impl-return.stderr new file mode 100644 index 0000000000000..883f5cea73eff --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-return.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `Display` + --> $DIR/impl-return.rs:1:19 + | +LL | fn code() -> Impl Display {} + | ^^^^^^^ expected one of 7 possible tokens + | +help: write keyword `impl` in lowercase (notice the capitalization difference) + | +LL | fn code() -> impl Display {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/impl-trait-for.rs b/tests/ui/parser/misspelled-keywords/impl-trait-for.rs new file mode 100644 index 0000000000000..c6f3fcda5ad71 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-trait-for.rs @@ -0,0 +1,6 @@ +struct Human; + +impl Debug form Human {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr b/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr new file mode 100644 index 0000000000000..8dd5a4645f362 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `Human` + --> $DIR/impl-trait-for.rs:3:17 + | +LL | impl Debug form Human {} + | ^^^^^ expected one of 7 possible tokens + | +help: there is a keyword `for` with a similar name + | +LL | impl Debug for Human {} + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/impl-trait.rs b/tests/ui/parser/misspelled-keywords/impl-trait.rs new file mode 100644 index 0000000000000..99380b8ac0ecd --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-trait.rs @@ -0,0 +1,4 @@ +fn code() -> u8 {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/impl-trait.stderr b/tests/ui/parser/misspelled-keywords/impl-trait.stderr new file mode 100644 index 0000000000000..02a0c80831107 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-trait.stderr @@ -0,0 +1,13 @@ +error: expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`, found `Debug` + --> $DIR/impl-trait.rs:1:18 + | +LL | fn code() -> u8 {} + | ^^^^^ expected one of 7 possible tokens + | +help: there is a keyword `impl` with a similar name + | +LL | fn code() -> u8 {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/let-else.rs b/tests/ui/parser/misspelled-keywords/let-else.rs new file mode 100644 index 0000000000000..0d5a03e3e43e4 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let-else.rs @@ -0,0 +1,4 @@ +fn main() { + let Some(a) = Some(10) elze {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/let-else.stderr b/tests/ui/parser/misspelled-keywords/let-else.stderr new file mode 100644 index 0000000000000..6f41a0d99dba9 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let-else.stderr @@ -0,0 +1,13 @@ +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `elze` + --> $DIR/let-else.rs:2:28 + | +LL | let Some(a) = Some(10) elze {} + | ^^^^ expected one of `.`, `;`, `?`, `else`, or an operator + | +help: there is a keyword `else` with a similar name + | +LL | let Some(a) = Some(10) else {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/let-mut.rs b/tests/ui/parser/misspelled-keywords/let-mut.rs new file mode 100644 index 0000000000000..83228fe8c6682 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let-mut.rs @@ -0,0 +1,4 @@ +fn main() { + let muta a = 10; + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/let-mut.stderr b/tests/ui/parser/misspelled-keywords/let-mut.stderr new file mode 100644 index 0000000000000..766d2a049090b --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let-mut.stderr @@ -0,0 +1,13 @@ +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `a` + --> $DIR/let-mut.rs:2:14 + | +LL | let muta a = 10; + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | let mut a = 10; + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/let.rs b/tests/ui/parser/misspelled-keywords/let.rs new file mode 100644 index 0000000000000..461c3e518db82 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let.rs @@ -0,0 +1,9 @@ +fn main() { + Let a = 10; + //~^ ERROR expected one of +} + +fn code() { + lett a = 10; + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/let.stderr b/tests/ui/parser/misspelled-keywords/let.stderr new file mode 100644 index 0000000000000..c2dcdef541d81 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let.stderr @@ -0,0 +1,24 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/let.rs:2:9 + | +LL | Let a = 10; + | ^ expected one of 8 possible tokens + | +help: write keyword `let` in lowercase + | +LL | let a = 10; + | ~~~ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/let.rs:7:10 + | +LL | lett a = 10; + | ^ expected one of 8 possible tokens + | +help: there is a keyword `let` with a similar name + | +LL | let a = 10; + | ~~~ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/misspelled-keywords/match.rs b/tests/ui/parser/misspelled-keywords/match.rs new file mode 100644 index 0000000000000..a31840a2d7111 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/match.rs @@ -0,0 +1,5 @@ +fn main() { + let a = 10; + matche a {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/match.stderr b/tests/ui/parser/misspelled-keywords/match.stderr new file mode 100644 index 0000000000000..90780ebd38ef0 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/match.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/match.rs:3:12 + | +LL | matche a {} + | ^ expected one of 8 possible tokens + | +help: there is a keyword `match` with a similar name + | +LL | match a {} + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/mod.rs b/tests/ui/parser/misspelled-keywords/mod.rs new file mode 100644 index 0000000000000..24f0101bc5aaa --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/mod.rs @@ -0,0 +1,4 @@ +mode parser; +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/mod.stderr b/tests/ui/parser/misspelled-keywords/mod.stderr new file mode 100644 index 0000000000000..6daeb4e5a152e --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/mod.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `parser` + --> $DIR/mod.rs:1:6 + | +LL | mode parser; + | ^^^^^^ expected one of `!` or `::` + | +help: there is a keyword `mod` with a similar name + | +LL | mod parser; + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/pub-fn.rs b/tests/ui/parser/misspelled-keywords/pub-fn.rs new file mode 100644 index 0000000000000..50d7129ce51ee --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/pub-fn.rs @@ -0,0 +1,5 @@ +puB fn code() {} +//~^ ERROR expected one of + +fn main() { +} diff --git a/tests/ui/parser/misspelled-keywords/pub-fn.stderr b/tests/ui/parser/misspelled-keywords/pub-fn.stderr new file mode 100644 index 0000000000000..82ca7105a4965 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/pub-fn.stderr @@ -0,0 +1,13 @@ +error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern`, `fn`, `gen`, `impl`, `macro_rules`, `macro`, `mod`, `pub`, `safe`, `static`, `struct`, `trait`, `type`, `unsafe`, or `use`, found `puB` + --> $DIR/pub-fn.rs:1:1 + | +LL | puB fn code() {} + | ^^^ expected one of 21 possible tokens + | +help: write keyword `pub` in lowercase + | +LL | pub fn code() {} + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/ref.rs b/tests/ui/parser/misspelled-keywords/ref.rs new file mode 100644 index 0000000000000..76b367ae99b75 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/ref.rs @@ -0,0 +1,9 @@ +fn main() { + let a = Some(vec![1, 2]); + match a { + Some(refe list) => println!("{list:?}"), + //~^ ERROR expected one of + //~| ERROR this pattern has 2 fields, + _ => println!("none"), + } +} diff --git a/tests/ui/parser/misspelled-keywords/ref.stderr b/tests/ui/parser/misspelled-keywords/ref.stderr new file mode 100644 index 0000000000000..b8b52702314c8 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/ref.stderr @@ -0,0 +1,23 @@ +error: expected one of `)`, `,`, `@`, or `|`, found `list` + --> $DIR/ref.rs:4:19 + | +LL | Some(refe list) => println!("{list:?}"), + | ^^^^ expected one of `)`, `,`, `@`, or `|` + | +help: there is a keyword `ref` with a similar name + | +LL | Some(ref list) => println!("{list:?}"), + | ~~~ + +error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field + --> $DIR/ref.rs:4:14 + | +LL | Some(refe list) => println!("{list:?}"), + | ^^^^ ^^^^ expected 1 field, found 2 + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: tuple variant has 1 field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0023`. diff --git a/tests/ui/parser/misspelled-keywords/return.rs b/tests/ui/parser/misspelled-keywords/return.rs new file mode 100644 index 0000000000000..4bbe55d37da72 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/return.rs @@ -0,0 +1,7 @@ +fn code() -> u8 { + let a = 10; + returnn a; + //~^ ERROR expected one of +} + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/return.stderr b/tests/ui/parser/misspelled-keywords/return.stderr new file mode 100644 index 0000000000000..efa45f3229909 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/return.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/return.rs:3:13 + | +LL | returnn a; + | ^ expected one of 8 possible tokens + | +help: there is a keyword `return` with a similar name + | +LL | return a; + | ~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/static-mut.rs b/tests/ui/parser/misspelled-keywords/static-mut.rs new file mode 100644 index 0000000000000..6509f62470a9c --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/static-mut.rs @@ -0,0 +1,5 @@ +static muta a: u8 = 0; +//~^ ERROR expected one of +//~| ERROR missing type for + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/static-mut.stderr b/tests/ui/parser/misspelled-keywords/static-mut.stderr new file mode 100644 index 0000000000000..3c25af548a3df --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/static-mut.stderr @@ -0,0 +1,24 @@ +error: expected one of `:`, `;`, or `=`, found `a` + --> $DIR/static-mut.rs:1:13 + | +LL | static muta a: u8 = 0; + | ^ expected one of `:`, `;`, or `=` + | +help: there is a keyword `mut` with a similar name + | +LL | static mut a: u8 = 0; + | ~~~ + +error: missing type for `static` item + --> $DIR/static-mut.rs:1:12 + | +LL | static muta a: u8 = 0; + | ^ + | +help: provide a type for the item + | +LL | static muta: a: u8 = 0; + | ++++++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/misspelled-keywords/static.rs b/tests/ui/parser/misspelled-keywords/static.rs new file mode 100644 index 0000000000000..240f4f52c8dc8 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/static.rs @@ -0,0 +1,4 @@ +Static a = 0; +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/static.stderr b/tests/ui/parser/misspelled-keywords/static.stderr new file mode 100644 index 0000000000000..003aa3929bc22 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/static.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `a` + --> $DIR/static.rs:1:8 + | +LL | Static a = 0; + | ^ expected one of `!` or `::` + | +help: write keyword `static` in lowercase (notice the capitalization difference) + | +LL | static a = 0; + | ~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/struct.rs b/tests/ui/parser/misspelled-keywords/struct.rs new file mode 100644 index 0000000000000..0f64dec6f56b3 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/struct.rs @@ -0,0 +1,4 @@ +Struct Foor { +//~^ ERROR expected one of + hello: String, +} diff --git a/tests/ui/parser/misspelled-keywords/struct.stderr b/tests/ui/parser/misspelled-keywords/struct.stderr new file mode 100644 index 0000000000000..559182f9c8f68 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/struct.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `Foor` + --> $DIR/struct.rs:1:8 + | +LL | Struct Foor { + | ^^^^ expected one of `!` or `::` + | +help: write keyword `struct` in lowercase (notice the capitalization difference) + | +LL | struct Foor { + | ~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/unsafe-fn.rs b/tests/ui/parser/misspelled-keywords/unsafe-fn.rs new file mode 100644 index 0000000000000..49a1322ad637f --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/unsafe-fn.rs @@ -0,0 +1,4 @@ +unsafee fn code() {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr b/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr new file mode 100644 index 0000000000000..b13281b039511 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found keyword `fn` + --> $DIR/unsafe-fn.rs:1:9 + | +LL | unsafee fn code() {} + | ^^ expected one of `!` or `::` + | +help: there is a keyword `unsafe` with a similar name + | +LL | unsafe fn code() {} + | ~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/use.rs b/tests/ui/parser/misspelled-keywords/use.rs new file mode 100644 index 0000000000000..f4911654354e2 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/use.rs @@ -0,0 +1,4 @@ +usee a::b; +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/use.stderr b/tests/ui/parser/misspelled-keywords/use.stderr new file mode 100644 index 0000000000000..db6dffdb613c5 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/use.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `a` + --> $DIR/use.rs:1:6 + | +LL | usee a::b; + | ^ expected one of `!` or `::` + | +help: there is a keyword `use` with a similar name + | +LL | use a::b; + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/where-clause.rs b/tests/ui/parser/misspelled-keywords/where-clause.rs new file mode 100644 index 0000000000000..c03d04d5fee50 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/where-clause.rs @@ -0,0 +1,8 @@ +fn code() -> u8 +wheree +//~^ ERROR expected one of + T: Debug, +{ +} + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/where-clause.stderr b/tests/ui/parser/misspelled-keywords/where-clause.stderr new file mode 100644 index 0000000000000..5143c30ca5103 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/where-clause.stderr @@ -0,0 +1,15 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `wheree` + --> $DIR/where-clause.rs:2:1 + | +LL | fn code() -> u8 + | - expected one of 7 possible tokens +LL | wheree + | ^^^^^^ unexpected token + | +help: there is a keyword `where` with a similar name + | +LL | where + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/while-loop.rs b/tests/ui/parser/misspelled-keywords/while-loop.rs new file mode 100644 index 0000000000000..37d337f3f1959 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/while-loop.rs @@ -0,0 +1,5 @@ +fn main() { + whilee a < b { + //~^ ERROR expected one of + } +} diff --git a/tests/ui/parser/misspelled-keywords/while-loop.stderr b/tests/ui/parser/misspelled-keywords/while-loop.stderr new file mode 100644 index 0000000000000..7d150443f57e7 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/while-loop.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/while-loop.rs:2:12 + | +LL | whilee a < b { + | ^ expected one of 8 possible tokens + | +help: there is a keyword `while` with a similar name + | +LL | while a < b { + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/while-without-identifiers.rs b/tests/ui/parser/misspelled-keywords/while-without-identifiers.rs new file mode 100644 index 0000000000000..203db8306af9c --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/while-without-identifiers.rs @@ -0,0 +1,4 @@ +fn main() { + whilee 2 > 1 {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/while-without-identifiers.stderr b/tests/ui/parser/misspelled-keywords/while-without-identifiers.stderr new file mode 100644 index 0000000000000..121e39313148a --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/while-without-identifiers.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `2` + --> $DIR/while-without-identifiers.rs:2:12 + | +LL | whilee 2 > 1 {} + | ^ expected one of 8 possible tokens + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 10c638a63e44c..892883c4aedca 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -1,8 +1,8 @@ error: expected a pattern, found an expression - --> $DIR/pat-lt-bracket-6.rs:5:15 + --> $DIR/pat-lt-bracket-6.rs:5:14 | LL | let Test(&desc[..]) = x; - | ^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^ arbitrary expressions are not allowed in patterns error[E0308]: mismatched types --> $DIR/pat-lt-bracket-6.rs:10:30 diff --git a/tests/ui/parser/pat-recover-exprs.rs b/tests/ui/parser/pat-recover-exprs.rs deleted file mode 100644 index ecd471467e380..0000000000000 --- a/tests/ui/parser/pat-recover-exprs.rs +++ /dev/null @@ -1,28 +0,0 @@ -fn main() { - match u8::MAX { - u8::MAX.abs() => (), - //~^ error: expected a pattern, found a method call - x.sqrt() @ .. => (), - //~^ error: expected a pattern, found a method call - //~| error: left-hand side of `@` must be a binding - z @ w @ v.u() => (), - //~^ error: expected a pattern, found a method call - y.ilog(3) => (), - //~^ error: expected a pattern, found a method call - n + 1 => (), - //~^ error: expected a pattern, found an expression - ("".f() + 14 * 8) => (), - //~^ error: expected a pattern, found an expression - 0 | ((1) | 2) | 3 => (), - f?() => (), - //~^ error: expected a pattern, found an expression - (_ + 1) => (), - //~^ error: expected one of `)`, `,`, or `|`, found `+` - } - - let 1 + 1 = 2; - //~^ error: expected a pattern, found an expression - - let b = matches!(x, (x * x | x.f()) | x[0]); - //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*` -} diff --git a/tests/ui/parser/pat-recover-exprs.stderr b/tests/ui/parser/pat-recover-exprs.stderr deleted file mode 100644 index 787fd03b0c30d..0000000000000 --- a/tests/ui/parser/pat-recover-exprs.stderr +++ /dev/null @@ -1,76 +0,0 @@ -error: expected a pattern, found a method call - --> $DIR/pat-recover-exprs.rs:3:9 - | -LL | u8::MAX.abs() => (), - | ^^^^^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-exprs.rs:5:9 - | -LL | x.sqrt() @ .. => (), - | ^^^^^^^^ method calls are not allowed in patterns - -error: left-hand side of `@` must be a binding - --> $DIR/pat-recover-exprs.rs:5:9 - | -LL | x.sqrt() @ .. => (), - | --------^^^-- - | | | - | | also a pattern - | interpreted as a pattern, not a binding - | - = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` - -error: expected a pattern, found a method call - --> $DIR/pat-recover-exprs.rs:8:17 - | -LL | z @ w @ v.u() => (), - | ^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-exprs.rs:10:9 - | -LL | y.ilog(3) => (), - | ^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found an expression - --> $DIR/pat-recover-exprs.rs:12:9 - | -LL | n + 1 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns - -error: expected a pattern, found an expression - --> $DIR/pat-recover-exprs.rs:14:10 - | -LL | ("".f() + 14 * 8) => (), - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns - -error: expected a pattern, found an expression - --> $DIR/pat-recover-exprs.rs:17:9 - | -LL | f?() => (), - | ^^^^ arbitrary expressions are not allowed in patterns - -error: expected one of `)`, `,`, or `|`, found `+` - --> $DIR/pat-recover-exprs.rs:19:12 - | -LL | (_ + 1) => (), - | ^ expected one of `)`, `,`, or `|` - -error: expected a pattern, found an expression - --> $DIR/pat-recover-exprs.rs:23:9 - | -LL | let 1 + 1 = 2; - | ^^^^^ arbitrary expressions are not allowed in patterns - -error: expected one of `)`, `,`, `@`, or `|`, found `*` - --> $DIR/pat-recover-exprs.rs:26:28 - | -LL | let b = matches!(x, (x * x | x.f()) | x[0]); - | ^ expected one of `)`, `,`, `@`, or `|` - --> $SRC_DIR/core/src/macros/mod.rs:LL:COL - | - = note: while parsing argument for this `pat` macro fragment - -error: aborting due to 11 previous errors - diff --git a/tests/ui/parser/pat-recover-methodcalls.rs b/tests/ui/parser/pat-recover-methodcalls.rs deleted file mode 100644 index 54104e9a53559..0000000000000 --- a/tests/ui/parser/pat-recover-methodcalls.rs +++ /dev/null @@ -1,37 +0,0 @@ -struct Foo(String); -struct Bar { baz: String } - -fn foo(foo: Foo) -> bool { - match foo { - Foo("hi".to_owned()) => true, - //~^ error: expected a pattern, found a method call - _ => false - } -} - -fn bar(bar: Bar) -> bool { - match bar { - Bar { baz: "hi".to_owned() } => true, - //~^ error: expected a pattern, found a method call - _ => false - } -} - -fn baz() { // issue #90121 - let foo = vec!["foo".to_string()]; - - match foo.as_slice() { - &["foo".to_string()] => {} - //~^ error: expected a pattern, found a method call - _ => {} - }; -} - -fn main() { - if let (-1.some(4)) = (0, Some(4)) {} - //~^ error: expected a pattern, found a method call - - if let (-1.Some(4)) = (0, Some(4)) {} - //~^ error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` - //~| help: missing `,` -} diff --git a/tests/ui/parser/pat-recover-methodcalls.stderr b/tests/ui/parser/pat-recover-methodcalls.stderr deleted file mode 100644 index 1f9ae81dc0c55..0000000000000 --- a/tests/ui/parser/pat-recover-methodcalls.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error: expected a pattern, found a method call - --> $DIR/pat-recover-methodcalls.rs:6:13 - | -LL | Foo("hi".to_owned()) => true, - | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-methodcalls.rs:14:20 - | -LL | Bar { baz: "hi".to_owned() } => true, - | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-methodcalls.rs:24:11 - | -LL | &["foo".to_string()] => {} - | ^^^^^^^^^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-methodcalls.rs:31:13 - | -LL | if let (-1.some(4)) = (0, Some(4)) {} - | ^^^^^^^^^^ method calls are not allowed in patterns - -error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` - --> $DIR/pat-recover-methodcalls.rs:34:15 - | -LL | if let (-1.Some(4)) = (0, Some(4)) {} - | ^ - | | - | expected one of `)`, `,`, `...`, `..=`, `..`, or `|` - | help: missing `,` - -error: aborting due to 5 previous errors - diff --git a/tests/ui/parser/pat-recover-ranges.stderr b/tests/ui/parser/pat-recover-ranges.stderr deleted file mode 100644 index a7d62bd7f8ad2..0000000000000 --- a/tests/ui/parser/pat-recover-ranges.stderr +++ /dev/null @@ -1,132 +0,0 @@ -error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:4:13 - | -LL | 0..=(1) => (), - | ^ ^ - | -help: remove these parentheses - | -LL - 0..=(1) => (), -LL + 0..=1 => (), - | - -error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:6:9 - | -LL | (-12)..=4 => (), - | ^ ^ - | -help: remove these parentheses - | -LL - (-12)..=4 => (), -LL + -12..=4 => (), - | - -error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:8:9 - | -LL | (0)..=(-4) => (), - | ^ ^ - | -help: remove these parentheses - | -LL - (0)..=(-4) => (), -LL + 0..=(-4) => (), - | - -error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:8:15 - | -LL | (0)..=(-4) => (), - | ^ ^ - | -help: remove these parentheses - | -LL - (0)..=(-4) => (), -LL + (0)..=-4 => (), - | - -error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-ranges.rs:11:12 - | -LL | ..=1 + 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns - -error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:13:9 - | -LL | (4).. => (), - | ^ ^ - | -help: remove these parentheses - | -LL - (4).. => (), -LL + 4.. => (), - | - -error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-ranges.rs:15:10 - | -LL | (-4 + 0).. => (), - | ^^^^^^ arbitrary expressions are not allowed in patterns - -error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:15:9 - | -LL | (-4 + 0).. => (), - | ^ ^ - | -help: remove these parentheses - | -LL - (-4 + 0).. => (), -LL + -4 + 0.. => (), - | - -error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-ranges.rs:18:10 - | -LL | (1 + 4)...1 * 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns - -error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:18:9 - | -LL | (1 + 4)...1 * 2 => (), - | ^ ^ - | -help: remove these parentheses - | -LL - (1 + 4)...1 * 2 => (), -LL + 1 + 4...1 * 2 => (), - | - -error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-ranges.rs:18:19 - | -LL | (1 + 4)...1 * 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns - -error: expected a pattern range bound, found a method call - --> $DIR/pat-recover-ranges.rs:24:9 - | -LL | 0.x()..="y".z() => (), - | ^^^^^ method calls are not allowed in patterns - -error: expected a pattern range bound, found a method call - --> $DIR/pat-recover-ranges.rs:24:17 - | -LL | 0.x()..="y".z() => (), - | ^^^^^^^ method calls are not allowed in patterns - -warning: `...` range patterns are deprecated - --> $DIR/pat-recover-ranges.rs:18:16 - | -LL | (1 + 4)...1 * 2 => (), - | ^^^ help: use `..=` for an inclusive range - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see - = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default - -error: aborting due to 13 previous errors; 1 warning emitted - diff --git a/tests/ui/parser/recover/recover-from-bad-variant.stderr b/tests/ui/parser/recover/recover-from-bad-variant.stderr index 04968bbdf999d..0339f86951543 100644 --- a/tests/ui/parser/recover/recover-from-bad-variant.stderr +++ b/tests/ui/parser/recover/recover-from-bad-variant.stderr @@ -19,6 +19,11 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `Enum | LL | Enum::Foo(a, b) => {} | ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: the struct variant's fields are being ignored + | +LL | Enum::Foo { a: _, b: _ } => {} + | ~~~~~~~~~~~~~~ error[E0769]: tuple variant `Enum::Bar` written as struct variant --> $DIR/recover-from-bad-variant.rs:12:9 diff --git a/tests/ui/parser/recover/recover-pat-exprs.rs b/tests/ui/parser/recover/recover-pat-exprs.rs new file mode 100644 index 0000000000000..e5e25df0c01cc --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-exprs.rs @@ -0,0 +1,106 @@ +// FieldExpression, TupleIndexingExpression +fn field_access() { + match 0 { + x => (), + x.y => (), //~ error: expected a pattern, found an expression + x.0 => (), //~ error: expected a pattern, found an expression + x._0 => (), //~ error: expected a pattern, found an expression + x.0.1 => (), //~ error: expected a pattern, found an expression + x.4.y.17.__z => (), //~ error: expected a pattern, found an expression + } + + { let x.0e0; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + { let x.-0.0; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + { let x.-0; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + + { let x.0u32; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + { let x.0.0_f64; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` +} + +// IndexExpression, ArrayExpression +fn array_indexing() { + match 0 { + x[0] => (), //~ error: expected a pattern, found an expression + x[..] => (), //~ error: expected a pattern, found an expression + } + + { let x[0, 1, 2]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + { let x[0; 20]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + { let x[]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + { let (x[]); } //~ error: expected one of `)`, `,`, `@`, or `|`, found `[` + //~^ missing `,` +} + +// MethodCallExpression, CallExpression, ErrorPropagationExpression +fn method_call() { + match 0 { + x.f() => (), //~ error: expected a pattern, found an expression + x._f() => (), //~ error: expected a pattern, found an expression + x? => (), //~ error: expected a pattern, found an expression + ().f() => (), //~ error: expected a pattern, found an expression + (0, x)?.f() => (), //~ error: expected a pattern, found an expression + x.f().g() => (), //~ error: expected a pattern, found an expression + 0.f()?.g()?? => (), //~ error: expected a pattern, found an expression + } +} + +// TypeCastExpression +fn type_cast() { + match 0 { + x as usize => (), //~ error: expected a pattern, found an expression + 0 as usize => (), //~ error: expected a pattern, found an expression + x.f().0.4 as f32 => (), //~ error: expected a pattern, found an expression + } +} + +// ArithmeticOrLogicalExpression, also check if parentheses are added as needed +fn operator() { + match 0 { + 1 + 1 => (), //~ error: expected a pattern, found an expression + (1 + 2) * 3 => (), + //~^ error: expected a pattern, found an expression + //~| error: expected a pattern, found an expression + x.0 > 2 => (), //~ error: expected a pattern, found an expression + x.0 == 2 => (), //~ error: expected a pattern, found an expression + } + + // preexisting match arm guard + match (0, 0) { + (x, y.0 > 2) if x != 0 => (), //~ error: expected a pattern, found an expression + (x, y.0 > 2) if x != 0 || x != 1 => (), //~ error: expected a pattern, found an expression + } +} + +const _: u32 = match 12 { + 1 + 2 * PI.cos() => 2, //~ error: expected a pattern, found an expression + _ => 0, +}; + +fn main() { + match u8::MAX { + u8::MAX.abs() => (), + //~^ error: expected a pattern, found an expression + x.sqrt() @ .. => (), + //~^ error: expected a pattern, found an expression + //~| error: left-hand side of `@` must be a binding + z @ w @ v.u() => (), + //~^ error: expected a pattern, found an expression + y.ilog(3) => (), + //~^ error: expected a pattern, found an expression + n + 1 => (), + //~^ error: expected a pattern, found an expression + ("".f() + 14 * 8) => (), + //~^ error: expected a pattern, found an expression + 0 | ((1) | 2) | 3 => (), + f?() => (), + //~^ error: expected a pattern, found an expression + (_ + 1) => (), + //~^ error: expected one of `)`, `,`, or `|`, found `+` + } + + let 1 + 1 = 2; + //~^ error: expected a pattern, found an expression + + let b = matches!(x, (x * x | x.f()) | x[0]); + //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*` +} diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr new file mode 100644 index 0000000000000..63956f35c079f --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-exprs.stderr @@ -0,0 +1,772 @@ +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:5:9 + | +LL | x.y => (), + | ^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.y => (), + | ~~~ +++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.y; +LL ~ match 0 { +LL | x => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.y } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:6:9 + | +LL | x.0 => (), + | ^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.0 => (), + | ~~~ +++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.0; +LL ~ match 0 { +LL | x => (), +LL | x.y => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.0 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:7:9 + | +LL | x._0 => (), + | ^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x._0 => (), + | ~~~ ++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x._0; +LL ~ match 0 { +LL | x => (), +LL | x.y => (), +LL | x.0 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x._0 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:8:9 + | +LL | x.0.1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.0.1 => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.0.1; +LL ~ match 0 { +LL | x => (), +... +LL | x._0 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.0.1 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:9:9 + | +LL | x.4.y.17.__z => (), + | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.4.y.17.__z => (), + | ~~~ ++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.4.y.17.__z; +LL ~ match 0 { +LL | x => (), +... +LL | x.0.1 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.4.y.17.__z } => (), + | +++++++ + + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:12:12 + | +LL | { let x.0e0; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:13:12 + | +LL | { let x.-0.0; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:14:12 + | +LL | { let x.-0; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:16:12 + | +LL | { let x.0u32; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:17:12 + | +LL | { let x.0.0_f64; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:23:9 + | +LL | x[0] => (), + | ^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x[0] => (), + | ~~~ ++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x[0]; +LL ~ match 0 { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x[0] } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:24:9 + | +LL | x[..] => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x[..] => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x[..]; +LL ~ match 0 { +LL | x[0] => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x[..] } => (), + | +++++++ + + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + --> $DIR/recover-pat-exprs.rs:27:12 + | +LL | { let x[0, 1, 2]; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + --> $DIR/recover-pat-exprs.rs:28:12 + | +LL | { let x[0; 20]; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + --> $DIR/recover-pat-exprs.rs:29:12 + | +LL | { let x[]; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `)`, `,`, `@`, or `|`, found `[` + --> $DIR/recover-pat-exprs.rs:30:13 + | +LL | { let (x[]); } + | ^ + | | + | expected one of `)`, `,`, `@`, or `|` + | help: missing `,` + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:37:9 + | +LL | x.f() => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.f() => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.f(); +LL ~ match 0 { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.f() } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:38:9 + | +LL | x._f() => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x._f() => (), + | ~~~ ++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x._f(); +LL ~ match 0 { +LL | x.f() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x._f() } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:39:9 + | +LL | x? => (), + | ^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x? => (), + | ~~~ ++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x?; +LL ~ match 0 { +LL | x.f() => (), +LL | x._f() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x? } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:40:9 + | +LL | ().f() => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == ().f() => (), + | ~~~ ++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = ().f(); +LL ~ match 0 { +LL | x.f() => (), +LL | x._f() => (), +LL | x? => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { ().f() } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:41:9 + | +LL | (0, x)?.f() => (), + | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == (0, x)?.f() => (), + | ~~~ +++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = (0, x)?.f(); +LL ~ match 0 { +LL | x.f() => (), +... +LL | ().f() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { (0, x)?.f() } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:42:9 + | +LL | x.f().g() => (), + | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.f().g() => (), + | ~~~ +++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.f().g(); +LL ~ match 0 { +LL | x.f() => (), +... +LL | (0, x)?.f() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.f().g() } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:43:9 + | +LL | 0.f()?.g()?? => (), + | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == 0.f()?.g()?? => (), + | ~~~ ++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 0.f()?.g()??; +LL ~ match 0 { +LL | x.f() => (), +... +LL | x.f().g() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { 0.f()?.g()?? } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:50:9 + | +LL | x as usize => (), + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x as usize => (), + | ~~~ ++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x as usize; +LL ~ match 0 { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x as usize } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:51:9 + | +LL | 0 as usize => (), + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == 0 as usize => (), + | ~~~ ++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 0 as usize; +LL ~ match 0 { +LL | x as usize => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { 0 as usize } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:52:9 + | +LL | x.f().0.4 as f32 => (), + | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.f().0.4 as f32 => (), + | ~~~ ++++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.f().0.4 as f32; +LL ~ match 0 { +LL | x as usize => (), +LL | 0 as usize => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.f().0.4 as f32 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:59:9 + | +LL | 1 + 1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == 1 + 1 => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 1; +LL ~ match 0 { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { 1 + 1 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:60:9 + | +LL | (1 + 2) * 3 => (), + | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == (1 + 2) * 3 => (), + | ~~~ +++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = (1 + 2) * 3; +LL ~ match 0 { +LL | 1 + 1 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { (1 + 2) * 3 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:63:9 + | +LL | x.0 > 2 => (), + | ^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == (x.0 > 2) => (), + | ~~~ +++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.0 > 2; +LL ~ match 0 { +LL | 1 + 1 => (), +... +LL | +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.0 > 2 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:64:9 + | +LL | x.0 == 2 => (), + | ^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == (x.0 == 2) => (), + | ~~~ ++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.0 == 2; +LL ~ match 0 { +LL | 1 + 1 => (), +... +LL | x.0 > 2 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.0 == 2 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:69:13 + | +LL | (x, y.0 > 2) if x != 0 => (), + | ^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to the match arm guard + | +LL | (x, val) if x != 0 && val == (y.0 > 2) => (), + | ~~~ +++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = y.0 > 2; +LL ~ match (0, 0) { +LL ~ (x, VAL) if x != 0 => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (x, const { y.0 > 2 }) if x != 0 => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:70:13 + | +LL | (x, y.0 > 2) if x != 0 || x != 1 => (), + | ^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to the match arm guard + | +LL | (x, val) if (x != 0 || x != 1) && val == (y.0 > 2) => (), + | ~~~ + +++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = y.0 > 2; +LL ~ match (0, 0) { +LL | (x, y.0 > 2) if x != 0 => (), +LL ~ (x, VAL) if x != 0 || x != 1 => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (x, const { y.0 > 2 }) if x != 0 || x != 1 => (), + | +++++++ + + +error: left-hand side of `@` must be a binding + --> $DIR/recover-pat-exprs.rs:83:9 + | +LL | x.sqrt() @ .. => (), + | --------^^^-- + | | | + | | also a pattern + | interpreted as a pattern, not a binding + | + = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +error: expected one of `)`, `,`, or `|`, found `+` + --> $DIR/recover-pat-exprs.rs:97:12 + | +LL | (_ + 1) => (), + | ^ expected one of `)`, `,`, or `|` + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:81:9 + | +LL | u8::MAX.abs() => (), + | ^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == u8::MAX.abs() => (), + | ~~~ +++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = u8::MAX.abs(); +LL ~ match u8::MAX { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { u8::MAX.abs() } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:86:17 + | +LL | z @ w @ v.u() => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | z @ w @ val if val == v.u() => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = v.u(); +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | +LL ~ z @ w @ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | z @ w @ const { v.u() } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:88:9 + | +LL | y.ilog(3) => (), + | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == y.ilog(3) => (), + | ~~~ +++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = y.ilog(3); +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { y.ilog(3) } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:90:9 + | +LL | n + 1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == n + 1 => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = n + 1; +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { n + 1 } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:92:10 + | +LL | ("".f() + 14 * 8) => (), + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | (val) if val == "".f() + 14 * 8 => (), + | ~~~ +++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = "".f() + 14 * 8; +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | +LL ~ (VAL) => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (const { "".f() + 14 * 8 }) => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:95:9 + | +LL | f?() => (), + | ^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == f?() => (), + | ~~~ ++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = f?(); +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | 0 | ((1) | 2) | 3 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { f?() } => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:101:9 + | +LL | let 1 + 1 = 2; + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, `@`, or `|`, found `*` + --> $DIR/recover-pat-exprs.rs:104:28 + | +LL | let b = matches!(x, (x * x | x.f()) | x[0]); + | ^ expected one of `)`, `,`, `@`, or `|` + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | + = note: while parsing argument for this `pat` macro fragment + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:60:10 + | +LL | (1 + 2) * 3 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:75:5 + | +LL | 1 + 2 * PI.cos() => 2, + | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:83:9 + | +LL | x.sqrt() @ .. => (), + | ^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: aborting due to 45 previous errors + diff --git a/tests/ui/parser/recover/recover-pat-issues.rs b/tests/ui/parser/recover/recover-pat-issues.rs new file mode 100644 index 0000000000000..5b900fe80e516 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-issues.rs @@ -0,0 +1,46 @@ +struct Foo(String); +struct Bar { baz: String } + +fn foo(foo: Foo) -> bool { + match foo { + Foo("hi".to_owned()) => true, + //~^ error: expected a pattern, found an expression + _ => false + } +} + +fn bar(bar: Bar) -> bool { + match bar { + Bar { baz: "hi".to_owned() } => true, + //~^ error: expected a pattern, found an expression + _ => false + } +} + +/// Issue #90121 +fn baz() { + let foo = vec!["foo".to_string()]; + + match foo.as_slice() { + &["foo".to_string()] => {} + //~^ error: expected a pattern, found an expression + _ => {} + }; +} + +/// Issue #104996 +fn qux() { + struct Magic(pub u16); + const MAGIC: Magic = Magic(42); + + if let Some(MAGIC.0 as usize) = None:: {} + //~^ error: expected a pattern, found an expression +} + +fn main() { + if let (-1.some(4)) = (0, Some(4)) {} + //~^ error: expected a pattern, found an expression + + if let (-1.Some(4)) = (0, Some(4)) {} + //~^ error: expected a pattern, found an expression +} diff --git a/tests/ui/parser/recover/recover-pat-issues.stderr b/tests/ui/parser/recover/recover-pat-issues.stderr new file mode 100644 index 0000000000000..596bff2139525 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-issues.stderr @@ -0,0 +1,113 @@ +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:6:13 + | +LL | Foo("hi".to_owned()) => true, + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | Foo(val) if val == "hi".to_owned() => true, + | ~~~ +++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = "hi".to_owned(); +LL ~ match foo { +LL ~ Foo(VAL) => true, + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | Foo(const { "hi".to_owned() }) => true, + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:14:20 + | +LL | Bar { baz: "hi".to_owned() } => true, + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | Bar { baz } if baz == "hi".to_owned() => true, + | ~~~ +++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const BAZ: /* Type */ = "hi".to_owned(); +LL ~ match bar { +LL ~ Bar { baz: BAZ } => true, + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | Bar { baz: const { "hi".to_owned() } } => true, + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:25:11 + | +LL | &["foo".to_string()] => {} + | ^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | &[val] if val == "foo".to_string() => {} + | ~~~ +++++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = "foo".to_string(); +LL ~ match foo.as_slice() { +LL ~ &[VAL] => {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | &[const { "foo".to_string() }] => {} + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:36:17 + | +LL | if let Some(MAGIC.0 as usize) = None:: {} + | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = MAGIC.0 as usize; +LL ~ if let Some(VAL) = None:: {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | if let Some(const { MAGIC.0 as usize }) = None:: {} + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:41:13 + | +LL | if let (-1.some(4)) = (0, Some(4)) {} + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = -1.some(4); +LL ~ if let (VAL) = (0, Some(4)) {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | if let (const { -1.some(4) }) = (0, Some(4)) {} + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:44:13 + | +LL | if let (-1.Some(4)) = (0, Some(4)) {} + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = -1.Some(4); +LL ~ if let (VAL) = (0, Some(4)) {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | if let (const { -1.Some(4) }) = (0, Some(4)) {} + | +++++++ + + +error: aborting due to 6 previous errors + diff --git a/tests/ui/parser/recover/recover-pat-lets.rs b/tests/ui/parser/recover/recover-pat-lets.rs new file mode 100644 index 0000000000000..6681cc25db37b --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-lets.rs @@ -0,0 +1,20 @@ +fn main() { + let x = Some(2); + + let x.expect("foo"); + //~^ error: expected a pattern, found an expression + + let x.unwrap(): u32; + //~^ error: expected a pattern, found an expression + + let x[0] = 1; + //~^ error: expected a pattern, found an expression + + let Some(1 + 1) = x else { //~ error: expected a pattern, found an expression + return; + }; + + if let Some(1 + 1) = x { //~ error: expected a pattern, found an expression + return; + } +} diff --git a/tests/ui/parser/recover/recover-pat-lets.stderr b/tests/ui/parser/recover/recover-pat-lets.stderr new file mode 100644 index 0000000000000..e54586b092483 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-lets.stderr @@ -0,0 +1,52 @@ +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:4:9 + | +LL | let x.expect("foo"); + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:7:9 + | +LL | let x.unwrap(): u32; + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:10:9 + | +LL | let x[0] = 1; + | ^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:13:14 + | +LL | let Some(1 + 1) = x else { + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 1; +LL ~ let Some(VAL) = x else { + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | let Some(const { 1 + 1 }) = x else { + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:17:17 + | +LL | if let Some(1 + 1) = x { + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 1; +LL ~ if let Some(VAL) = x { + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | if let Some(const { 1 + 1 }) = x { + | +++++++ + + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/pat-recover-ranges.rs b/tests/ui/parser/recover/recover-pat-ranges.rs similarity index 89% rename from tests/ui/parser/pat-recover-ranges.rs rename to tests/ui/parser/recover/recover-pat-ranges.rs index 7d77e950d905a..e3f061c625d3d 100644 --- a/tests/ui/parser/pat-recover-ranges.rs +++ b/tests/ui/parser/recover/recover-pat-ranges.rs @@ -22,8 +22,8 @@ fn main() { //~| warning: `...` range patterns are deprecated //~| warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! 0.x()..="y".z() => (), - //~^ error: expected a pattern range bound, found a method call - //~| error: expected a pattern range bound, found a method call + //~^ error: expected a pattern range bound, found an expression + //~| error: expected a pattern range bound, found an expression }; } diff --git a/tests/ui/parser/recover/recover-pat-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr new file mode 100644 index 0000000000000..088f83b0ccbac --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-ranges.stderr @@ -0,0 +1,216 @@ +error: range pattern bounds cannot have parentheses + --> $DIR/recover-pat-ranges.rs:4:13 + | +LL | 0..=(1) => (), + | ^ ^ + | +help: remove these parentheses + | +LL - 0..=(1) => (), +LL + 0..=1 => (), + | + +error: range pattern bounds cannot have parentheses + --> $DIR/recover-pat-ranges.rs:6:9 + | +LL | (-12)..=4 => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (-12)..=4 => (), +LL + -12..=4 => (), + | + +error: range pattern bounds cannot have parentheses + --> $DIR/recover-pat-ranges.rs:8:9 + | +LL | (0)..=(-4) => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (0)..=(-4) => (), +LL + 0..=(-4) => (), + | + +error: range pattern bounds cannot have parentheses + --> $DIR/recover-pat-ranges.rs:8:15 + | +LL | (0)..=(-4) => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (0)..=(-4) => (), +LL + (0)..=-4 => (), + | + +error: range pattern bounds cannot have parentheses + --> $DIR/recover-pat-ranges.rs:13:9 + | +LL | (4).. => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (4).. => (), +LL + 4.. => (), + | + +error: range pattern bounds cannot have parentheses + --> $DIR/recover-pat-ranges.rs:15:9 + | +LL | (-4 + 0).. => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (-4 + 0).. => (), +LL + -4 + 0.. => (), + | + +error: range pattern bounds cannot have parentheses + --> $DIR/recover-pat-ranges.rs:18:9 + | +LL | (1 + 4)...1 * 2 => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (1 + 4)...1 * 2 => (), +LL + 1 + 4...1 * 2 => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:11:12 + | +LL | ..=1 + 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 2; +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ ..=VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | ..=const { 1 + 2 } => (), + | +++++++ + + +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:15:10 + | +LL | (-4 + 0).. => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = -4 + 0; +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ (VAL).. => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (const { -4 + 0 }).. => (), + | +++++++ + + +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:18:10 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 4; +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ (VAL)...1 * 2 => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (const { 1 + 4 })...1 * 2 => (), + | +++++++ + + +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:18:19 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 * 2; +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ (1 + 4)...VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (1 + 4)...const { 1 * 2 } => (), + | +++++++ + + +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:24:9 + | +LL | 0.x()..="y".z() => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 0.x(); +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ VAL..="y".z() => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { 0.x() }..="y".z() => (), + | +++++++ + + +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:24:17 + | +LL | 0.x()..="y".z() => (), + | ^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = "y".z(); +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ 0.x()..=VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | 0.x()..=const { "y".z() } => (), + | +++++++ + + +warning: `...` range patterns are deprecated + --> $DIR/recover-pat-ranges.rs:18:16 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^ help: use `..=` for an inclusive range + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default + +error: aborting due to 13 previous errors; 1 warning emitted + diff --git a/tests/ui/parser/pat-recover-wildcards.rs b/tests/ui/parser/recover/recover-pat-wildcards.rs similarity index 100% rename from tests/ui/parser/pat-recover-wildcards.rs rename to tests/ui/parser/recover/recover-pat-wildcards.rs diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/recover/recover-pat-wildcards.stderr similarity index 70% rename from tests/ui/parser/pat-recover-wildcards.stderr rename to tests/ui/parser/recover/recover-pat-wildcards.stderr index e36ff237bb00a..30307726a973b 100644 --- a/tests/ui/parser/pat-recover-wildcards.stderr +++ b/tests/ui/parser/recover/recover-pat-wildcards.stderr @@ -1,35 +1,35 @@ error: expected one of `=>`, `if`, or `|`, found `+` - --> $DIR/pat-recover-wildcards.rs:5:11 + --> $DIR/recover-pat-wildcards.rs:5:11 | LL | _ + 1 => () | ^ expected one of `=>`, `if`, or `|` error: expected one of `)`, `,`, or `|`, found `%` - --> $DIR/pat-recover-wildcards.rs:11:12 + --> $DIR/recover-pat-wildcards.rs:11:12 | LL | (_ % 4) => () | ^ expected one of `)`, `,`, or `|` error: expected one of `=>`, `if`, or `|`, found `.` - --> $DIR/pat-recover-wildcards.rs:17:10 + --> $DIR/recover-pat-wildcards.rs:17:10 | LL | _.x() => () | ^ expected one of `=>`, `if`, or `|` error: expected one of `=>`, `if`, or `|`, found `..=` - --> $DIR/pat-recover-wildcards.rs:23:10 + --> $DIR/recover-pat-wildcards.rs:23:10 | LL | _..=4 => () | ^^^ expected one of `=>`, `if`, or `|` error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` - --> $DIR/pat-recover-wildcards.rs:29:11 + --> $DIR/recover-pat-wildcards.rs:29:11 | LL | .._ => () | ^ expected one of `=>`, `if`, or `|` error[E0586]: inclusive range with no end - --> $DIR/pat-recover-wildcards.rs:35:10 + --> $DIR/recover-pat-wildcards.rs:35:10 | LL | 0..._ => () | ^^^ @@ -42,31 +42,25 @@ LL + 0.._ => () | error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` - --> $DIR/pat-recover-wildcards.rs:35:13 + --> $DIR/recover-pat-wildcards.rs:35:13 | LL | 0..._ => () | ^ expected one of `=>`, `if`, or `|` error: expected one of `)`, `,`, or `|`, found `*` - --> $DIR/pat-recover-wildcards.rs:43:12 + --> $DIR/recover-pat-wildcards.rs:43:12 | LL | (_ * 0)..5 => () | ^ expected one of `)`, `,`, or `|` error: expected one of `=>`, `if`, or `|`, found `(` - --> $DIR/pat-recover-wildcards.rs:49:11 + --> $DIR/recover-pat-wildcards.rs:49:11 | LL | ..(_) => () | ^ expected one of `=>`, `if`, or `|` -error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-wildcards.rs:55:14 - | -LL | 4..=(2 + _) => () - | ^^^^^ arbitrary expressions are not allowed in patterns - error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-wildcards.rs:55:13 + --> $DIR/recover-pat-wildcards.rs:55:13 | LL | 4..=(2 + _) => () | ^ ^ @@ -77,6 +71,23 @@ LL - 4..=(2 + _) => () LL + 4..=2 + _ => () | +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-wildcards.rs:55:14 + | +LL | 4..=(2 + _) => () + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 2 + _; +LL ~ match 9 { +LL ~ 4..=(VAL) => () + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | 4..=(const { 2 + _ }) => () + | +++++++ + + error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0586`. diff --git a/tests/ui/parser/triple-colon-delegation.fixed b/tests/ui/parser/triple-colon-delegation.fixed new file mode 100644 index 0000000000000..fbb614b57daa3 --- /dev/null +++ b/tests/ui/parser/triple-colon-delegation.fixed @@ -0,0 +1,44 @@ +//@ run-rustfix + +#![feature(fn_delegation)] +#![allow(incomplete_features, unused)] + +trait Trait { + fn foo(&self) {} +} + +struct F; +impl Trait for F {} + +pub mod to_reuse { + pub fn bar() {} +} + +mod fn_to_other { + use super::*; + + reuse Trait::foo; //~ ERROR path separator must be a double colon + reuse to_reuse::bar; //~ ERROR path separator must be a double colon +} + +impl Trait for u8 {} + +struct S(u8); + +mod to_import { + pub fn check(arg: &u8) -> &u8 { arg } +} + +impl Trait for S { + reuse Trait::* { //~ ERROR path separator must be a double colon + use to_import::check; + + let _arr = Some(self.0).map(|x| [x * 2; 3]); + check(&self.0) + } +} + +fn main() { + let s = S(0); + s.foo(); +} diff --git a/tests/ui/parser/triple-colon-delegation.rs b/tests/ui/parser/triple-colon-delegation.rs new file mode 100644 index 0000000000000..9fbaa4477ae75 --- /dev/null +++ b/tests/ui/parser/triple-colon-delegation.rs @@ -0,0 +1,44 @@ +//@ run-rustfix + +#![feature(fn_delegation)] +#![allow(incomplete_features, unused)] + +trait Trait { + fn foo(&self) {} +} + +struct F; +impl Trait for F {} + +pub mod to_reuse { + pub fn bar() {} +} + +mod fn_to_other { + use super::*; + + reuse Trait:::foo; //~ ERROR path separator must be a double colon + reuse to_reuse:::bar; //~ ERROR path separator must be a double colon +} + +impl Trait for u8 {} + +struct S(u8); + +mod to_import { + pub fn check(arg: &u8) -> &u8 { arg } +} + +impl Trait for S { + reuse Trait:::* { //~ ERROR path separator must be a double colon + use to_import::check; + + let _arr = Some(self.0).map(|x| [x * 2; 3]); + check(&self.0) + } +} + +fn main() { + let s = S(0); + s.foo(); +} diff --git a/tests/ui/parser/triple-colon-delegation.stderr b/tests/ui/parser/triple-colon-delegation.stderr new file mode 100644 index 0000000000000..d748c7d92b5bc --- /dev/null +++ b/tests/ui/parser/triple-colon-delegation.stderr @@ -0,0 +1,38 @@ +error: path separator must be a double colon + --> $DIR/triple-colon-delegation.rs:20:18 + | +LL | reuse Trait:::foo; + | ^ + | +help: use a double colon instead + | +LL - reuse Trait:::foo; +LL + reuse Trait::foo; + | + +error: path separator must be a double colon + --> $DIR/triple-colon-delegation.rs:21:21 + | +LL | reuse to_reuse:::bar; + | ^ + | +help: use a double colon instead + | +LL - reuse to_reuse:::bar; +LL + reuse to_reuse::bar; + | + +error: path separator must be a double colon + --> $DIR/triple-colon-delegation.rs:33:18 + | +LL | reuse Trait:::* { + | ^ + | +help: use a double colon instead + | +LL - reuse Trait:::* { +LL + reuse Trait::* { + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/parser/triple-colon.fixed b/tests/ui/parser/triple-colon.fixed new file mode 100644 index 0000000000000..168e4c1f618ae --- /dev/null +++ b/tests/ui/parser/triple-colon.fixed @@ -0,0 +1,23 @@ +//@ run-rustfix + +#![allow(unused)] + +use ::std::{cell as _}; //~ ERROR path separator must be a double colon +use std::cell::*; //~ ERROR path separator must be a double colon +use std::cell::Cell; //~ ERROR path separator must be a double colon +use std::{cell as _}; //~ ERROR path separator must be a double colon + +mod foo{ + use ::{}; //~ ERROR path separator must be a double colon + use ::*; //~ ERROR path separator must be a double colon +} + +fn main() { + let c: ::std::cell::Cell:: = Cell::::new(0); + //~^ ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon +} diff --git a/tests/ui/parser/triple-colon.rs b/tests/ui/parser/triple-colon.rs new file mode 100644 index 0000000000000..1a70012685f8d --- /dev/null +++ b/tests/ui/parser/triple-colon.rs @@ -0,0 +1,23 @@ +//@ run-rustfix + +#![allow(unused)] + +use :::std::{cell as _}; //~ ERROR path separator must be a double colon +use std::cell:::*; //~ ERROR path separator must be a double colon +use std::cell:::Cell; //~ ERROR path separator must be a double colon +use std:::{cell as _}; //~ ERROR path separator must be a double colon + +mod foo{ + use :::{}; //~ ERROR path separator must be a double colon + use :::*; //~ ERROR path separator must be a double colon +} + +fn main() { + let c: :::std:::cell:::Cell::: = Cell::::::new(0); + //~^ ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon + //~| ERROR path separator must be a double colon +} diff --git a/tests/ui/parser/triple-colon.stderr b/tests/ui/parser/triple-colon.stderr new file mode 100644 index 0000000000000..8d57fd7ebc9fe --- /dev/null +++ b/tests/ui/parser/triple-colon.stderr @@ -0,0 +1,146 @@ +error: path separator must be a double colon + --> $DIR/triple-colon.rs:5:7 + | +LL | use :::std::{cell as _}; + | ^ + | +help: use a double colon instead + | +LL - use :::std::{cell as _}; +LL + use ::std::{cell as _}; + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:6:16 + | +LL | use std::cell:::*; + | ^ + | +help: use a double colon instead + | +LL - use std::cell:::*; +LL + use std::cell::*; + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:7:16 + | +LL | use std::cell:::Cell; + | ^ + | +help: use a double colon instead + | +LL - use std::cell:::Cell; +LL + use std::cell::Cell; + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:8:10 + | +LL | use std:::{cell as _}; + | ^ + | +help: use a double colon instead + | +LL - use std:::{cell as _}; +LL + use std::{cell as _}; + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:11:11 + | +LL | use :::{}; + | ^ + | +help: use a double colon instead + | +LL - use :::{}; +LL + use ::{}; + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:12:11 + | +LL | use :::*; + | ^ + | +help: use a double colon instead + | +LL - use :::*; +LL + use ::*; + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:16:14 + | +LL | let c: :::std:::cell:::Cell::: = Cell::::::new(0); + | ^ + | +help: use a double colon instead + | +LL - let c: :::std:::cell:::Cell::: = Cell::::::new(0); +LL + let c: ::std:::cell:::Cell::: = Cell::::::new(0); + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:16:20 + | +LL | let c: :::std:::cell:::Cell::: = Cell::::::new(0); + | ^ + | +help: use a double colon instead + | +LL - let c: :::std:::cell:::Cell::: = Cell::::::new(0); +LL + let c: :::std::cell:::Cell::: = Cell::::::new(0); + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:16:27 + | +LL | let c: :::std:::cell:::Cell::: = Cell::::::new(0); + | ^ + | +help: use a double colon instead + | +LL - let c: :::std:::cell:::Cell::: = Cell::::::new(0); +LL + let c: :::std:::cell::Cell::: = Cell::::::new(0); + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:16:34 + | +LL | let c: :::std:::cell:::Cell::: = Cell::::::new(0); + | ^ + | +help: use a double colon instead + | +LL - let c: :::std:::cell:::Cell::: = Cell::::::new(0); +LL + let c: :::std:::cell:::Cell:: = Cell::::::new(0); + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:16:48 + | +LL | let c: :::std:::cell:::Cell::: = Cell::::::new(0); + | ^ + | +help: use a double colon instead + | +LL - let c: :::std:::cell:::Cell::: = Cell::::::new(0); +LL + let c: :::std:::cell:::Cell::: = Cell:::::new(0); + | + +error: path separator must be a double colon + --> $DIR/triple-colon.rs:16:55 + | +LL | let c: :::std:::cell:::Cell::: = Cell::::::new(0); + | ^ + | +help: use a double colon instead + | +LL - let c: :::std:::cell:::Cell::: = Cell::::::new(0); +LL + let c: :::std:::cell:::Cell::: = Cell:::::new(0); + | + +error: aborting due to 12 previous errors + diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr index 60ab4d52c30f1..ec08e22e2ca07 100644 --- a/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr @@ -2,7 +2,10 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:17:9 | LL | _ => {} - | ^ matches no values because `EmptyEnum` is uninhabited + | ^------ + | | + | matches no values because `EmptyEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here @@ -15,7 +18,10 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:22:9 | LL | _ if false => {} - | ^ matches no values because `EmptyEnum` is uninhabited + | ^--------------- + | | + | matches no values because `EmptyEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -23,7 +29,10 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:31:9 | LL | _ => {} - | ^ matches no values because `EmptyForeignEnum` is uninhabited + | ^------ + | | + | matches no values because `EmptyForeignEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -31,7 +40,10 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:36:9 | LL | _ if false => {} - | ^ matches no values because `EmptyForeignEnum` is uninhabited + | ^--------------- + | | + | matches no values because `EmptyForeignEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr b/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr index 60ab4d52c30f1..ec08e22e2ca07 100644 --- a/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr @@ -2,7 +2,10 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:17:9 | LL | _ => {} - | ^ matches no values because `EmptyEnum` is uninhabited + | ^------ + | | + | matches no values because `EmptyEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here @@ -15,7 +18,10 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:22:9 | LL | _ if false => {} - | ^ matches no values because `EmptyEnum` is uninhabited + | ^--------------- + | | + | matches no values because `EmptyEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -23,7 +29,10 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:31:9 | LL | _ => {} - | ^ matches no values because `EmptyForeignEnum` is uninhabited + | ^------ + | | + | matches no values because `EmptyForeignEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -31,7 +40,10 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:36:9 | LL | _ if false => {} - | ^ matches no values because `EmptyForeignEnum` is uninhabited + | ^--------------- + | | + | matches no values because `EmptyForeignEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr index 9decddfe5de9a..c6e41c1875fa7 100644 --- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr @@ -2,7 +2,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:49:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here @@ -15,7 +18,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:52:9 | LL | _x => {} - | ^^ matches no values because `!` is uninhabited + | ^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -38,7 +44,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:70:9 | LL | (_, _) => {} - | ^^^^^^ matches no values because `(u32, !)` is uninhabited + | ^^^^^^------ + | | + | matches no values because `(u32, !)` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -46,7 +55,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:76:9 | LL | _ => {} - | ^ matches no values because `(!, !)` is uninhabited + | ^------ + | | + | matches no values because `(!, !)` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -54,7 +66,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:79:9 | LL | (_, _) => {} - | ^^^^^^ matches no values because `(!, !)` is uninhabited + | ^^^^^^------ + | | + | matches no values because `(!, !)` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -62,7 +77,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:83:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -89,7 +107,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:94:9 | LL | Err(_) => {} - | ^^^^^^ matches no values because `!` is uninhabited + | ^^^^^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -97,7 +118,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:99:9 | LL | Err(_) => {} - | ^^^^^^ matches no values because `!` is uninhabited + | ^^^^^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -137,7 +161,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:112:9 | LL | _ => {} - | ^ matches no values because `Result` is uninhabited + | ^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -145,7 +172,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:115:9 | LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited + | ^^^^^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -153,7 +183,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:118:9 | LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited + | ^^^^^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -161,7 +194,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:119:9 | LL | _ => {} - | ^ matches no values because `Result` is uninhabited + | ^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -169,7 +205,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:122:9 | LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited + | ^^^^^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -177,7 +216,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:123:9 | LL | Err(_) => {} - | ^^^^^^ matches no values because `Result` is uninhabited + | ^^^^^^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -185,7 +227,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:132:13 | LL | _ => {} - | ^ matches no values because `Void` is uninhabited + | ^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -193,7 +238,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:135:13 | LL | _ if false => {} - | ^ matches no values because `Void` is uninhabited + | ^--------------- + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -201,7 +249,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:143:13 | LL | Some(_) => {} - | ^^^^^^^ matches no values because `Void` is uninhabited + | ^^^^^^^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -217,7 +268,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:199:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -225,7 +279,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:204:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -233,7 +290,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:209:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -241,7 +301,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:214:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -249,7 +312,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:220:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -257,7 +323,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:281:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -265,7 +334,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:284:9 | LL | (_, _) => {} - | ^^^^^^ matches no values because `(!, !)` is uninhabited + | ^^^^^^------ + | | + | matches no values because `(!, !)` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -273,7 +345,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:287:9 | LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited + | ^^^^^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -281,7 +356,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:288:9 | LL | Err(_) => {} - | ^^^^^^ matches no values because `Result` is uninhabited + | ^^^^^^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -344,7 +422,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:368:9 | LL | _ => {} - | ^ matches no values because `[!; 3]` is uninhabited + | ^------ + | | + | matches no values because `[!; 3]` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -352,7 +433,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:371:9 | LL | [_, _, _] => {} - | ^^^^^^^^^ matches no values because `[!; 3]` is uninhabited + | ^^^^^^^^^------ + | | + | matches no values because `[!; 3]` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -360,7 +444,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:374:9 | LL | [_, ..] => {} - | ^^^^^^^ matches no values because `[!; 3]` is uninhabited + | ^^^^^^^------ + | | + | matches no values because `[!; 3]` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -404,7 +491,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:416:9 | LL | Some(_) => {} - | ^^^^^^^ matches no values because `!` is uninhabited + | ^^^^^^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -412,7 +502,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:421:9 | LL | Some(_a) => {} - | ^^^^^^^^ matches no values because `!` is uninhabited + | ^^^^^^^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -438,7 +531,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:603:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -446,7 +542,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:606:9 | LL | _x => {} - | ^^ matches no values because `!` is uninhabited + | ^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -454,7 +553,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:609:9 | LL | _ if false => {} - | ^ matches no values because `!` is uninhabited + | ^--------------- + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -462,7 +564,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:612:9 | LL | _x if false => {} - | ^^ matches no values because `!` is uninhabited + | ^^--------------- + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr index 68213a2d661e0..3f312d46c7ee8 100644 --- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr +++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr @@ -11,7 +11,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:49:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here @@ -24,7 +27,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:52:9 | LL | _x => {} - | ^^ matches no values because `!` is uninhabited + | ^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -43,35 +49,14 @@ LL + _ => todo!(), LL + } | -error: unreachable pattern - --> $DIR/empty-types.rs:70:9 - | -LL | (_, _) => {} - | ^^^^^^ matches no values because `(u32, !)` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:76:9 - | -LL | _ => {} - | ^ matches no values because `(!, !)` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:79:9 - | -LL | (_, _) => {} - | ^^^^^^ matches no values because `(!, !)` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error: unreachable pattern --> $DIR/empty-types.rs:83:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -94,22 +79,6 @@ LL + Ok(_) => todo!(), LL + } | -error: unreachable pattern - --> $DIR/empty-types.rs:94:9 - | -LL | Err(_) => {} - | ^^^^^^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:99:9 - | -LL | Err(_) => {} - | ^^^^^^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered --> $DIR/empty-types.rs:96:11 | @@ -156,59 +125,14 @@ help: you might want to use `let else` to handle the variant that isn't matched LL | let Ok(_x) = &res_u32_never else { todo!() }; | ++++++++++++++++ -error: unreachable pattern - --> $DIR/empty-types.rs:112:9 - | -LL | _ => {} - | ^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:115:9 - | -LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:118:9 - | -LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:119:9 - | -LL | _ => {} - | ^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:122:9 - | -LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:123:9 - | -LL | Err(_) => {} - | ^^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error: unreachable pattern --> $DIR/empty-types.rs:132:13 | LL | _ => {} - | ^ matches no values because `Void` is uninhabited + | ^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -216,26 +140,13 @@ error: unreachable pattern --> $DIR/empty-types.rs:135:13 | LL | _ if false => {} - | ^ matches no values because `Void` is uninhabited + | ^--------------- + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types -error: unreachable pattern - --> $DIR/empty-types.rs:143:13 - | -LL | Some(_) => {} - | ^^^^^^^ matches no values because `Void` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:147:13 - | -LL | None => {} - | ---- matches all the relevant values -LL | _ => {} - | ^ no value can reach this - error[E0004]: non-exhaustive patterns: `Some(!)` not covered --> $DIR/empty-types.rs:156:15 | @@ -259,7 +170,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:199:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -267,7 +181,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:204:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -275,7 +192,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:209:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -283,7 +203,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:214:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -291,7 +214,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:220:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -299,31 +225,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:281:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:284:9 - | -LL | (_, _) => {} - | ^^^^^^ matches no values because `(!, !)` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:287:9 - | -LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:288:9 - | -LL | Err(_) => {} - | ^^^^^^ matches no values because `Result` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -474,30 +379,6 @@ LL + _ => todo!(), LL + } | -error: unreachable pattern - --> $DIR/empty-types.rs:368:9 - | -LL | _ => {} - | ^ matches no values because `[!; 3]` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:371:9 - | -LL | [_, _, _] => {} - | ^^^^^^^^^ matches no values because `[!; 3]` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:374:9 - | -LL | [_, ..] => {} - | ^^^^^^^ matches no values because `[!; 3]` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty --> $DIR/empty-types.rs:388:11 | @@ -534,40 +415,6 @@ LL ~ [..] if false => {}, LL + [] => todo!() | -error: unreachable pattern - --> $DIR/empty-types.rs:416:9 - | -LL | Some(_) => {} - | ^^^^^^^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:421:9 - | -LL | Some(_a) => {} - | ^^^^^^^^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:426:9 - | -LL | None => {} - | ---- matches all the relevant values -LL | // !useful, !reachable -LL | _ => {} - | ^ no value can reach this - -error: unreachable pattern - --> $DIR/empty-types.rs:431:9 - | -LL | None => {} - | ---- matches all the relevant values -LL | // !useful, !reachable -LL | _a => {} - | ^^ no value can reach this - error[E0004]: non-exhaustive patterns: `&Some(!)` not covered --> $DIR/empty-types.rs:451:11 | @@ -662,7 +509,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:603:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -670,7 +520,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:606:9 | LL | _x => {} - | ^^ matches no values because `!` is uninhabited + | ^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -678,7 +531,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:609:9 | LL | _ if false => {} - | ^ matches no values because `!` is uninhabited + | ^--------------- + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -686,7 +542,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:612:9 | LL | _x if false => {} - | ^^ matches no values because `!` is uninhabited + | ^^--------------- + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -744,7 +603,7 @@ LL ~ None => {}, LL + Some(!) | -error: aborting due to 65 previous errors; 1 warning emitted +error: aborting due to 42 previous errors; 1 warning emitted Some errors have detailed explanations: E0004, E0005. For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr index 8f60dad4467bc..bba50dab27b04 100644 --- a/tests/ui/pattern/usefulness/empty-types.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr @@ -2,7 +2,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:49:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here @@ -15,7 +18,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:52:9 | LL | _x => {} - | ^^ matches no values because `!` is uninhabited + | ^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -34,35 +40,14 @@ LL + _ => todo!(), LL + } | -error: unreachable pattern - --> $DIR/empty-types.rs:70:9 - | -LL | (_, _) => {} - | ^^^^^^ matches no values because `(u32, !)` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:76:9 - | -LL | _ => {} - | ^ matches no values because `(!, !)` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:79:9 - | -LL | (_, _) => {} - | ^^^^^^ matches no values because `(!, !)` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error: unreachable pattern --> $DIR/empty-types.rs:83:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -85,22 +70,6 @@ LL + Ok(_) => todo!(), LL + } | -error: unreachable pattern - --> $DIR/empty-types.rs:94:9 - | -LL | Err(_) => {} - | ^^^^^^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:99:9 - | -LL | Err(_) => {} - | ^^^^^^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered --> $DIR/empty-types.rs:96:11 | @@ -147,59 +116,14 @@ help: you might want to use `let else` to handle the variant that isn't matched LL | let Ok(_x) = &res_u32_never else { todo!() }; | ++++++++++++++++ -error: unreachable pattern - --> $DIR/empty-types.rs:112:9 - | -LL | _ => {} - | ^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:115:9 - | -LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:118:9 - | -LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:119:9 - | -LL | _ => {} - | ^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:122:9 - | -LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:123:9 - | -LL | Err(_) => {} - | ^^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error: unreachable pattern --> $DIR/empty-types.rs:132:13 | LL | _ => {} - | ^ matches no values because `Void` is uninhabited + | ^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -207,26 +131,13 @@ error: unreachable pattern --> $DIR/empty-types.rs:135:13 | LL | _ if false => {} - | ^ matches no values because `Void` is uninhabited + | ^--------------- + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types -error: unreachable pattern - --> $DIR/empty-types.rs:143:13 - | -LL | Some(_) => {} - | ^^^^^^^ matches no values because `Void` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:147:13 - | -LL | None => {} - | ---- matches all the relevant values -LL | _ => {} - | ^ no value can reach this - error[E0004]: non-exhaustive patterns: `Some(_)` not covered --> $DIR/empty-types.rs:156:15 | @@ -250,7 +161,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:199:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -258,7 +172,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:204:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -266,7 +183,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:209:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -274,7 +194,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:214:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -282,7 +205,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:220:13 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -290,31 +216,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:281:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:284:9 - | -LL | (_, _) => {} - | ^^^^^^ matches no values because `(!, !)` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:287:9 - | -LL | Ok(_) => {} - | ^^^^^ matches no values because `Result` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:288:9 - | -LL | Err(_) => {} - | ^^^^^^ matches no values because `Result` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -465,30 +370,6 @@ LL + _ => todo!(), LL + } | -error: unreachable pattern - --> $DIR/empty-types.rs:368:9 - | -LL | _ => {} - | ^ matches no values because `[!; 3]` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:371:9 - | -LL | [_, _, _] => {} - | ^^^^^^^^^ matches no values because `[!; 3]` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:374:9 - | -LL | [_, ..] => {} - | ^^^^^^^ matches no values because `[!; 3]` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty --> $DIR/empty-types.rs:388:11 | @@ -525,40 +406,6 @@ LL ~ [..] if false => {}, LL + [] => todo!() | -error: unreachable pattern - --> $DIR/empty-types.rs:416:9 - | -LL | Some(_) => {} - | ^^^^^^^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:421:9 - | -LL | Some(_a) => {} - | ^^^^^^^^ matches no values because `!` is uninhabited - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:426:9 - | -LL | None => {} - | ---- matches all the relevant values -LL | // !useful, !reachable -LL | _ => {} - | ^ no value can reach this - -error: unreachable pattern - --> $DIR/empty-types.rs:431:9 - | -LL | None => {} - | ---- matches all the relevant values -LL | // !useful, !reachable -LL | _a => {} - | ^^ no value can reach this - error[E0004]: non-exhaustive patterns: `&Some(_)` not covered --> $DIR/empty-types.rs:451:11 | @@ -653,7 +500,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:603:9 | LL | _ => {} - | ^ matches no values because `!` is uninhabited + | ^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -661,7 +511,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:606:9 | LL | _x => {} - | ^^ matches no values because `!` is uninhabited + | ^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -669,7 +522,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:609:9 | LL | _ if false => {} - | ^ matches no values because `!` is uninhabited + | ^--------------- + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -677,7 +533,10 @@ error: unreachable pattern --> $DIR/empty-types.rs:612:9 | LL | _x if false => {} - | ^^ matches no values because `!` is uninhabited + | ^^--------------- + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types @@ -735,7 +594,7 @@ LL ~ None => {}, LL + Some(_) => todo!() | -error: aborting due to 65 previous errors +error: aborting due to 42 previous errors Some errors have detailed explanations: E0004, E0005. For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/empty-types.rs b/tests/ui/pattern/usefulness/empty-types.rs index d561a0e9c128b..9e5f273a39052 100644 --- a/tests/ui/pattern/usefulness/empty-types.rs +++ b/tests/ui/pattern/usefulness/empty-types.rs @@ -67,16 +67,16 @@ fn basic(x: NeverBundle) { let tuple_half_never: (u32, !) = x.tuple_half_never; match tuple_half_never {} match tuple_half_never { - (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } let tuple_never: (!, !) = x.tuple_never; match tuple_never {} match tuple_never { - _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match tuple_never { - (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match tuple_never.0 {} match tuple_never.0 { @@ -91,12 +91,12 @@ fn basic(x: NeverBundle) { } match res_u32_never { Ok(_) => {} - Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match res_u32_never { //~^ ERROR non-exhaustive Ok(0) => {} - Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } let Ok(_x) = res_u32_never; let Ok(_x) = res_u32_never.as_ref(); @@ -109,18 +109,18 @@ fn basic(x: NeverBundle) { let result_never: Result = x.result_never; match result_never {} match result_never { - _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern - _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern - Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } } @@ -140,11 +140,11 @@ fn void_same_as_never(x: NeverBundle) { } match opt_void { None => {} - Some(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match opt_void { None => {} - _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern } let ref_void: &Void = &x.void; @@ -281,11 +281,11 @@ fn nested_validity_tracking(bundle: NeverBundle) { _ => {} //~ ERROR unreachable pattern } match tuple_never { - (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern - Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } // These should be considered !known_valid and not warn unreachable. @@ -365,13 +365,13 @@ fn arrays_and_slices(x: NeverBundle) { let array_3_never: [!; 3] = x.array_3_never; match array_3_never {} match array_3_never { - _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match array_3_never { - [_, _, _] => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + [_, _, _] => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match array_3_never { - [_, ..] => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + [_, ..] => {} //[exhaustive_patterns]~ ERROR unreachable pattern } let ref_array_3_never: &[!; 3] = &array_3_never; @@ -413,22 +413,22 @@ fn bindings(x: NeverBundle) { match opt_never { None => {} // !useful, !reachable - Some(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - Some(_a) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + Some(_a) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - _a => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern + _a => {} //[exhaustive_patterns]~ ERROR unreachable pattern } // The scrutinee is known_valid, but under the `&` isn't anymore. diff --git a/tests/ui/pattern/usefulness/explain-unreachable-pats.rs b/tests/ui/pattern/usefulness/explain-unreachable-pats.rs index 1cfa5212414bb..f1af7f294cbd8 100644 --- a/tests/ui/pattern/usefulness/explain-unreachable-pats.rs +++ b/tests/ui/pattern/usefulness/explain-unreachable-pats.rs @@ -1,4 +1,5 @@ #![feature(never_type)] +#![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] //~^ NOTE lint level is defined here diff --git a/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr b/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr index 7023c2775e9a7..8651be2055f53 100644 --- a/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr +++ b/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:10:9 + --> $DIR/explain-unreachable-pats.rs:11:9 | LL | (1 | 2,) => {} | -------- matches all the relevant values @@ -8,19 +8,19 @@ LL | (2,) => {} | ^^^^ no value can reach this | note: the lint level is defined here - --> $DIR/explain-unreachable-pats.rs:2:9 + --> $DIR/explain-unreachable-pats.rs:3:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:21:9 + --> $DIR/explain-unreachable-pats.rs:22:9 | LL | (1 | 2,) => {} | ^^^^^^^^ no value can reach this | note: multiple earlier patterns match some of the same values - --> $DIR/explain-unreachable-pats.rs:21:9 + --> $DIR/explain-unreachable-pats.rs:22:9 | LL | (1,) => {} | ---- matches some of the same values @@ -32,13 +32,13 @@ LL | (1 | 2,) => {} | ^^^^^^^^ collectively making this unreachable error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:40:9 + --> $DIR/explain-unreachable-pats.rs:41:9 | LL | 1 ..= 6 => {} | ^^^^^^^ no value can reach this | note: multiple earlier patterns match some of the same values - --> $DIR/explain-unreachable-pats.rs:40:9 + --> $DIR/explain-unreachable-pats.rs:41:9 | LL | 1 => {} | - matches some of the same values @@ -56,31 +56,40 @@ LL | 1 ..= 6 => {} | ^^^^^^^ ...and 2 other patterns collectively make this unreachable error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:51:9 + --> $DIR/explain-unreachable-pats.rs:52:9 | LL | Err(_) => {} - | ^^^^^^ matches no values because `!` is uninhabited + | ^^^^^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:65:9 + --> $DIR/explain-unreachable-pats.rs:66:9 | LL | (Err(_), Err(_)) => {} - | ^^^^^^^^^^^^^^^^ matches no values because `Void2` is uninhabited + | ^^^^^^^^^^^^^^^^------ + | | + | matches no values because `Void2` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:72:9 + --> $DIR/explain-unreachable-pats.rs:73:9 | LL | (Err(_), Err(_)) => {} - | ^^^^^^^^^^^^^^^^ matches no values because `Void1` is uninhabited + | ^^^^^^^^^^^^^^^^------ + | | + | matches no values because `Void1` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:82:11 + --> $DIR/explain-unreachable-pats.rs:83:11 | LL | if let (0 | - matches all the relevant values @@ -89,13 +98,13 @@ LL | | 0, _) = (0, 0) {} | ^ no value can reach this error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:92:9 + --> $DIR/explain-unreachable-pats.rs:93:9 | LL | (_, true) => {} | ^^^^^^^^^ no value can reach this | note: multiple earlier patterns match some of the same values - --> $DIR/explain-unreachable-pats.rs:92:9 + --> $DIR/explain-unreachable-pats.rs:93:9 | LL | (true, _) => {} | --------- matches some of the same values @@ -107,7 +116,7 @@ LL | (_, true) => {} | ^^^^^^^^^ collectively making this unreachable error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:105:9 + --> $DIR/explain-unreachable-pats.rs:106:9 | LL | (true, _) => {} | --------- matches all the relevant values @@ -116,7 +125,7 @@ LL | (true, true) => {} | ^^^^^^^^^^^^ no value can reach this error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:117:9 + --> $DIR/explain-unreachable-pats.rs:118:9 | LL | (_, true, 0..10) => {} | ---------------- matches all the relevant values diff --git a/tests/ui/pattern/usefulness/impl-trait.rs b/tests/ui/pattern/usefulness/impl-trait.rs index c1cc279f74ce9..16560a092675f 100644 --- a/tests/ui/pattern/usefulness/impl-trait.rs +++ b/tests/ui/pattern/usefulness/impl-trait.rs @@ -1,6 +1,7 @@ #![feature(never_type)] #![feature(type_alias_impl_trait)] #![feature(non_exhaustive_omitted_patterns_lint)] +#![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] // Test that the lint traversal handles opaques correctly #![deny(non_exhaustive_omitted_patterns)] diff --git a/tests/ui/pattern/usefulness/impl-trait.stderr b/tests/ui/pattern/usefulness/impl-trait.stderr index 34b157f0fc443..75cba4b5f0276 100644 --- a/tests/ui/pattern/usefulness/impl-trait.stderr +++ b/tests/ui/pattern/usefulness/impl-trait.stderr @@ -1,34 +1,43 @@ error: unreachable pattern - --> $DIR/impl-trait.rs:16:13 + --> $DIR/impl-trait.rs:17:13 | LL | _ => {} - | ^ matches no values because `Void` is uninhabited + | ^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here - --> $DIR/impl-trait.rs:4:9 + --> $DIR/impl-trait.rs:5:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/impl-trait.rs:30:13 + --> $DIR/impl-trait.rs:31:13 | LL | _ => {} - | ^ matches no values because `Void` is uninhabited + | ^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/impl-trait.rs:44:13 + --> $DIR/impl-trait.rs:45:13 | LL | Some(_) => {} - | ^^^^^^^ matches no values because `Void` is uninhabited + | ^^^^^^^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/impl-trait.rs:48:13 + --> $DIR/impl-trait.rs:49:13 | LL | None => {} | ---- matches all the relevant values @@ -36,15 +45,18 @@ LL | _ => {} | ^ no value can reach this error: unreachable pattern - --> $DIR/impl-trait.rs:58:13 + --> $DIR/impl-trait.rs:59:13 | LL | Some(_) => {} - | ^^^^^^^ matches no values because `Void` is uninhabited + | ^^^^^^^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/impl-trait.rs:62:13 + --> $DIR/impl-trait.rs:63:13 | LL | None => {} | ---- matches all the relevant values @@ -52,15 +64,18 @@ LL | _ => {} | ^ no value can reach this error: unreachable pattern - --> $DIR/impl-trait.rs:75:9 + --> $DIR/impl-trait.rs:76:9 | LL | _ => {} - | ^ matches no values because `Void` is uninhabited + | ^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/impl-trait.rs:85:9 + --> $DIR/impl-trait.rs:86:9 | LL | _ => {} | - matches any value @@ -68,15 +83,18 @@ LL | Some((a, b)) => {} | ^^^^^^^^^^^^ no value can reach this error: unreachable pattern - --> $DIR/impl-trait.rs:93:13 + --> $DIR/impl-trait.rs:94:13 | LL | _ => {} - | ^ matches no values because `Void` is uninhabited + | ^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/impl-trait.rs:104:9 + --> $DIR/impl-trait.rs:105:9 | LL | Some((a, b)) => {} | ------------ matches all the relevant values @@ -84,7 +102,7 @@ LL | Some((mut x, mut y)) => { | ^^^^^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern - --> $DIR/impl-trait.rs:123:13 + --> $DIR/impl-trait.rs:124:13 | LL | _ => {} | - matches any value @@ -92,23 +110,29 @@ LL | Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern - --> $DIR/impl-trait.rs:137:13 + --> $DIR/impl-trait.rs:138:13 | LL | _ => {} - | ^ matches no values because `SecretelyVoid` is uninhabited + | ^------ + | | + | matches no values because `SecretelyVoid` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/impl-trait.rs:150:13 + --> $DIR/impl-trait.rs:151:13 | LL | _ => {} - | ^ matches no values because `SecretelyDoubleVoid` is uninhabited + | ^------ + | | + | matches no values because `SecretelyDoubleVoid` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty - --> $DIR/impl-trait.rs:22:11 + --> $DIR/impl-trait.rs:23:11 | LL | match return_never_rpit(x) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +146,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `T` is non-empty - --> $DIR/impl-trait.rs:36:11 + --> $DIR/impl-trait.rs:37:11 | LL | match return_never_tait(x) {} | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.fixed b/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.fixed new file mode 100644 index 0000000000000..18e3aecbd0db9 --- /dev/null +++ b/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.fixed @@ -0,0 +1,23 @@ +//@ run-rustfix +#![feature(never_patterns)] +#![feature(exhaustive_patterns)] +#![allow(incomplete_features)] +#![deny(unreachable_patterns)] + +enum Void {} + +#[rustfmt::skip] +fn main() { + let res: Result<(), Void> = Ok(()); + match res { + Ok(_) => {} + //~ ERROR unreachable + //~ ERROR unreachable + } + + match res { + Ok(_x) => {} + //~ ERROR unreachable + //~ ERROR unreachable + } +} diff --git a/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.rs b/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.rs new file mode 100644 index 0000000000000..a81420d149690 --- /dev/null +++ b/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.rs @@ -0,0 +1,23 @@ +//@ run-rustfix +#![feature(never_patterns)] +#![feature(exhaustive_patterns)] +#![allow(incomplete_features)] +#![deny(unreachable_patterns)] + +enum Void {} + +#[rustfmt::skip] +fn main() { + let res: Result<(), Void> = Ok(()); + match res { + Ok(_) => {} + Err(_) => {} //~ ERROR unreachable + Err(_) => {}, //~ ERROR unreachable + } + + match res { + Ok(_x) => {} + Err(!), //~ ERROR unreachable + Err(!) //~ ERROR unreachable + } +} diff --git a/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.stderr b/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.stderr new file mode 100644 index 0000000000000..bb246cea0a0c9 --- /dev/null +++ b/tests/ui/pattern/usefulness/rustfix-unreachable-pattern.stderr @@ -0,0 +1,51 @@ +error: unreachable pattern + --> $DIR/rustfix-unreachable-pattern.rs:14:9 + | +LL | Err(_) => {} + | ^^^^^^------ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types +note: the lint level is defined here + --> $DIR/rustfix-unreachable-pattern.rs:5:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/rustfix-unreachable-pattern.rs:15:9 + | +LL | Err(_) => {}, + | ^^^^^^------- + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: unreachable pattern + --> $DIR/rustfix-unreachable-pattern.rs:20:9 + | +LL | Err(!), + | ^^^^^^- + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: unreachable pattern + --> $DIR/rustfix-unreachable-pattern.rs:21:9 + | +LL | Err(!) + | ^^^^^^ + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: aborting due to 4 previous errors + diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout index da67a57f420d7..4415b3c858e35 100644 --- a/tests/ui/print-calling-conventions.stdout +++ b/tests/ui/print-calling-conventions.stdout @@ -1,5 +1,6 @@ C C-cmse-nonsecure-call +C-cmse-nonsecure-entry C-unwind Rust aapcs diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index 8b01e8c3c10ef..1e28b9fbd86bd 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -44,7 +44,7 @@ LL | wtf: Some(Box::new_zeroed()), | ~~~~~~~~~~~~~~ LL | wtf: Some(Box::new_in(_, _)), | ~~~~~~~~~~~~~~ - and 10 other candidates + and 12 other candidates help: consider using the `Default` trait | LL | wtf: Some(::default()), @@ -89,7 +89,7 @@ LL | let _ = Box::new_zeroed(); | ~~~~~~~~~~~~~~ LL | let _ = Box::new_in(_, _); | ~~~~~~~~~~~~~~ - and 10 other candidates + and 12 other candidates help: consider using the `Default` trait | LL | let _ = ::default(); diff --git a/tests/ui/proc-macro/macro-rules-derive-cfg.rs b/tests/ui/proc-macro/macro-rules-derive-cfg.rs index 68026a60be686..c34f1695761cf 100644 --- a/tests/ui/proc-macro/macro-rules-derive-cfg.rs +++ b/tests/ui/proc-macro/macro-rules-derive-cfg.rs @@ -14,17 +14,15 @@ extern crate test_macros; macro_rules! produce_it { ($expr:expr) => { #[derive(Print)] - struct Foo { - val: [bool; { - let a = #[cfg_attr(not(FALSE), rustc_dummy(first))] $expr; - 0 - }] - } + struct Foo( + [bool; #[cfg_attr(not(FALSE), rustc_dummy(first))] $expr] + ); } } produce_it!(#[cfg_attr(not(FALSE), rustc_dummy(second))] { - #![cfg_attr(not(FALSE), allow(unused))] + #![cfg_attr(not(FALSE), rustc_dummy(third))] + #[cfg_attr(not(FALSE), rustc_dummy(fourth))] 30 }); diff --git a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout index fadf210127e4d..c1e46b50d40c2 100644 --- a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout +++ b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout @@ -1,21 +1,9 @@ -PRINT-DERIVE INPUT (DISPLAY): struct Foo -{ - val : - [bool; - { - let a = #[rustc_dummy(first)] #[rustc_dummy(second)] - { #![allow(unused)] 30 }; 0 - }] -} -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct Foo -{ - val : - [bool; - { - let a = #[rustc_dummy(first)] #[rustc_dummy(second)] - { #! [allow(unused)] 30 }; 0 - }] -} +PRINT-DERIVE INPUT (DISPLAY): struct +Foo([bool; #[rustc_dummy(first)] #[rustc_dummy(second)] +{ #![rustc_dummy(third)] #[rustc_dummy(fourth)] 30 }]); +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct +Foo([bool; #[rustc_dummy(first)] #[rustc_dummy(second)] +{ #! [rustc_dummy(third)] #[rustc_dummy(fourth)] 30 }]); PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -26,155 +14,146 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/macro-rules-derive-cfg.rs:17:16: 17:19 (#3), }, Group { - delimiter: Brace, + delimiter: Parenthesis, stream: TokenStream [ - Ident { - ident: "val", - span: $DIR/macro-rules-derive-cfg.rs:18:13: 18:16 (#3), - }, - Punct { - ch: ':', - spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:18:16: 18:17 (#3), - }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "bool", - span: $DIR/macro-rules-derive-cfg.rs:18:19: 18:23 (#3), + span: $DIR/macro-rules-derive-cfg.rs:18:14: 18:18 (#3), }, Punct { ch: ';', spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:18:23: 18:24 (#3), + span: $DIR/macro-rules-derive-cfg.rs:18:18: 18:19 (#3), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/macro-rules-derive-cfg.rs:18:20: 18:21 (#3), }, Group { - delimiter: Brace, + delimiter: Bracket, stream: TokenStream [ Ident { - ident: "let", - span: $DIR/macro-rules-derive-cfg.rs:19:17: 19:20 (#3), + ident: "rustc_dummy", + span: $DIR/macro-rules-derive-cfg.rs:18:43: 18:54 (#3), }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "first", + span: $DIR/macro-rules-derive-cfg.rs:18:55: 18:60 (#3), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:18:54: 18:61 (#3), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:18:21: 18:63 (#3), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/macro-rules-derive-cfg.rs:23:13: 23:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ Ident { - ident: "a", - span: $DIR/macro-rules-derive-cfg.rs:19:21: 19:22 (#3), + ident: "rustc_dummy", + span: $DIR/macro-rules-derive-cfg.rs:23:36: 23:47 (#0), }, - Punct { - ch: '=', - spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:19:23: 19:24 (#3), + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "second", + span: $DIR/macro-rules-derive-cfg.rs:23:48: 23:54 (#0), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:23:47: 23:55 (#0), }, + ], + span: $DIR/macro-rules-derive-cfg.rs:23:14: 23:57 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ Punct { ch: '#', + spacing: Joint, + span: $DIR/macro-rules-derive-cfg.rs:24:5: 24:6 (#0), + }, + Punct { + ch: '!', spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:19:25: 19:26 (#3), + span: $DIR/macro-rules-derive-cfg.rs:24:6: 24:7 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "rustc_dummy", - span: $DIR/macro-rules-derive-cfg.rs:19:48: 19:59 (#3), + span: $DIR/macro-rules-derive-cfg.rs:24:29: 24:40 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "first", - span: $DIR/macro-rules-derive-cfg.rs:19:60: 19:65 (#3), + ident: "third", + span: $DIR/macro-rules-derive-cfg.rs:24:41: 24:46 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:19:59: 19:66 (#3), + span: $DIR/macro-rules-derive-cfg.rs:24:40: 24:47 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:19:26: 19:68 (#3), + span: $DIR/macro-rules-derive-cfg.rs:24:7: 24:49 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:26:13: 26:14 (#0), + span: $DIR/macro-rules-derive-cfg.rs:25:5: 25:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "rustc_dummy", - span: $DIR/macro-rules-derive-cfg.rs:26:36: 26:47 (#0), + span: $DIR/macro-rules-derive-cfg.rs:25:28: 25:39 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "second", - span: $DIR/macro-rules-derive-cfg.rs:26:48: 26:54 (#0), + ident: "fourth", + span: $DIR/macro-rules-derive-cfg.rs:25:40: 25:46 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:26:47: 26:55 (#0), + span: $DIR/macro-rules-derive-cfg.rs:25:39: 25:47 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:26:14: 26:57 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Punct { - ch: '#', - spacing: Joint, - span: $DIR/macro-rules-derive-cfg.rs:27:5: 27:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:27:6: 27:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "allow", - span: $DIR/macro-rules-derive-cfg.rs:27:29: 27:34 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "unused", - span: $DIR/macro-rules-derive-cfg.rs:27:35: 27:41 (#0), - }, - ], - span: $DIR/macro-rules-derive-cfg.rs:27:34: 27:42 (#0), - }, - ], - span: $DIR/macro-rules-derive-cfg.rs:27:7: 27:44 (#0), - }, - Literal { - kind: Integer, - symbol: "30", - suffix: None, - span: $DIR/macro-rules-derive-cfg.rs:28:5: 28:7 (#0), - }, - ], - span: $DIR/macro-rules-derive-cfg.rs:26:58: 29:2 (#0), - }, - Punct { - ch: ';', - spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:19:74: 19:75 (#3), + span: $DIR/macro-rules-derive-cfg.rs:25:6: 25:49 (#0), }, Literal { kind: Integer, - symbol: "0", + symbol: "30", suffix: None, - span: $DIR/macro-rules-derive-cfg.rs:20:17: 20:18 (#3), + span: $DIR/macro-rules-derive-cfg.rs:26:5: 26:7 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:18:25: 21:14 (#3), + span: $DIR/macro-rules-derive-cfg.rs:23:58: 27:2 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:18:18: 21:15 (#3), + span: $DIR/macro-rules-derive-cfg.rs:18:13: 18:70 (#3), }, ], - span: $DIR/macro-rules-derive-cfg.rs:17:20: 22:10 (#3), + span: $DIR/macro-rules-derive-cfg.rs:17:19: 19:10 (#3), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/macro-rules-derive-cfg.rs:19:10: 19:11 (#3), }, ] diff --git a/tests/ui/reachable/unreachable-loop-patterns.rs b/tests/ui/reachable/unreachable-loop-patterns.rs index d074e3a6ece4b..9be37ecf2bb27 100644 --- a/tests/ui/reachable/unreachable-loop-patterns.rs +++ b/tests/ui/reachable/unreachable-loop-patterns.rs @@ -1,3 +1,4 @@ +#![feature(exhaustive_patterns)] #![feature(never_type, never_type_fallback)] #![allow(unreachable_code)] #![deny(unreachable_patterns)] diff --git a/tests/ui/reachable/unreachable-loop-patterns.stderr b/tests/ui/reachable/unreachable-loop-patterns.stderr index 03959ac160695..290f45700b2e4 100644 --- a/tests/ui/reachable/unreachable-loop-patterns.stderr +++ b/tests/ui/reachable/unreachable-loop-patterns.stderr @@ -1,12 +1,12 @@ error: unreachable pattern - --> $DIR/unreachable-loop-patterns.rs:16:9 + --> $DIR/unreachable-loop-patterns.rs:17:9 | LL | for _ in unimplemented!() as Void {} | ^ matches no values because `Void` is uninhabited | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here - --> $DIR/unreachable-loop-patterns.rs:3:9 + --> $DIR/unreachable-loop-patterns.rs:4:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/reachable/unreachable-try-pattern.stderr b/tests/ui/reachable/unreachable-try-pattern.stderr index b082bc1160332..40b116131057c 100644 --- a/tests/ui/reachable/unreachable-try-pattern.stderr +++ b/tests/ui/reachable/unreachable-try-pattern.stderr @@ -17,7 +17,10 @@ warning: unreachable pattern --> $DIR/unreachable-try-pattern.rs:19:24 | LL | let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?; - | ^^^^^ matches no values because `!` is uninhabited + | ^^^^^----------------- + | | + | matches no values because `!` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here @@ -30,7 +33,10 @@ warning: unreachable pattern --> $DIR/unreachable-try-pattern.rs:30:40 | LL | let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?; - | ^^^^^^ matches no values because `Void` is uninhabited + | ^^^^^^---------- + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types diff --git a/tests/ui/regions/regions-close-object-into-object-4.stderr b/tests/ui/regions/regions-close-object-into-object-4.stderr index b8b414b7e125e..f6a79be09477c 100644 --- a/tests/ui/regions/regions-close-object-into-object-4.stderr +++ b/tests/ui/regions/regions-close-object-into-object-4.stderr @@ -30,12 +30,11 @@ error[E0310]: the parameter type `U` may not live long enough --> $DIR/regions-close-object-into-object-4.rs:9:5 | LL | Box::new(B(&*v)) as Box - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the parameter type `U` must be valid for the static lifetime... | ...so that the type `U` will meet its required lifetime bounds | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit lifetime bound | LL | fn i<'a, T, U: 'static>(v: Box+'a>) -> Box { diff --git a/tests/ui/regions/regions-close-object-into-object-5.stderr b/tests/ui/regions/regions-close-object-into-object-5.stderr index 4a2f4f847a308..881d9e03cdfab 100644 --- a/tests/ui/regions/regions-close-object-into-object-5.stderr +++ b/tests/ui/regions/regions-close-object-into-object-5.stderr @@ -30,12 +30,11 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:5 | LL | Box::new(B(&*v)) as Box - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the parameter type `T` must be valid for the static lifetime... | ...so that the type `T` will meet its required lifetime bounds | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit lifetime bound | LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { diff --git a/tests/ui/regions/regions-close-over-type-parameter-1.stderr b/tests/ui/regions/regions-close-over-type-parameter-1.stderr index 1cd5b7f225079..7c8c5fe5cf68b 100644 --- a/tests/ui/regions/regions-close-over-type-parameter-1.stderr +++ b/tests/ui/regions/regions-close-over-type-parameter-1.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:11:5 | LL | Box::new(v) as Box - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the parameter type `A` must be valid for the static lifetime... | ...so that the type `A` will meet its required lifetime bounds @@ -18,7 +18,7 @@ error[E0309]: the parameter type `A` may not live long enough LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { | -- the parameter type `A` must be valid for the lifetime `'b` as defined here... LL | Box::new(v) as Box - | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds | help: consider adding an explicit lifetime bound | diff --git a/tests/ui/repr/attr-usage-repr.rs b/tests/ui/repr/attr-usage-repr.rs index 8965decc37989..dc0d4f5be2e30 100644 --- a/tests/ui/repr/attr-usage-repr.rs +++ b/tests/ui/repr/attr-usage-repr.rs @@ -10,7 +10,7 @@ struct SExtern(f64, f64); struct SPacked(f64, f64); #[repr(simd)] -struct SSimd(f64, f64); +struct SSimd([f64; 2]); #[repr(i8)] //~ ERROR: attribute should be applied to an enum struct SInt(f64, f64); diff --git a/tests/ui/repr/explicit-rust-repr-conflicts.rs b/tests/ui/repr/explicit-rust-repr-conflicts.rs index 22dd12d316ac5..5278f5e6ae0cc 100644 --- a/tests/ui/repr/explicit-rust-repr-conflicts.rs +++ b/tests/ui/repr/explicit-rust-repr-conflicts.rs @@ -18,6 +18,6 @@ enum U { #[repr(Rust, simd)] //~^ ERROR conflicting representation hints //~| ERROR SIMD types are experimental and possibly buggy -struct F32x4(f32, f32, f32, f32); +struct F32x4([f32; 4]); fn main() {} diff --git a/tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs b/tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs new file mode 100644 index 0000000000000..952957ec480fb --- /dev/null +++ b/tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs @@ -0,0 +1,3 @@ +pub trait Foo { + type Bar; +} diff --git a/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs new file mode 100644 index 0000000000000..20bbbff8fd20b --- /dev/null +++ b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs @@ -0,0 +1,11 @@ +//@ aux-build:foreign-trait-with-assoc.rs + +extern crate foreign_trait_with_assoc; +use foreign_trait_with_assoc::Foo; + +// Make sure we don't try to call `fn_arg_names` on a non-fn item. + +impl Foo for Bar {} +//~^ ERROR cannot find type `Bar` in this scope + +fn main() {} diff --git a/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr new file mode 100644 index 0000000000000..a1a8bb575e14a --- /dev/null +++ b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr @@ -0,0 +1,14 @@ +error[E0412]: cannot find type `Bar` in this scope + --> $DIR/dont-compute-arg-names-for-non-fn.rs:8:14 + | +LL | impl Foo for Bar {} + | ^^^ + | +help: you might have meant to use the associated type + | +LL | impl Foo for Self::Bar {} + | ++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.rs b/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.rs new file mode 100644 index 0000000000000..a66c446441778 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.rs @@ -0,0 +1,16 @@ +// Make sure we consider `!` to be a union read. + +#![feature(never_type, never_patterns)] +//~^ WARN the feature `never_patterns` is incomplete + +union U { + a: !, + b: usize, +} + +fn foo(u: U) -> ! { + let U { a: ! } = u; + //~^ ERROR access to union field is unsafe +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.stderr new file mode 100644 index 0000000000000..d7dc7a47e7283 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.stderr @@ -0,0 +1,20 @@ +warning: the feature `never_patterns` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/never-pattern-is-a-read.rs:3:24 + | +LL | #![feature(never_type, never_patterns)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #118155 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/never-pattern-is-a-read.rs:12:16 + | +LL | let U { a: ! } = u; + | ^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs index f68da4aa17316..6d7815f7a9eb0 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs @@ -1,3 +1,4 @@ +#![feature(exhaustive_patterns)] #![feature(never_patterns)] #![allow(incomplete_features)] #![allow(dead_code, unreachable_code)] diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr index 6b3f303eeab84..0c9552bb95053 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr @@ -1,18 +1,21 @@ error: unreachable pattern - --> $DIR/unreachable.rs:14:9 + --> $DIR/unreachable.rs:15:9 | LL | Err(!), - | ^^^^^^ matches no values because `Void` is uninhabited + | ^^^^^^- + | | + | matches no values because `Void` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here - --> $DIR/unreachable.rs:4:9 + --> $DIR/unreachable.rs:5:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/unreachable.rs:17:19 + --> $DIR/unreachable.rs:18:19 | LL | let (Ok(_x) | Err(!)) = res_void; | ^^^^^^ matches no values because `Void` is uninhabited @@ -20,7 +23,7 @@ LL | let (Ok(_x) | Err(!)) = res_void; = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/unreachable.rs:19:12 + --> $DIR/unreachable.rs:20:12 | LL | if let Err(!) = res_void {} | ^^^^^^ matches no values because `Void` is uninhabited @@ -28,7 +31,7 @@ LL | if let Err(!) = res_void {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/unreachable.rs:21:24 + --> $DIR/unreachable.rs:22:24 | LL | if let (Ok(true) | Err(!)) = res_void {} | ^^^^^^ matches no values because `Void` is uninhabited @@ -36,7 +39,7 @@ LL | if let (Ok(true) | Err(!)) = res_void {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/unreachable.rs:23:23 + --> $DIR/unreachable.rs:24:23 | LL | for (Ok(mut _x) | Err(!)) in [res_void] {} | ^^^^^^ matches no values because `Void` is uninhabited @@ -44,7 +47,7 @@ LL | for (Ok(mut _x) | Err(!)) in [res_void] {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/unreachable.rs:27:18 + --> $DIR/unreachable.rs:28:18 | LL | fn foo((Ok(_x) | Err(!)): Result) {} | ^^^^^^ matches no values because `Void` is uninhabited diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr index dfd7f9d630051..45a0ca01a5603 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -2,7 +2,10 @@ error: unreachable pattern --> $DIR/enum_same_crate_empty_match.rs:28:9 | LL | _ => {} - | ^ matches no values because `EmptyNonExhaustiveEnum` is uninhabited + | ^------ + | | + | matches no values because `EmptyNonExhaustiveEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs index a2735d4cbfb29..e1799761b6961 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs @@ -7,11 +7,17 @@ pub enum UninhabitedEnum { #[non_exhaustive] pub struct UninhabitedStruct { - _priv: !, + pub never: !, + _priv: (), } #[non_exhaustive] -pub struct UninhabitedTupleStruct(!); +pub struct PrivatelyUninhabitedStruct { + never: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(pub !); pub enum UninhabitedVariants { #[non_exhaustive] Tuple(!), diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr index 66e93291c72a0..f332e6deeb82c 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -5,7 +5,7 @@ LL | match x {} | ^ | note: `IndirectUninhabitedEnum` defined here - --> $DIR/auxiliary/uninhabited.rs:26:1 + --> $DIR/auxiliary/uninhabited.rs:32:1 | LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | match x {} | ^ | note: `IndirectUninhabitedStruct` defined here - --> $DIR/auxiliary/uninhabited.rs:28:1 + --> $DIR/auxiliary/uninhabited.rs:34:1 | LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | match x {} | ^ | note: `IndirectUninhabitedTupleStruct` defined here - --> $DIR/auxiliary/uninhabited.rs:30:1 + --> $DIR/auxiliary/uninhabited.rs:36:1 | LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,7 +62,7 @@ LL | match x {} | ^ | note: `IndirectUninhabitedVariants` defined here - --> $DIR/auxiliary/uninhabited.rs:32:1 + --> $DIR/auxiliary/uninhabited.rs:38:1 | LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr index 745b196a0e3ad..48f3857bfa7f8 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr @@ -5,7 +5,7 @@ LL | match x {} | ^ | note: `IndirectUninhabitedEnum` defined here - --> $DIR/auxiliary/uninhabited.rs:26:1 + --> $DIR/auxiliary/uninhabited.rs:32:1 | LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | match x {} | ^ | note: `IndirectUninhabitedStruct` defined here - --> $DIR/auxiliary/uninhabited.rs:28:1 + --> $DIR/auxiliary/uninhabited.rs:34:1 | LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | match x {} | ^ | note: `IndirectUninhabitedTupleStruct` defined here - --> $DIR/auxiliary/uninhabited.rs:30:1 + --> $DIR/auxiliary/uninhabited.rs:36:1 | LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,7 +62,7 @@ LL | match x {} | ^ | note: `IndirectUninhabitedVariants` defined here - --> $DIR/auxiliary/uninhabited.rs:32:1 + --> $DIR/auxiliary/uninhabited.rs:38:1 | LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs index fd77fab8738d3..ca7c528715420 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs @@ -11,11 +11,11 @@ use uninhabited::PartiallyInhabitedVariants; pub fn foo(x: PartiallyInhabitedVariants) { match x { - PartiallyInhabitedVariants::Struct { .. } => {}, - PartiallyInhabitedVariants::Struct { .. } => {}, + PartiallyInhabitedVariants::Struct { .. } => {} + PartiallyInhabitedVariants::Struct { .. } => {} //~^ ERROR unreachable pattern - _ => {}, + _ => {} } } -fn main() { } +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr index 956725fc10eb9..86df9ef9b564c 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr @@ -1,9 +1,9 @@ error: unreachable pattern --> $DIR/issue-65157-repeated-match-arm.rs:15:9 | -LL | PartiallyInhabitedVariants::Struct { .. } => {}, +LL | PartiallyInhabitedVariants::Struct { .. } => {} | ----------------------------------------- matches all the relevant values -LL | PartiallyInhabitedVariants::Struct { .. } => {}, +LL | PartiallyInhabitedVariants::Struct { .. } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs index c330f3aa05c4b..58d7bbd2c1730 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs @@ -3,12 +3,7 @@ extern crate uninhabited; -use uninhabited::{ - UninhabitedEnum, - UninhabitedStruct, - UninhabitedTupleStruct, - UninhabitedVariants, -}; +use uninhabited::*; struct A; @@ -19,16 +14,20 @@ fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { match x {} //~ ERROR non-exhaustive patterns } -fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { - match x {} //~ ERROR non-exhaustive patterns +fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A { + match x {} } -fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { +fn cannot_empty_match_on_privately_empty_struct(x: PrivatelyUninhabitedStruct) -> A { match x {} //~ ERROR non-exhaustive patterns } -fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { - match x {} //~ ERROR non-exhaustive patterns +fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A { + match x {} +} + +fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A { + match x {} } fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr index c125756a646d5..0232e7106aab7 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -1,15 +1,15 @@ -error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty - --> $DIR/match.rs:19:11 +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty + --> $DIR/match.rs:14:11 | LL | match x {} | ^ | -note: `UninhabitedEnum` defined here +note: `uninhabited::UninhabitedEnum` defined here --> $DIR/auxiliary/uninhabited.rs:5:1 | LL | pub enum UninhabitedEnum { | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive + = note: the matched value is of type `uninhabited::UninhabitedEnum`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | LL ~ match x { @@ -17,18 +17,18 @@ LL + _ => todo!(), LL ~ } | -error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty - --> $DIR/match.rs:23:11 +error[E0004]: non-exhaustive patterns: type `uninhabited::PrivatelyUninhabitedStruct` is non-empty + --> $DIR/match.rs:22:11 | LL | match x {} | ^ | -note: `UninhabitedStruct` defined here - --> $DIR/auxiliary/uninhabited.rs:9:1 +note: `uninhabited::PrivatelyUninhabitedStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:15:1 | -LL | pub struct UninhabitedStruct { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `UninhabitedStruct` +LL | pub struct PrivatelyUninhabitedStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `uninhabited::PrivatelyUninhabitedStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | LL ~ match x { @@ -36,48 +36,6 @@ LL + _ => todo!(), LL ~ } | -error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty - --> $DIR/match.rs:27:11 - | -LL | match x {} - | ^ - | -note: `UninhabitedTupleStruct` defined here - --> $DIR/auxiliary/uninhabited.rs:14:1 - | -LL | pub struct UninhabitedTupleStruct(!); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `UninhabitedTupleStruct` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown - | -LL ~ match x { -LL + _ => todo!(), -LL ~ } - | - -error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered - --> $DIR/match.rs:31:11 - | -LL | match x {} - | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered - | -note: `UninhabitedVariants` defined here - --> $DIR/auxiliary/uninhabited.rs:16:1 - | -LL | pub enum UninhabitedVariants { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | #[non_exhaustive] Tuple(!), - | ----- not covered -LL | #[non_exhaustive] Struct { x: ! } - | ------ not covered - = note: the matched value is of type `UninhabitedVariants` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms - | -LL ~ match x { -LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(), -LL ~ } - | - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs index 108cac7099ebf..c214581549cd7 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs @@ -5,32 +5,28 @@ extern crate uninhabited; use uninhabited::{ - UninhabitedEnum, - UninhabitedStruct, - UninhabitedTupleStruct, - UninhabitedVariants, + UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct, UninhabitedVariants, }; struct A; -// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate -// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can -// change the branch used in the compiler to determine this. - -fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { +// This test checks that non-exhaustive enums are never considered uninhabited outside their +// defining crate, and non-exhaustive structs are considered uninhabited the same way as normal +// ones. +fn cannot_empty_match_on_non_exhaustive_empty_enum(x: UninhabitedEnum) -> A { match x {} //~ ERROR non-exhaustive patterns } -fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { - match x {} //~ ERROR non-exhaustive patterns +fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A { + match x {} } -fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { - match x {} //~ ERROR non-exhaustive patterns +fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A { + match x {} } -fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { - match x {} //~ ERROR non-exhaustive patterns +fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A { + match x {} } fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr index 0c8b14ab69df0..d6f0bc724a98d 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty - --> $DIR/match_with_exhaustive_patterns.rs:21:11 + --> $DIR/match_with_exhaustive_patterns.rs:17:11 | LL | match x {} | ^ @@ -17,67 +17,6 @@ LL + _ => todo!(), LL ~ } | -error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty - --> $DIR/match_with_exhaustive_patterns.rs:25:11 - | -LL | match x {} - | ^ - | -note: `UninhabitedStruct` defined here - --> $DIR/auxiliary/uninhabited.rs:9:1 - | -LL | pub struct UninhabitedStruct { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `UninhabitedStruct` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown - | -LL ~ match x { -LL + _ => todo!(), -LL ~ } - | - -error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty - --> $DIR/match_with_exhaustive_patterns.rs:29:11 - | -LL | match x {} - | ^ - | -note: `UninhabitedTupleStruct` defined here - --> $DIR/auxiliary/uninhabited.rs:14:1 - | -LL | pub struct UninhabitedTupleStruct(!); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `UninhabitedTupleStruct` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown - | -LL ~ match x { -LL + _ => todo!(), -LL ~ } - | - -error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered - --> $DIR/match_with_exhaustive_patterns.rs:33:11 - | -LL | match x {} - | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered - | -note: `UninhabitedVariants` defined here - --> $DIR/auxiliary/uninhabited.rs:16:1 - | -LL | pub enum UninhabitedVariants { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | #[non_exhaustive] Tuple(!), - | ----- not covered -LL | #[non_exhaustive] Struct { x: ! } - | ------ not covered - = note: the matched value is of type `UninhabitedVariants` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms - | -LL ~ match x { -LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(), -LL ~ } - | - -error: aborting due to 4 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs index 468703c78e068..9662016221278 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs @@ -1,5 +1,4 @@ //@ check-pass - #![deny(unreachable_patterns)] #![feature(never_type)] @@ -9,11 +8,12 @@ pub enum UninhabitedEnum { #[non_exhaustive] pub struct UninhabitedStruct { - _priv: !, + pub never: !, + _priv: (), } #[non_exhaustive] -pub struct UninhabitedTupleStruct(!); +pub struct UninhabitedTupleStruct(pub !); pub enum UninhabitedVariants { #[non_exhaustive] Tuple(!), @@ -22,24 +22,21 @@ pub enum UninhabitedVariants { struct A; -// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate -// will compile. In particular, this enables the `exhaustive_patterns` feature as this can -// change the branch used in the compiler to determine this. -// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648. - -fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { +// This checks that `non_exhaustive` annotations do not affect exhaustiveness checking within the +// defining crate. +fn empty_match_on_empty_enum(x: UninhabitedEnum) -> A { match x {} } -fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { +fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A { match x {} } -fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { +fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A { match x {} } -fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { +fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A { match x {} } diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs index be55ad51578be..088331b0e7f72 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs @@ -1,14 +1,11 @@ //@ aux-build:uninhabited.rs -//@ build-pass (FIXME(62277): could be check-pass?) +#![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] extern crate uninhabited; use uninhabited::{ - PartiallyInhabitedVariants, - UninhabitedEnum, - UninhabitedStruct, - UninhabitedTupleStruct, + PartiallyInhabitedVariants, UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct, UninhabitedVariants, }; @@ -32,27 +29,26 @@ fn uninhabited_tuple_struct() -> Option { None } -// This test checks that non-exhaustive types that would normally be considered uninhabited within -// the defining crate are not considered uninhabited from extern crates. - +// This test checks that non-exhaustive enums are never considered uninhabited outside their +// defining crate, and non-exhaustive structs are considered uninhabited the same way as normal +// ones. fn main() { match uninhabited_enum() { - Some(_x) => (), // This line would normally error. + Some(_x) => (), // This would error without `non_exhaustive` None => (), } match uninhabited_variant() { - Some(_x) => (), // This line would normally error. + Some(_x) => (), //~ ERROR unreachable None => (), } // This line would normally error. - while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() { - } + while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {} //~ ERROR unreachable - while let Some(_x) = uninhabited_struct() { // This line would normally error. + while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable } - while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error. + while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable } } diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.stderr new file mode 100644 index 0000000000000..1bb07fd06713c --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.stderr @@ -0,0 +1,42 @@ +error: unreachable pattern + --> $DIR/patterns.rs:42:9 + | +LL | Some(_x) => (), + | ^^^^^^^^------- + | | + | matches no values because `UninhabitedVariants` is uninhabited + | help: remove the match arm + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types +note: the lint level is defined here + --> $DIR/patterns.rs:3:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns.rs:47:15 + | +LL | while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: unreachable pattern + --> $DIR/patterns.rs:49:15 + | +LL | while let Some(_x) = uninhabited_struct() { + | ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: unreachable pattern + --> $DIR/patterns.rs:52:15 + | +LL | while let Some(_x) = uninhabited_tuple_struct() { + | ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: aborting due to 4 previous errors + diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs index 1194d7b858d60..3d89ca15d3778 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs @@ -1,3 +1,4 @@ +#![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] #![feature(never_type)] @@ -6,11 +7,12 @@ pub enum UninhabitedEnum { } #[non_exhaustive] -pub struct UninhabitedTupleStruct(!); +pub struct UninhabitedTupleStruct(pub !); #[non_exhaustive] pub struct UninhabitedStruct { - _priv: !, + pub never: !, + _priv: (), } pub enum UninhabitedVariants { diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr index 7e7dc802e7fbf..bd70a7b409149 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr @@ -1,26 +1,32 @@ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:51:9 + --> $DIR/patterns_same_crate.rs:53:9 | LL | Some(_x) => (), - | ^^^^^^^^ matches no values because `UninhabitedEnum` is uninhabited + | ^^^^^^^^------- + | | + | matches no values because `UninhabitedEnum` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here - --> $DIR/patterns_same_crate.rs:1:9 + --> $DIR/patterns_same_crate.rs:2:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:56:9 + --> $DIR/patterns_same_crate.rs:58:9 | LL | Some(_x) => (), - | ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited + | ^^^^^^^^------- + | | + | matches no values because `UninhabitedVariants` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/patterns_same_crate.rs:60:15 + --> $DIR/patterns_same_crate.rs:62:15 | LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited @@ -28,7 +34,7 @@ LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabite = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/patterns_same_crate.rs:64:15 + --> $DIR/patterns_same_crate.rs:66:15 | LL | while let Some(_x) = uninhabited_struct() { | ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited @@ -36,7 +42,7 @@ LL | while let Some(_x) = uninhabited_struct() { = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/patterns_same_crate.rs:67:15 + --> $DIR/patterns_same_crate.rs:69:15 | LL | while let Some(_x) = uninhabited_tuple_struct() { | ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs index 348bf839b6995..ea3cbabf3020b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs @@ -39,7 +39,6 @@ impl const Foo for NonConstAdd { #[const_trait] trait Baz { type Qux: Add; - //~^ ERROR the trait bound } impl const Baz for NonConstAdd { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr index 405212b52c7c7..c20b53c210fe6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr @@ -12,17 +12,5 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -error[E0277]: the trait bound `Add::{synthetic#0}: Compat` is not satisfied - --> $DIR/assoc-type.rs:41:15 - | -LL | type Qux: Add; - | ^^^ the trait `Compat` is not implemented for `Add::{synthetic#0}` - | -help: consider further restricting the associated type - | -LL | trait Baz where Add::{synthetic#0}: Compat { - | ++++++++++++++++++++++++++++++++ - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs index cd5fa60994720..7b57e0405af98 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs @@ -1,6 +1,5 @@ //@ known-bug: #110395 #![feature(const_trait_impl)] -#![feature(const_mut_refs)] // #![cfg_attr(precise, feature(const_precise_live_drops))] use std::marker::{Destruct, PhantomData}; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr index 1d56d015dfc15..faf24c6d91145 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr @@ -1,5 +1,5 @@ error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop-fail-2.rs:40:25 + --> $DIR/const-drop-fail-2.rs:39:25 | LL | impl const Drop for ConstDropImplWithNonConstBounds { | ^^^^ @@ -8,13 +8,13 @@ LL | impl const Drop for ConstDropImplWithNonConstBounds { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail-2.rs:21:26 + --> $DIR/const-drop-fail-2.rs:20:26 | LL | const fn check(_: T) {} | ^^^^^^^^ error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/const-drop-fail-2.rs:21:36 + --> $DIR/const-drop-fail-2.rs:20:36 | LL | const fn check(_: T) {} | ^ - value is dropped here @@ -22,7 +22,7 @@ LL | const fn check(_: T) {} | the destructor for this type cannot be evaluated in constant functions error[E0015]: cannot call non-const fn `::a` in constant functions - --> $DIR/const-drop-fail-2.rs:42:9 + --> $DIR/const-drop-fail-2.rs:41:9 | LL | T::a(); | ^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr index b251d84a9670e..3d400bf015871 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr @@ -1,5 +1,5 @@ error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop-fail.rs:20:12 + --> $DIR/const-drop-fail.rs:19:12 | LL | impl const Drop for ConstImplWithDropGlue { | ^^^^ @@ -8,13 +8,13 @@ LL | impl const Drop for ConstImplWithDropGlue { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail.rs:24:26 + --> $DIR/const-drop-fail.rs:23:26 | LL | const fn check(_: T) {} | ^^^^^^^^ error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/const-drop-fail.rs:24:36 + --> $DIR/const-drop-fail.rs:23:36 | LL | const fn check(_: T) {} | ^ the destructor for this type cannot be evaluated in constant functions @@ -27,12 +27,12 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::drop_in_place:: - shim(Some(NonTrivialDrop))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `check::` - --> $DIR/const-drop-fail.rs:24:43 + --> $DIR/const-drop-fail.rs:23:43 | LL | const fn check(_: T) {} | ^ note: inside `_` - --> $DIR/const-drop-fail.rs:28:23 + --> $DIR/const-drop-fail.rs:27:23 | LL | const _: () = check($exp); | ^^^^^^^^^^^ @@ -54,12 +54,12 @@ note: inside `std::ptr::drop_in_place:: - shim(Some(NonTrivialDr note: inside `std::ptr::drop_in_place:: - shim(Some(ConstImplWithDropGlue))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `check::` - --> $DIR/const-drop-fail.rs:24:43 + --> $DIR/const-drop-fail.rs:23:43 | LL | const fn check(_: T) {} | ^ note: inside `_` - --> $DIR/const-drop-fail.rs:28:23 + --> $DIR/const-drop-fail.rs:27:23 | LL | const _: () = check($exp); | ^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs index a9640816b893d..5a98c32e83887 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs @@ -2,7 +2,6 @@ //@ revisions: stock precise #![feature(const_trait_impl)] -#![feature(const_mut_refs)] #![cfg_attr(precise, feature(const_precise_live_drops))] use std::marker::{Destruct, PhantomData}; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr index 912700f2a8345..fd0f6d02684a6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr @@ -1,5 +1,5 @@ error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop-fail.rs:20:12 + --> $DIR/const-drop-fail.rs:19:12 | LL | impl const Drop for ConstImplWithDropGlue { | ^^^^ @@ -8,13 +8,13 @@ LL | impl const Drop for ConstImplWithDropGlue { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail.rs:24:26 + --> $DIR/const-drop-fail.rs:23:26 | LL | const fn check(_: T) {} | ^^^^^^^^ error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/const-drop-fail.rs:24:36 + --> $DIR/const-drop-fail.rs:23:36 | LL | const fn check(_: T) {} | ^ - value is dropped here diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr index b451555ec3ccd..dd3ea5d241d76 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr @@ -1,5 +1,5 @@ error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop.rs:13:16 + --> $DIR/const-drop.rs:12:16 | LL | impl<'a> const Drop for S<'a> { | ^^^^ @@ -8,7 +8,7 @@ LL | impl<'a> const Drop for S<'a> { = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop.rs:47:16 + --> $DIR/const-drop.rs:46:16 | LL | impl const Drop for ConstDrop { | ^^^^ @@ -17,7 +17,7 @@ LL | impl const Drop for ConstDrop { = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop.rs:68:37 + --> $DIR/const-drop.rs:67:37 | LL | impl const Drop for ConstDropWithBound { | ^^^^ @@ -26,7 +26,7 @@ LL | impl const Drop for ConstDropWithBound { = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop.rs:76:30 + --> $DIR/const-drop.rs:75:30 | LL | impl const Drop for ConstDropWithNonconstBound { | ^^^^ @@ -35,13 +35,13 @@ LL | impl const Drop for ConstDropWithNonconstBound { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop.rs:19:22 + --> $DIR/const-drop.rs:18:22 | LL | const fn a(_: T) {} | ^^^^^^^^ error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-drop.rs:54:5 + --> $DIR/const-drop.rs:53:5 | LL | #[const_trait] | ^^^^^^^^^^^^^^ found 1 const parameter @@ -50,7 +50,7 @@ LL | fn foo(); | - expected 0 const parameters error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-drop.rs:54:5 + --> $DIR/const-drop.rs:53:5 | LL | #[const_trait] | ^^^^^^^^^^^^^^ found 1 const parameter @@ -61,13 +61,13 @@ LL | fn foo(); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/const-drop.rs:19:32 + --> $DIR/const-drop.rs:18:32 | LL | const fn a(_: T) {} | ^ the destructor for this type cannot be evaluated in constant functions error[E0015]: cannot call non-const fn `::foo` in constant functions - --> $DIR/const-drop.rs:70:13 + --> $DIR/const-drop.rs:69:13 | LL | T::foo(); | ^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs index 4ab1704a9fbbf..5bd81fb3ab631 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs @@ -2,7 +2,6 @@ //@ known-bug: #110395 //@ revisions: stock precise #![feature(const_trait_impl)] -#![feature(const_mut_refs)] #![feature(never_type)] #![cfg_attr(precise, feature(const_precise_live_drops))] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr index 296614f7fd076..aa59e1c8dc492 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr @@ -1,5 +1,5 @@ error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop.rs:13:16 + --> $DIR/const-drop.rs:12:16 | LL | impl<'a> const Drop for S<'a> { | ^^^^ @@ -8,7 +8,7 @@ LL | impl<'a> const Drop for S<'a> { = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop.rs:47:16 + --> $DIR/const-drop.rs:46:16 | LL | impl const Drop for ConstDrop { | ^^^^ @@ -17,7 +17,7 @@ LL | impl const Drop for ConstDrop { = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop.rs:68:37 + --> $DIR/const-drop.rs:67:37 | LL | impl const Drop for ConstDropWithBound { | ^^^^ @@ -26,7 +26,7 @@ LL | impl const Drop for ConstDropWithBound { = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` - --> $DIR/const-drop.rs:76:30 + --> $DIR/const-drop.rs:75:30 | LL | impl const Drop for ConstDropWithNonconstBound { | ^^^^ @@ -35,13 +35,13 @@ LL | impl const Drop for ConstDropWithNonconstBound { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop.rs:19:22 + --> $DIR/const-drop.rs:18:22 | LL | const fn a(_: T) {} | ^^^^^^^^ error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-drop.rs:54:5 + --> $DIR/const-drop.rs:53:5 | LL | #[const_trait] | ^^^^^^^^^^^^^^ found 1 const parameter @@ -50,7 +50,7 @@ LL | fn foo(); | - expected 0 const parameters error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-drop.rs:54:5 + --> $DIR/const-drop.rs:53:5 | LL | #[const_trait] | ^^^^^^^^^^^^^^ found 1 const parameter @@ -61,7 +61,7 @@ LL | fn foo(); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/const-drop.rs:19:32 + --> $DIR/const-drop.rs:18:32 | LL | const fn a(_: T) {} | ^ - value is dropped here @@ -69,7 +69,7 @@ LL | const fn a(_: T) {} | the destructor for this type cannot be evaluated in constant functions error[E0015]: cannot call non-const fn `::foo` in constant functions - --> $DIR/const-drop.rs:70:13 + --> $DIR/const-drop.rs:69:13 | LL | T::foo(); | ^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr index 7db6a77c77bf6..698b1b5b57817 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr @@ -1,3 +1,11 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/const-trait-bounds.rs:4:39 + | +LL | #![feature(const_trait_impl, effects, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + error[E0284]: type annotations needed: cannot normalize `process::{constant#0}` --> $DIR/const-trait-bounds.rs:12:35 | @@ -16,6 +24,6 @@ error[E0284]: type annotations needed: cannot normalize `process::{constant#1 LL | input | ^^^^^ cannot normalize `process::{constant#1}` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index 3c6d4757fea2a..1c3c66bc3ce76 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs @@ -9,7 +9,7 @@ #![crate_type = "lib"] #![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs, staged_api)] #![feature(fundamental, marker_trait_attr)] -#![feature(const_trait_impl, effects, const_mut_refs)] +#![feature(const_trait_impl, effects)] #![allow(internal_features, incomplete_features)] #![no_std] #![no_core] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs index 47f9fc664cef5..13c469d656cfc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs @@ -3,7 +3,7 @@ //@ check-pass #![allow(incomplete_features)] -#![feature(const_trait_impl, effects, associated_type_defaults, const_mut_refs)] +#![feature(const_trait_impl, effects, associated_type_defaults)] #[cfg_attr(any(yn, yy), const_trait)] pub trait Index { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs index c50c755f667fc..5fffe54fc1a99 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs @@ -1,3 +1,4 @@ +//@ known-bug: unknown // Ensure that we print unsatisfied always-const trait bounds as `const Trait` in diagnostics. //@ compile-flags: -Znext-solver @@ -19,7 +20,7 @@ impl Trait for Ty { fn main() { // FIXME(effects): improve diagnostics on this - require::(); //~ ERROR the trait bound `Trait::{synthetic#0}: const Compat` is not satisfied + require::(); } struct Container; @@ -27,9 +28,7 @@ struct Container; // FIXME(effects): Somehow emit `the trait bound `T: const Trait` is not satisfied` here instead // and suggest changing `Trait` to `const Trait`. fn accept0(_: Container<{ T::make() }>) {} -//~^ ERROR mismatched types // FIXME(effects): Instead of suggesting `+ const Trait`, suggest // changing `~const Trait` to `const Trait`. const fn accept1(_: Container<{ T::make() }>) {} -//~^ ERROR mismatched types diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr index b9f6c9e883562..0806ffa4b5df6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr @@ -1,5 +1,13 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/unsatisfied-const-trait-bound.rs:5:39 + | +LL | #![feature(const_trait_impl, effects, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + error[E0308]: mismatched types - --> $DIR/unsatisfied-const-trait-bound.rs:29:37 + --> $DIR/unsatisfied-const-trait-bound.rs:30:37 | LL | fn accept0(_: Container<{ T::make() }>) {} | ^^^^^^^^^ expected `false`, found `true` @@ -17,18 +25,18 @@ LL | const fn accept1(_: Container<{ T::make() }>) {} found constant `host` error[E0277]: the trait bound `Trait::{synthetic#0}: const Compat` is not satisfied - --> $DIR/unsatisfied-const-trait-bound.rs:22:15 + --> $DIR/unsatisfied-const-trait-bound.rs:23:15 | LL | require::(); | ^^ the trait `const Compat` is not implemented for `Trait::{synthetic#0}` | note: required by a bound in `require` - --> $DIR/unsatisfied-const-trait-bound.rs:7:15 + --> $DIR/unsatisfied-const-trait-bound.rs:8:15 | LL | fn require() {} | ^^^^^^^^^^^ required by this bound in `require` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rust-2024/gen-kw.e2015.stderr b/tests/ui/rust-2024/gen-kw.e2015.stderr index b1074f77e0089..ff552f663c741 100644 --- a/tests/ui/rust-2024/gen-kw.e2015.stderr +++ b/tests/ui/rust-2024/gen-kw.e2015.stderr @@ -31,5 +31,14 @@ LL | () => { mod test { fn gen() {} } } = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! = note: for more information, see issue #49716 -error: aborting due to 3 previous errors +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:25:9 + | +LL | fn test<'gen>() {} + | ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 + +error: aborting due to 4 previous errors diff --git a/tests/ui/rust-2024/gen-kw.e2018.stderr b/tests/ui/rust-2024/gen-kw.e2018.stderr index b902cff7fdbc3..efa812069c386 100644 --- a/tests/ui/rust-2024/gen-kw.e2018.stderr +++ b/tests/ui/rust-2024/gen-kw.e2018.stderr @@ -31,5 +31,14 @@ LL | () => { mod test { fn gen() {} } } = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! = note: for more information, see issue #49716 -error: aborting due to 3 previous errors +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:25:9 + | +LL | fn test<'gen>() {} + | ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 + +error: aborting due to 4 previous errors diff --git a/tests/ui/rust-2024/gen-kw.rs b/tests/ui/rust-2024/gen-kw.rs index 04251cbcac47b..5a658470c0a8e 100644 --- a/tests/ui/rust-2024/gen-kw.rs +++ b/tests/ui/rust-2024/gen-kw.rs @@ -22,4 +22,9 @@ macro_rules! t { //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! } +fn test<'gen>() {} +//~^ ERROR `gen` is a keyword in the 2024 edition +//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! +//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + t!(); diff --git a/tests/ui/rust-2024/raw-gen-lt.rs b/tests/ui/rust-2024/raw-gen-lt.rs new file mode 100644 index 0000000000000..b2df217d1a1fa --- /dev/null +++ b/tests/ui/rust-2024/raw-gen-lt.rs @@ -0,0 +1,8 @@ +//@ edition: 2021 +//@ check-pass + +#![deny(keyword_idents_2024)] + +fn foo<'r#gen>() {} + +fn main() {} diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs index 8bf9f97e0b91d..a544c8ea0d154 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs @@ -11,8 +11,7 @@ impl Foo { //~^ ERROR: `R` cannot be used as the type of `self` //~| ERROR destructor of `R` cannot be evaluated at compile-time self.0 - //~^ ERROR cannot borrow here, since the borrowed element may contain interior mutability - //~| ERROR cannot call non-const fn `::deref` in constant function + //~^ ERROR cannot call non-const fn `::deref` in constant function } } diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index 9e3851f9a6e72..505b0a173fada 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -1,13 +1,3 @@ -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9 - | -LL | self.0 - | ^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0015]: cannot call non-const fn `::deref` in constant functions --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9 | @@ -40,7 +30,7 @@ LL | const fn get>(self: R) -> u32 { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0015, E0493, E0658. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs b/tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs index 1f45d91847f97..7f76ed7fd2a59 100644 --- a/tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs +++ b/tests/ui/self/arbitrary_self_types_raw_pointer_struct.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(arbitrary_self_types)] +#![feature(arbitrary_self_types_pointers)] use std::rc::Rc; diff --git a/tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs b/tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs index 43f596659b9cd..6f34c9281b074 100644 --- a/tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs +++ b/tests/ui/self/arbitrary_self_types_raw_pointer_trait.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(arbitrary_self_types)] +#![feature(arbitrary_self_types_pointers)] use std::ptr; diff --git a/tests/ui/self/where-for-self.rs b/tests/ui/self/where-for-self.rs index 9b4e83256645d..d31bb1f22c4ce 100644 --- a/tests/ui/self/where-for-self.rs +++ b/tests/ui/self/where-for-self.rs @@ -2,6 +2,8 @@ // Test that we can quantify lifetimes outside a constraint (i.e., including // the self type) in a where clause. +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] static mut COUNT: u32 = 1; diff --git a/tests/ui/simd/const-err-trumps-simd-err.rs b/tests/ui/simd/const-err-trumps-simd-err.rs index fda044344517d..fb87fe1cbca83 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.rs +++ b/tests/ui/simd/const-err-trumps-simd-err.rs @@ -10,7 +10,7 @@ use std::intrinsics::simd::*; #[repr(simd)] #[allow(non_camel_case_types)] -struct int8x4_t(u8,u8,u8,u8); +struct int8x4_t([u8; 4]); fn get_elem(a: int8x4_t) -> u8 { const { assert!(LANE < 4); } // the error should be here... @@ -20,5 +20,5 @@ fn get_elem(a: int8x4_t) -> u8 { } fn main() { - get_elem::<4>(int8x4_t(0,0,0,0)); + get_elem::<4>(int8x4_t([0, 0, 0, 0])); } diff --git a/tests/ui/simd/const-err-trumps-simd-err.stderr b/tests/ui/simd/const-err-trumps-simd-err.stderr index 1e46667cf4e2a..11cbcad227ff8 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.stderr +++ b/tests/ui/simd/const-err-trumps-simd-err.stderr @@ -15,8 +15,8 @@ LL | const { assert!(LANE < 4); } // the error should be here... note: the above error was encountered while instantiating `fn get_elem::<4>` --> $DIR/const-err-trumps-simd-err.rs:23:5 | -LL | get_elem::<4>(int8x4_t(0,0,0,0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | get_elem::<4>(int8x4_t([0, 0, 0, 0])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/simd/generics.rs b/tests/ui/simd/generics.rs index bd048b19ca886..f96a7cd75e933 100644 --- a/tests/ui/simd/generics.rs +++ b/tests/ui/simd/generics.rs @@ -6,7 +6,7 @@ use std::ops; #[repr(simd)] #[derive(Copy, Clone)] -struct f32x4(f32, f32, f32, f32); +struct f32x4([f32; 4]); #[repr(simd)] #[derive(Copy, Clone)] @@ -67,8 +67,8 @@ pub fn main() { let y = [2.0f32, 4.0f32, 6.0f32, 8.0f32]; // lame-o - let a = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32); - let f32x4(a0, a1, a2, a3) = add(a, a); + let a = f32x4([1.0f32, 2.0f32, 3.0f32, 4.0f32]); + let f32x4([a0, a1, a2, a3]) = add(a, a); assert_eq!(a0, 2.0f32); assert_eq!(a1, 4.0f32); assert_eq!(a2, 6.0f32); diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs index ea31e2a7c570e..9b14d410acbe3 100644 --- a/tests/ui/simd/intrinsic/float-math-pass.rs +++ b/tests/ui/simd/intrinsic/float-math-pass.rs @@ -13,7 +13,7 @@ #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); +struct f32x4(pub [f32; 4]); extern "rust-intrinsic" { fn simd_fsqrt(x: T) -> T; @@ -47,19 +47,19 @@ macro_rules! assert_approx_eq { ($a:expr, $b:expr) => ({ let a = $a; let b = $b; - assert_approx_eq_f32!(a.0, b.0); - assert_approx_eq_f32!(a.1, b.1); - assert_approx_eq_f32!(a.2, b.2); - assert_approx_eq_f32!(a.3, b.3); + assert_approx_eq_f32!(a.0[0], b.0[0]); + assert_approx_eq_f32!(a.0[1], b.0[1]); + assert_approx_eq_f32!(a.0[2], b.0[2]); + assert_approx_eq_f32!(a.0[3], b.0[3]); }) } fn main() { - let x = f32x4(1.0, 1.0, 1.0, 1.0); - let y = f32x4(-1.0, -1.0, -1.0, -1.0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); + let x = f32x4([1.0, 1.0, 1.0, 1.0]); + let y = f32x4([-1.0, -1.0, -1.0, -1.0]); + let z = f32x4([0.0, 0.0, 0.0, 0.0]); - let h = f32x4(0.5, 0.5, 0.5, 0.5); + let h = f32x4([0.5, 0.5, 0.5, 0.5]); unsafe { let r = simd_fabs(y); diff --git a/tests/ui/simd/intrinsic/float-minmax-pass.rs b/tests/ui/simd/intrinsic/float-minmax-pass.rs index d6cbcd4e05a63..00c0d8cea3fa5 100644 --- a/tests/ui/simd/intrinsic/float-minmax-pass.rs +++ b/tests/ui/simd/intrinsic/float-minmax-pass.rs @@ -8,13 +8,13 @@ #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); +struct f32x4(pub [f32; 4]); use std::intrinsics::simd::*; fn main() { - let x = f32x4(1.0, 2.0, 3.0, 4.0); - let y = f32x4(2.0, 1.0, 4.0, 3.0); + let x = f32x4([1.0, 2.0, 3.0, 4.0]); + let y = f32x4([2.0, 1.0, 4.0, 3.0]); #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] let nan = f32::NAN; @@ -23,13 +23,13 @@ fn main() { #[cfg(any(target_arch = "mips", target_arch = "mips64"))] let nan = f32::from_bits(f32::NAN.to_bits() - 1); - let n = f32x4(nan, nan, nan, nan); + let n = f32x4([nan, nan, nan, nan]); unsafe { let min0 = simd_fmin(x, y); let min1 = simd_fmin(y, x); assert_eq!(min0, min1); - let e = f32x4(1.0, 1.0, 3.0, 3.0); + let e = f32x4([1.0, 1.0, 3.0, 3.0]); assert_eq!(min0, e); let minn = simd_fmin(x, n); assert_eq!(minn, x); @@ -39,7 +39,7 @@ fn main() { let max0 = simd_fmax(x, y); let max1 = simd_fmax(y, x); assert_eq!(max0, max1); - let e = f32x4(2.0, 2.0, 4.0, 4.0); + let e = f32x4([2.0, 2.0, 4.0, 4.0]); assert_eq!(max0, e); let maxn = simd_fmax(x, n); assert_eq!(maxn, x); diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs index fc3087cbf7542..663bcdf198193 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs @@ -4,15 +4,15 @@ #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone)] -pub struct i32x4(pub i32, pub i32, pub i32, pub i32); +pub struct i32x4(pub [i32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -pub struct u32x4(pub u32, pub u32, pub u32, pub u32); +pub struct u32x4(pub [u32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -pub struct f32x4(pub f32, pub f32, pub f32, pub f32); +pub struct f32x4(pub [f32; 4]); extern "rust-intrinsic" { fn simd_add(x: T, y: T) -> T; @@ -35,9 +35,9 @@ extern "rust-intrinsic" { } fn main() { - let x = i32x4(0, 0, 0, 0); - let y = u32x4(0, 0, 0, 0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); + let x = i32x4([0, 0, 0, 0]); + let y = u32x4([0, 0, 0, 0]); + let z = f32x4([0.0, 0.0, 0.0, 0.0]); unsafe { simd_add(x, x); diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs index 60dfa62741488..e4eb2a9da2718 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs @@ -5,7 +5,7 @@ #[repr(simd)] #[derive(Copy, Clone)] -struct i32x4(pub i32, pub i32, pub i32, pub i32); +struct i32x4(pub [i32; 4]); #[repr(simd)] #[derive(Copy, Clone)] @@ -13,17 +13,9 @@ struct U32([u32; N]); #[repr(simd)] #[derive(Copy, Clone)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); +struct f32x4(pub [f32; 4]); macro_rules! all_eq { - ($a: expr, $b: expr) => {{ - let a = $a; - let b = $b; - assert!(a.0 == b.0 && a.1 == b.1 && a.2 == b.2 && a.3 == b.3); - }}; -} - -macro_rules! all_eq_ { ($a: expr, $b: expr) => {{ let a = $a; let b = $b; @@ -52,112 +44,112 @@ extern "rust-intrinsic" { } fn main() { - let x1 = i32x4(1, 2, 3, 4); + let x1 = i32x4([1, 2, 3, 4]); let y1 = U32::<4>([1, 2, 3, 4]); - let z1 = f32x4(1.0, 2.0, 3.0, 4.0); - let x2 = i32x4(2, 3, 4, 5); + let z1 = f32x4([1.0, 2.0, 3.0, 4.0]); + let x2 = i32x4([2, 3, 4, 5]); let y2 = U32::<4>([2, 3, 4, 5]); - let z2 = f32x4(2.0, 3.0, 4.0, 5.0); - let x3 = i32x4(0, i32::MAX, i32::MIN, -1_i32); + let z2 = f32x4([2.0, 3.0, 4.0, 5.0]); + let x3 = i32x4([0, i32::MAX, i32::MIN, -1_i32]); let y3 = U32::<4>([0, i32::MAX as _, i32::MIN as _, -1_i32 as _]); unsafe { - all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9)); - all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9)); - all_eq_!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9])); - all_eq_!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9])); - all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0)); - all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0)); - - all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20)); - all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20)); - all_eq_!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20])); - all_eq_!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20])); - all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0)); - all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0)); - - all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1)); - all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1)); - all_eq_!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1])); - all_eq_!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0])); - all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0)); - all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0)); - - all_eq!(simd_div(x1, x1), i32x4(1, 1, 1, 1)); - all_eq!(simd_div(i32x4(2, 4, 6, 8), i32x4(2, 2, 2, 2)), x1); - all_eq_!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1])); - all_eq_!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1); - all_eq!(simd_div(z1, z1), f32x4(1.0, 1.0, 1.0, 1.0)); - all_eq!(simd_div(z1, z2), f32x4(1.0 / 2.0, 2.0 / 3.0, 3.0 / 4.0, 4.0 / 5.0)); - all_eq!(simd_div(z2, z1), f32x4(2.0 / 1.0, 3.0 / 2.0, 4.0 / 3.0, 5.0 / 4.0)); - - all_eq!(simd_rem(x1, x1), i32x4(0, 0, 0, 0)); - all_eq!(simd_rem(x2, x1), i32x4(0, 1, 1, 1)); - all_eq_!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0])); - all_eq_!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1])); - all_eq!(simd_rem(z1, z1), f32x4(0.0, 0.0, 0.0, 0.0)); + all_eq!(simd_add(x1, x2), i32x4([3, 5, 7, 9])); + all_eq!(simd_add(x2, x1), i32x4([3, 5, 7, 9])); + all_eq!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9])); + all_eq!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9])); + all_eq!(simd_add(z1, z2), f32x4([3.0, 5.0, 7.0, 9.0])); + all_eq!(simd_add(z2, z1), f32x4([3.0, 5.0, 7.0, 9.0])); + + all_eq!(simd_mul(x1, x2), i32x4([2, 6, 12, 20])); + all_eq!(simd_mul(x2, x1), i32x4([2, 6, 12, 20])); + all_eq!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20])); + all_eq!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20])); + all_eq!(simd_mul(z1, z2), f32x4([2.0, 6.0, 12.0, 20.0])); + all_eq!(simd_mul(z2, z1), f32x4([2.0, 6.0, 12.0, 20.0])); + + all_eq!(simd_sub(x2, x1), i32x4([1, 1, 1, 1])); + all_eq!(simd_sub(x1, x2), i32x4([-1, -1, -1, -1])); + all_eq!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1])); + all_eq!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0])); + all_eq!(simd_sub(z2, z1), f32x4([1.0, 1.0, 1.0, 1.0])); + all_eq!(simd_sub(z1, z2), f32x4([-1.0, -1.0, -1.0, -1.0])); + + all_eq!(simd_div(x1, x1), i32x4([1, 1, 1, 1])); + all_eq!(simd_div(i32x4([2, 4, 6, 8]), i32x4([2, 2, 2, 2])), x1); + all_eq!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1])); + all_eq!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1); + all_eq!(simd_div(z1, z1), f32x4([1.0, 1.0, 1.0, 1.0])); + all_eq!(simd_div(z1, z2), f32x4([1.0 / 2.0, 2.0 / 3.0, 3.0 / 4.0, 4.0 / 5.0])); + all_eq!(simd_div(z2, z1), f32x4([2.0 / 1.0, 3.0 / 2.0, 4.0 / 3.0, 5.0 / 4.0])); + + all_eq!(simd_rem(x1, x1), i32x4([0, 0, 0, 0])); + all_eq!(simd_rem(x2, x1), i32x4([0, 1, 1, 1])); + all_eq!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0])); + all_eq!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1])); + all_eq!(simd_rem(z1, z1), f32x4([0.0, 0.0, 0.0, 0.0])); all_eq!(simd_rem(z1, z2), z1); - all_eq!(simd_rem(z2, z1), f32x4(0.0, 1.0, 1.0, 1.0)); + all_eq!(simd_rem(z2, z1), f32x4([0.0, 1.0, 1.0, 1.0])); - all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); - all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); - all_eq_!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); - all_eq_!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4])); + all_eq!(simd_shl(x1, x2), i32x4([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq!(simd_shl(x2, x1), i32x4([2 << 1, 3 << 2, 4 << 3, 5 << 4])); + all_eq!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4])); // test right-shift by assuming left-shift is correct all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); all_eq!(simd_shr(simd_shl(x2, x1), x1), x2); - all_eq_!(simd_shr(simd_shl(y1, y2), y2), y1); - all_eq_!(simd_shr(simd_shl(y2, y1), y1), y2); + all_eq!(simd_shr(simd_shl(y1, y2), y2), y1); + all_eq!(simd_shr(simd_shl(y2, y1), y1), y2); // ensure we get logical vs. arithmetic shifts correct let (a, b, c, d) = (-12, -123, -1234, -12345); - all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4)); - all_eq_!( + all_eq!(simd_shr(i32x4([a, b, c, d]), x1), i32x4([a >> 1, b >> 2, c >> 3, d >> 4])); + all_eq!( simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1), U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4]) ); - all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4)); - all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4)); - all_eq_!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4])); - all_eq_!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4])); + all_eq!(simd_and(x1, x2), i32x4([0, 2, 0, 4])); + all_eq!(simd_and(x2, x1), i32x4([0, 2, 0, 4])); + all_eq!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4])); + all_eq!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4])); - all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5)); - all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5)); - all_eq_!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5])); - all_eq_!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5])); + all_eq!(simd_or(x1, x2), i32x4([3, 3, 7, 5])); + all_eq!(simd_or(x2, x1), i32x4([3, 3, 7, 5])); + all_eq!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5])); + all_eq!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5])); - all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1)); - all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1)); - all_eq_!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1])); - all_eq_!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); + all_eq!(simd_xor(x1, x2), i32x4([3, 1, 7, 1])); + all_eq!(simd_xor(x2, x1), i32x4([3, 1, 7, 1])); + all_eq!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1])); + all_eq!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); - all_eq!(simd_neg(x1), i32x4(-1, -2, -3, -4)); - all_eq!(simd_neg(x2), i32x4(-2, -3, -4, -5)); - all_eq!(simd_neg(z1), f32x4(-1.0, -2.0, -3.0, -4.0)); - all_eq!(simd_neg(z2), f32x4(-2.0, -3.0, -4.0, -5.0)); + all_eq!(simd_neg(x1), i32x4([-1, -2, -3, -4])); + all_eq!(simd_neg(x2), i32x4([-2, -3, -4, -5])); + all_eq!(simd_neg(z1), f32x4([-1.0, -2.0, -3.0, -4.0])); + all_eq!(simd_neg(z2), f32x4([-2.0, -3.0, -4.0, -5.0])); - all_eq!(simd_bswap(x1), i32x4(0x01000000, 0x02000000, 0x03000000, 0x04000000)); - all_eq_!(simd_bswap(y1), U32::<4>([0x01000000, 0x02000000, 0x03000000, 0x04000000])); + all_eq!(simd_bswap(x1), i32x4([0x01000000, 0x02000000, 0x03000000, 0x04000000])); + all_eq!(simd_bswap(y1), U32::<4>([0x01000000, 0x02000000, 0x03000000, 0x04000000])); all_eq!( simd_bitreverse(x1), - i32x4(0x80000000u32 as i32, 0x40000000, 0xc0000000u32 as i32, 0x20000000) + i32x4([0x80000000u32 as i32, 0x40000000, 0xc0000000u32 as i32, 0x20000000]) ); - all_eq_!(simd_bitreverse(y1), U32::<4>([0x80000000, 0x40000000, 0xc0000000, 0x20000000])); + all_eq!(simd_bitreverse(y1), U32::<4>([0x80000000, 0x40000000, 0xc0000000, 0x20000000])); - all_eq!(simd_ctlz(x1), i32x4(31, 30, 30, 29)); - all_eq_!(simd_ctlz(y1), U32::<4>([31, 30, 30, 29])); + all_eq!(simd_ctlz(x1), i32x4([31, 30, 30, 29])); + all_eq!(simd_ctlz(y1), U32::<4>([31, 30, 30, 29])); - all_eq!(simd_ctpop(x1), i32x4(1, 1, 2, 1)); - all_eq_!(simd_ctpop(y1), U32::<4>([1, 1, 2, 1])); - all_eq!(simd_ctpop(x2), i32x4(1, 2, 1, 2)); - all_eq_!(simd_ctpop(y2), U32::<4>([1, 2, 1, 2])); - all_eq!(simd_ctpop(x3), i32x4(0, 31, 1, 32)); - all_eq_!(simd_ctpop(y3), U32::<4>([0, 31, 1, 32])); + all_eq!(simd_ctpop(x1), i32x4([1, 1, 2, 1])); + all_eq!(simd_ctpop(y1), U32::<4>([1, 1, 2, 1])); + all_eq!(simd_ctpop(x2), i32x4([1, 2, 1, 2])); + all_eq!(simd_ctpop(y2), U32::<4>([1, 2, 1, 2])); + all_eq!(simd_ctpop(x3), i32x4([0, 31, 1, 32])); + all_eq!(simd_ctpop(y3), U32::<4>([0, 31, 1, 32])); - all_eq!(simd_cttz(x1), i32x4(0, 1, 0, 2)); - all_eq_!(simd_cttz(y1), U32::<4>([0, 1, 0, 2])); + all_eq!(simd_cttz(x1), i32x4([0, 1, 0, 2])); + all_eq!(simd_cttz(y1), U32::<4>([0, 1, 0, 2])); } } diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs index 36be8cc62a8c8..ec6ac78df1a7a 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs @@ -4,15 +4,15 @@ #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone)] -pub struct i32x4(pub i32, pub i32, pub i32, pub i32); +pub struct i32x4(pub [i32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -pub struct x4(pub T, pub T, pub T, pub T); +pub struct x4(pub [T; 4]); #[repr(simd)] #[derive(Copy, Clone)] -pub struct f32x4(pub f32, pub f32, pub f32, pub f32); +pub struct f32x4(pub [f32; 4]); extern "rust-intrinsic" { fn simd_saturating_add(x: T, y: T) -> T; @@ -20,9 +20,9 @@ extern "rust-intrinsic" { } fn main() { - let x = i32x4(0, 0, 0, 0); - let y = x4(0_usize, 0, 0, 0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); + let x = i32x4([0, 0, 0, 0]); + let y = x4([0_usize, 0, 0, 0]); + let z = f32x4([0.0, 0.0, 0.0, 0.0]); unsafe { simd_saturating_add(x, x); diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs index deee9c2ac41e6..57bda5c2d624e 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs @@ -6,7 +6,7 @@ #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); +struct u32x4(pub [u32; 4]); #[repr(simd)] #[derive(Copy, Clone)] @@ -22,11 +22,11 @@ fn main() { { const M: u32 = u32::MAX; - let a = u32x4(1, 2, 3, 4); - let b = u32x4(2, 4, 6, 8); - let m = u32x4(M, M, M, M); - let m1 = u32x4(M - 1, M - 1, M - 1, M - 1); - let z = u32x4(0, 0, 0, 0); + let a = u32x4([1, 2, 3, 4]); + let b = u32x4([2, 4, 6, 8]); + let m = u32x4([M, M, M, M]); + let m1 = u32x4([M - 1, M - 1, M - 1, M - 1]); + let z = u32x4([0, 0, 0, 0]); unsafe { assert_eq!(simd_saturating_add(z, z), z); diff --git a/tests/ui/simd/intrinsic/generic-bitmask-pass.rs b/tests/ui/simd/intrinsic/generic-bitmask-pass.rs index 5c6a07876e35e..db10020bd469b 100644 --- a/tests/ui/simd/intrinsic/generic-bitmask-pass.rs +++ b/tests/ui/simd/intrinsic/generic-bitmask-pass.rs @@ -11,36 +11,36 @@ #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); +struct u32x4(pub [u32; 4]); #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct u8x4(pub u8, pub u8, pub u8, pub u8); +struct u8x4(pub [u8; 4]); #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct Tx4(pub T, pub T, pub T, pub T); +struct Tx4(pub [T; 4]); extern "rust-intrinsic" { fn simd_bitmask(x: T) -> U; } fn main() { - let z = u32x4(0, 0, 0, 0); + let z = u32x4([0, 0, 0, 0]); let ez = 0_u8; - let o = u32x4(!0, !0, !0, !0); + let o = u32x4([!0, !0, !0, !0]); let eo = 0b_1111_u8; - let m0 = u32x4(!0, 0, !0, 0); + let m0 = u32x4([!0, 0, !0, 0]); let e0 = 0b_0000_0101_u8; // Check that the MSB is extracted: - let m = u8x4(0b_1000_0000, 0b_0100_0001, 0b_1100_0001, 0b_1111_1111); + let m = u8x4([0b_1000_0000, 0b_0100_0001, 0b_1100_0001, 0b_1111_1111]); let e = 0b_1101; // Check usize / isize - let msize: Tx4 = Tx4(usize::MAX, 0, usize::MAX, usize::MAX); + let msize: Tx4 = Tx4([usize::MAX, 0, usize::MAX, usize::MAX]); unsafe { let r: u8 = simd_bitmask(z); diff --git a/tests/ui/simd/intrinsic/generic-cast.rs b/tests/ui/simd/intrinsic/generic-cast.rs index f3fdbe3403f79..33978a2f7395d 100644 --- a/tests/ui/simd/intrinsic/generic-cast.rs +++ b/tests/ui/simd/intrinsic/generic-cast.rs @@ -5,22 +5,20 @@ #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); +struct i32x4([i32; 4]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); +struct i32x8([i32; 8]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct f32x4(f32, f32, f32, f32); +struct f32x4([f32; 4]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct f32x8(f32, f32, f32, f32, - f32, f32, f32, f32); +struct f32x8([f32; 8]); extern "rust-intrinsic" { @@ -28,7 +26,7 @@ extern "rust-intrinsic" { } fn main() { - let x = i32x4(0, 0, 0, 0); + let x = i32x4([0, 0, 0, 0]); unsafe { simd_cast::(0); diff --git a/tests/ui/simd/intrinsic/generic-cast.stderr b/tests/ui/simd/intrinsic/generic-cast.stderr index 2226bbbe1bd55..2f9d44037afb5 100644 --- a/tests/ui/simd/intrinsic/generic-cast.stderr +++ b/tests/ui/simd/intrinsic/generic-cast.stderr @@ -1,23 +1,23 @@ error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-cast.rs:34:9 + --> $DIR/generic-cast.rs:32:9 | LL | simd_cast::(0); | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-cast.rs:36:9 + --> $DIR/generic-cast.rs:34:9 | LL | simd_cast::(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/generic-cast.rs:38:9 + --> $DIR/generic-cast.rs:36:9 | LL | simd_cast::(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i32x8` with length 8 - --> $DIR/generic-cast.rs:40:9 + --> $DIR/generic-cast.rs:38:9 | LL | simd_cast::<_, i32x8>(x); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/intrinsic/generic-comparison-pass.rs b/tests/ui/simd/intrinsic/generic-comparison-pass.rs index a4df836b6f82a..a4d84a4c53482 100644 --- a/tests/ui/simd/intrinsic/generic-comparison-pass.rs +++ b/tests/ui/simd/intrinsic/generic-comparison-pass.rs @@ -6,13 +6,13 @@ #[repr(simd)] #[derive(Copy, Clone)] -struct i32x4(i32, i32, i32, i32); +struct i32x4([i32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); +struct u32x4(pub [u32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); +struct f32x4(pub [f32; 4]); extern "rust-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -29,10 +29,10 @@ macro_rules! cmp { let rhs = $rhs; let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs); // assume the scalar version is correct/the behaviour we want. - assert!((e.0 != 0) == lhs.0 .$method(&rhs.0)); - assert!((e.1 != 0) == lhs.1 .$method(&rhs.1)); - assert!((e.2 != 0) == lhs.2 .$method(&rhs.2)); - assert!((e.3 != 0) == lhs.3 .$method(&rhs.3)); + assert!((e.0[0] != 0) == lhs.0[0] .$method(&rhs.0[0])); + assert!((e.0[1] != 0) == lhs.0[1] .$method(&rhs.0[1])); + assert!((e.0[2] != 0) == lhs.0[2] .$method(&rhs.0[2])); + assert!((e.0[3] != 0) == lhs.0[3] .$method(&rhs.0[3])); }} } macro_rules! tests { @@ -61,17 +61,17 @@ macro_rules! tests { fn main() { // 13 vs. -100 tests that we get signed vs. unsigned comparisons // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); - let i1 = i32x4(10, -11, 12, 13); - let i2 = i32x4(5, -5, 20, -100); - let i3 = i32x4(10, -11, 20, -100); + let i1 = i32x4([10, -11, 12, 13]); + let i2 = i32x4([5, -5, 20, -100]); + let i3 = i32x4([10, -11, 20, -100]); - let u1 = u32x4(10, !11+1, 12, 13); - let u2 = u32x4(5, !5+1, 20, !100+1); - let u3 = u32x4(10, !11+1, 20, !100+1); + let u1 = u32x4([10, !11+1, 12, 13]); + let u2 = u32x4([5, !5+1, 20, !100+1]); + let u3 = u32x4([10, !11+1, 20, !100+1]); - let f1 = f32x4(10.0, -11.0, 12.0, 13.0); - let f2 = f32x4(5.0, -5.0, 20.0, -100.0); - let f3 = f32x4(10.0, -11.0, 20.0, -100.0); + let f1 = f32x4([10.0, -11.0, 12.0, 13.0]); + let f2 = f32x4([5.0, -5.0, 20.0, -100.0]); + let f3 = f32x4([10.0, -11.0, 20.0, -100.0]); unsafe { tests! { @@ -92,7 +92,7 @@ fn main() { // NAN comparisons are special: // -11 (*) 13 // -5 -100 (*) - let f4 = f32x4(f32::NAN, f1.1, f32::NAN, f2.3); + let f4 = f32x4([f32::NAN, f1.0[1], f32::NAN, f2.0[3]]); unsafe { tests! { diff --git a/tests/ui/simd/intrinsic/generic-comparison.rs b/tests/ui/simd/intrinsic/generic-comparison.rs index bb2720f615fef..f7f0655f3d244 100644 --- a/tests/ui/simd/intrinsic/generic-comparison.rs +++ b/tests/ui/simd/intrinsic/generic-comparison.rs @@ -5,12 +5,11 @@ #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); +struct i32x4([i32; 4]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i16x8(i16, i16, i16, i16, - i16, i16, i16, i16); +struct i16x8([i16; 8]); extern "rust-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -22,7 +21,7 @@ extern "rust-intrinsic" { } fn main() { - let x = i32x4(0, 0, 0, 0); + let x = i32x4([0, 0, 0, 0]); unsafe { simd_eq::(0, 0); diff --git a/tests/ui/simd/intrinsic/generic-comparison.stderr b/tests/ui/simd/intrinsic/generic-comparison.stderr index 0eae2688bced0..ac4d491882742 100644 --- a/tests/ui/simd/intrinsic/generic-comparison.stderr +++ b/tests/ui/simd/intrinsic/generic-comparison.stderr @@ -1,107 +1,107 @@ error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:28:9 + --> $DIR/generic-comparison.rs:27:9 | LL | simd_eq::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:30:9 + --> $DIR/generic-comparison.rs:29:9 | LL | simd_ne::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:32:9 + --> $DIR/generic-comparison.rs:31:9 | LL | simd_lt::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:34:9 + --> $DIR/generic-comparison.rs:33:9 | LL | simd_le::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:36:9 + --> $DIR/generic-comparison.rs:35:9 | LL | simd_gt::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:38:9 + --> $DIR/generic-comparison.rs:37:9 | LL | simd_ge::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:41:9 + --> $DIR/generic-comparison.rs:40:9 | LL | simd_eq::<_, i32>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:43:9 + --> $DIR/generic-comparison.rs:42:9 | LL | simd_ne::<_, i32>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:45:9 + --> $DIR/generic-comparison.rs:44:9 | LL | simd_lt::<_, i32>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:47:9 + --> $DIR/generic-comparison.rs:46:9 | LL | simd_le::<_, i32>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:49:9 + --> $DIR/generic-comparison.rs:48:9 | LL | simd_gt::<_, i32>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/generic-comparison.rs:51:9 + --> $DIR/generic-comparison.rs:50:9 | LL | simd_ge::<_, i32>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/generic-comparison.rs:54:9 + --> $DIR/generic-comparison.rs:53:9 | LL | simd_eq::<_, i16x8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/generic-comparison.rs:56:9 + --> $DIR/generic-comparison.rs:55:9 | LL | simd_ne::<_, i16x8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/generic-comparison.rs:58:9 + --> $DIR/generic-comparison.rs:57:9 | LL | simd_lt::<_, i16x8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/generic-comparison.rs:60:9 + --> $DIR/generic-comparison.rs:59:9 | LL | simd_le::<_, i16x8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/generic-comparison.rs:62:9 + --> $DIR/generic-comparison.rs:61:9 | LL | simd_gt::<_, i16x8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/generic-comparison.rs:64:9 + --> $DIR/generic-comparison.rs:63:9 | LL | simd_ge::<_, i16x8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index a81d8ebdf50c2..7b1bda4fbcd5f 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -6,16 +6,15 @@ #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); +struct i32x4([i32; 4]); #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); +struct i32x8([i32; 8]); extern "rust-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; @@ -24,6 +23,9 @@ extern "rust-intrinsic" { fn simd_shuffle(x: T, y: T, idx: I) -> U; } +#[repr(simd)] +struct SimdShuffleIdx([u32; LEN]); + macro_rules! all_eq { ($a: expr, $b: expr) => {{ let a = $a; @@ -31,32 +33,31 @@ macro_rules! all_eq { // type inference works better with the concrete type on the // left, but humans work better with the expected on the // right. - assert!(b == a, - "{:?} != {:?}", a, b); - }} + assert!(b == a, "{:?} != {:?}", a, b); + }}; } fn main() { - let x2 = i32x2(20, 21); - let x4 = i32x4(40, 41, 42, 43); - let x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); + let x2 = i32x2([20, 21]); + let x4 = i32x4([40, 41, 42, 43]); + let x8 = i32x8([80, 81, 82, 83, 84, 85, 86, 87]); unsafe { - all_eq!(simd_insert(x2, 0, 100), i32x2(100, 21)); - all_eq!(simd_insert(x2, 1, 100), i32x2(20, 100)); + all_eq!(simd_insert(x2, 0, 100), i32x2([100, 21])); + all_eq!(simd_insert(x2, 1, 100), i32x2([20, 100])); - all_eq!(simd_insert(x4, 0, 100), i32x4(100, 41, 42, 43)); - all_eq!(simd_insert(x4, 1, 100), i32x4(40, 100, 42, 43)); - all_eq!(simd_insert(x4, 2, 100), i32x4(40, 41, 100, 43)); - all_eq!(simd_insert(x4, 3, 100), i32x4(40, 41, 42, 100)); + all_eq!(simd_insert(x4, 0, 100), i32x4([100, 41, 42, 43])); + all_eq!(simd_insert(x4, 1, 100), i32x4([40, 100, 42, 43])); + all_eq!(simd_insert(x4, 2, 100), i32x4([40, 41, 100, 43])); + all_eq!(simd_insert(x4, 3, 100), i32x4([40, 41, 42, 100])); - all_eq!(simd_insert(x8, 0, 100), i32x8(100, 81, 82, 83, 84, 85, 86, 87)); - all_eq!(simd_insert(x8, 1, 100), i32x8(80, 100, 82, 83, 84, 85, 86, 87)); - all_eq!(simd_insert(x8, 2, 100), i32x8(80, 81, 100, 83, 84, 85, 86, 87)); - all_eq!(simd_insert(x8, 3, 100), i32x8(80, 81, 82, 100, 84, 85, 86, 87)); - all_eq!(simd_insert(x8, 4, 100), i32x8(80, 81, 82, 83, 100, 85, 86, 87)); - all_eq!(simd_insert(x8, 5, 100), i32x8(80, 81, 82, 83, 84, 100, 86, 87)); - all_eq!(simd_insert(x8, 6, 100), i32x8(80, 81, 82, 83, 84, 85, 100, 87)); - all_eq!(simd_insert(x8, 7, 100), i32x8(80, 81, 82, 83, 84, 85, 86, 100)); + all_eq!(simd_insert(x8, 0, 100), i32x8([100, 81, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 1, 100), i32x8([80, 100, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 2, 100), i32x8([80, 81, 100, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 3, 100), i32x8([80, 81, 82, 100, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 4, 100), i32x8([80, 81, 82, 83, 100, 85, 86, 87])); + all_eq!(simd_insert(x8, 5, 100), i32x8([80, 81, 82, 83, 84, 100, 86, 87])); + all_eq!(simd_insert(x8, 6, 100), i32x8([80, 81, 82, 83, 84, 85, 100, 87])); + all_eq!(simd_insert(x8, 7, 100), i32x8([80, 81, 82, 83, 84, 85, 86, 100])); all_eq!(simd_extract(x2, 0), 20); all_eq!(simd_extract(x2, 1), 21); @@ -76,24 +77,38 @@ fn main() { all_eq!(simd_extract(x8, 7), 87); } - let y2 = i32x2(120, 121); - let y4 = i32x4(140, 141, 142, 143); - let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); + let y2 = i32x2([120, 121]); + let y4 = i32x4([140, 141, 142, 143]); + let y8 = i32x8([180, 181, 182, 183, 184, 185, 186, 187]); unsafe { - all_eq!(simd_shuffle(x2, y2, const { [3u32, 0] }), i32x2(121, 20)); - all_eq!(simd_shuffle(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120)); - all_eq!(simd_shuffle(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }), - i32x8(121, 20, 21, 120, 21, 120, 121, 20)); + all_eq!(simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0]) }), i32x2([121, 20])); + all_eq!( + simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2]) }), + i32x4([121, 20, 21, 120]) + ); + all_eq!( + simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2, 1, 2, 3, 0]) }), + i32x8([121, 20, 21, 120, 21, 120, 121, 20]) + ); - all_eq!(simd_shuffle(x4, y4, const { [7u32, 2] }), i32x2(143, 42)); - all_eq!(simd_shuffle(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40)); - all_eq!(simd_shuffle(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }), - i32x8(143, 42, 141, 40, 43, 142, 140, 41)); + all_eq!(simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2]) }), i32x2([143, 42])); + all_eq!( + simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0]) }), + i32x4([143, 42, 141, 40]) + ); + all_eq!( + simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0, 3, 6, 4, 1]) }), + i32x8([143, 42, 141, 40, 43, 142, 140, 41]) + ); - all_eq!(simd_shuffle(x8, y8, const { [11u32, 5] }), i32x2(183, 85)); - all_eq!(simd_shuffle(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80)); - all_eq!(simd_shuffle(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }), - i32x8(183, 85, 187, 80, 83, 180, 184, 81)); + all_eq!(simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5]) }), i32x2([183, 85])); + all_eq!( + simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0]) }), + i32x4([183, 85, 187, 80]) + ); + all_eq!( + simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0, 3, 8, 12, 1]) }), + i32x8([183, 85, 187, 80, 83, 180, 184, 81]) + ); } - } diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs index aec75a673067e..5d784a25eab4a 100644 --- a/tests/ui/simd/intrinsic/generic-elements.rs +++ b/tests/ui/simd/intrinsic/generic-elements.rs @@ -6,28 +6,28 @@ #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i32x2(i32, i32); +struct i32x2([i32; 2]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); +struct i32x4([i32; 4]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); +struct i32x8([i32; 8]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct f32x2(f32, f32); +struct f32x2([f32; 2]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct f32x4(f32, f32, f32, f32); +struct f32x4([f32; 4]); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); +struct f32x8([f32; 8]); extern "rust-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; @@ -37,8 +37,11 @@ extern "rust-intrinsic" { fn simd_shuffle_generic(x: T, y: T) -> U; } +#[repr(simd)] +struct SimdShuffleIdx([u32; LEN]); + fn main() { - let x = i32x4(0, 0, 0, 0); + let x = i32x4([0, 0, 0, 0]); unsafe { simd_insert(0, 0, 0); @@ -48,13 +51,13 @@ fn main() { simd_extract::<_, f32>(x, 0); //~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32` - const IDX2: [u32; 2] = [0; 2]; + const IDX2: SimdShuffleIdx<2> = SimdShuffleIdx([0; 2]); simd_shuffle::(0, 0, IDX2); //~^ ERROR expected SIMD input type, found non-SIMD `i32` - const IDX4: [u32; 4] = [0; 4]; + const IDX4: SimdShuffleIdx<4> = SimdShuffleIdx([0; 4]); simd_shuffle::(0, 0, IDX4); //~^ ERROR expected SIMD input type, found non-SIMD `i32` - const IDX8: [u32; 8] = [0; 8]; + const IDX8: SimdShuffleIdx<8> = SimdShuffleIdx([0; 8]); simd_shuffle::(0, 0, IDX8); //~^ ERROR expected SIMD input type, found non-SIMD `i32` diff --git a/tests/ui/simd/intrinsic/generic-elements.stderr b/tests/ui/simd/intrinsic/generic-elements.stderr index 0788a7c17f994..fd726d7532600 100644 --- a/tests/ui/simd/intrinsic/generic-elements.stderr +++ b/tests/ui/simd/intrinsic/generic-elements.stderr @@ -1,125 +1,125 @@ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:44:9 + --> $DIR/generic-elements.rs:47:9 | LL | simd_insert(0, 0, 0); | ^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64` - --> $DIR/generic-elements.rs:46:9 + --> $DIR/generic-elements.rs:49:9 | LL | simd_insert(x, 0, 1.0); | ^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32` - --> $DIR/generic-elements.rs:48:9 + --> $DIR/generic-elements.rs:51:9 | LL | simd_extract::<_, f32>(x, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:52:9 + --> $DIR/generic-elements.rs:55:9 | LL | simd_shuffle::(0, 0, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:55:9 + --> $DIR/generic-elements.rs:58:9 | LL | simd_shuffle::(0, 0, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:58:9 + --> $DIR/generic-elements.rs:61:9 | LL | simd_shuffle::(0, 0, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/generic-elements.rs:61:9 + --> $DIR/generic-elements.rs:64:9 | LL | simd_shuffle::<_, _, f32x2>(x, x, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/generic-elements.rs:63:9 + --> $DIR/generic-elements.rs:66:9 | LL | simd_shuffle::<_, _, f32x4>(x, x, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:65:9 + --> $DIR/generic-elements.rs:68:9 | LL | simd_shuffle::<_, _, f32x8>(x, x, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:68:9 + --> $DIR/generic-elements.rs:71:9 | LL | simd_shuffle::<_, _, i32x8>(x, x, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:70:9 + --> $DIR/generic-elements.rs:73:9 | LL | simd_shuffle::<_, _, i32x8>(x, x, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:72:9 + --> $DIR/generic-elements.rs:75:9 | LL | simd_shuffle::<_, _, i32x2>(x, x, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:76:9 + --> $DIR/generic-elements.rs:79:9 | LL | simd_shuffle_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:79:9 + --> $DIR/generic-elements.rs:82:9 | LL | simd_shuffle_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:82:9 + --> $DIR/generic-elements.rs:85:9 | LL | simd_shuffle_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/generic-elements.rs:85:9 + --> $DIR/generic-elements.rs:88:9 | LL | simd_shuffle_generic::<_, f32x2, I2>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/generic-elements.rs:87:9 + --> $DIR/generic-elements.rs:90:9 | LL | simd_shuffle_generic::<_, f32x4, I4>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:89:9 + --> $DIR/generic-elements.rs:92:9 | LL | simd_shuffle_generic::<_, f32x8, I8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:92:9 + --> $DIR/generic-elements.rs:95:9 | LL | simd_shuffle_generic::<_, i32x8, I2>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:94:9 + --> $DIR/generic-elements.rs:97:9 | LL | simd_shuffle_generic::<_, i32x8, I4>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:96:9 + --> $DIR/generic-elements.rs:99:9 | LL | simd_shuffle_generic::<_, i32x2, I8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/intrinsic/generic-gather-pass.rs b/tests/ui/simd/intrinsic/generic-gather-pass.rs index a00bc67e73bd4..3315d1cdaa22d 100644 --- a/tests/ui/simd/intrinsic/generic-gather-pass.rs +++ b/tests/ui/simd/intrinsic/generic-gather-pass.rs @@ -8,7 +8,7 @@ #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct x4(pub T, pub T, pub T, pub T); +struct x4(pub [T; 4]); extern "rust-intrinsic" { fn simd_gather(x: T, y: U, z: V) -> T; @@ -18,19 +18,19 @@ extern "rust-intrinsic" { fn main() { let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; - let default = x4(-3_f32, -3., -3., -3.); - let s_strided = x4(0_f32, 2., -3., 6.); - let mask = x4(-1_i32, -1, 0, -1); + let default = x4([-3_f32, -3., -3., -3.]); + let s_strided = x4([0_f32, 2., -3., 6.]); + let mask = x4([-1_i32, -1, 0, -1]); // reading from *const unsafe { let pointer = x.as_ptr(); - let pointers = x4( + let pointers = x4([ pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6) - ); + ]); let r_strided = simd_gather(default, pointers, mask); @@ -40,12 +40,12 @@ fn main() { // reading from *mut unsafe { let pointer = x.as_mut_ptr(); - let pointers = x4( + let pointers = x4([ pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6) - ); + ]); let r_strided = simd_gather(default, pointers, mask); @@ -55,14 +55,14 @@ fn main() { // writing to *mut unsafe { let pointer = x.as_mut_ptr(); - let pointers = x4( + let pointers = x4([ pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6) - ); + ]); - let values = x4(42_f32, 43_f32, 44_f32, 45_f32); + let values = x4([42_f32, 43_f32, 44_f32, 45_f32]); simd_scatter(values, pointers, mask); assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); @@ -80,18 +80,18 @@ fn main() { &x[7] as *const f32 ]; - let default = x4(y[0], y[0], y[0], y[0]); - let s_strided = x4(y[0], y[2], y[0], y[6]); + let default = x4([y[0], y[0], y[0], y[0]]); + let s_strided = x4([y[0], y[2], y[0], y[6]]); // reading from *const unsafe { let pointer = y.as_ptr(); - let pointers = x4( + let pointers = x4([ pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6) - ); + ]); let r_strided = simd_gather(default, pointers, mask); @@ -101,12 +101,12 @@ fn main() { // reading from *mut unsafe { let pointer = y.as_mut_ptr(); - let pointers = x4( + let pointers = x4([ pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6) - ); + ]); let r_strided = simd_gather(default, pointers, mask); @@ -116,14 +116,14 @@ fn main() { // writing to *mut unsafe { let pointer = y.as_mut_ptr(); - let pointers = x4( + let pointers = x4([ pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6) - ); + ]); - let values = x4(y[7], y[6], y[5], y[1]); + let values = x4([y[7], y[6], y[5], y[1]]); simd_scatter(values, pointers, mask); let s = [ diff --git a/tests/ui/simd/intrinsic/generic-reduction-pass.rs b/tests/ui/simd/intrinsic/generic-reduction-pass.rs index 64902788709eb..699fb396259dc 100644 --- a/tests/ui/simd/intrinsic/generic-reduction-pass.rs +++ b/tests/ui/simd/intrinsic/generic-reduction-pass.rs @@ -10,19 +10,19 @@ #[repr(simd)] #[derive(Copy, Clone)] -struct i32x4(pub i32, pub i32, pub i32, pub i32); +struct i32x4(pub [i32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); +struct u32x4(pub [u32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); +struct f32x4(pub [f32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -struct b8x4(pub i8, pub i8, pub i8, pub i8); +struct b8x4(pub [i8; 4]); extern "rust-intrinsic" { fn simd_reduce_add_unordered(x: T) -> U; @@ -40,7 +40,7 @@ extern "rust-intrinsic" { fn main() { unsafe { - let x = i32x4(1, -2, 3, 4); + let x = i32x4([1, -2, 3, 4]); let r: i32 = simd_reduce_add_unordered(x); assert_eq!(r, 6_i32); let r: i32 = simd_reduce_mul_unordered(x); @@ -55,7 +55,7 @@ fn main() { let r: i32 = simd_reduce_max(x); assert_eq!(r, 4_i32); - let x = i32x4(-1, -1, -1, -1); + let x = i32x4([-1, -1, -1, -1]); let r: i32 = simd_reduce_and(x); assert_eq!(r, -1_i32); let r: i32 = simd_reduce_or(x); @@ -63,7 +63,7 @@ fn main() { let r: i32 = simd_reduce_xor(x); assert_eq!(r, 0_i32); - let x = i32x4(-1, -1, 0, -1); + let x = i32x4([-1, -1, 0, -1]); let r: i32 = simd_reduce_and(x); assert_eq!(r, 0_i32); let r: i32 = simd_reduce_or(x); @@ -73,7 +73,7 @@ fn main() { } unsafe { - let x = u32x4(1, 2, 3, 4); + let x = u32x4([1, 2, 3, 4]); let r: u32 = simd_reduce_add_unordered(x); assert_eq!(r, 10_u32); let r: u32 = simd_reduce_mul_unordered(x); @@ -89,7 +89,7 @@ fn main() { assert_eq!(r, 4_u32); let t = u32::MAX; - let x = u32x4(t, t, t, t); + let x = u32x4([t, t, t, t]); let r: u32 = simd_reduce_and(x); assert_eq!(r, t); let r: u32 = simd_reduce_or(x); @@ -97,7 +97,7 @@ fn main() { let r: u32 = simd_reduce_xor(x); assert_eq!(r, 0_u32); - let x = u32x4(t, t, 0, t); + let x = u32x4([t, t, 0, t]); let r: u32 = simd_reduce_and(x); assert_eq!(r, 0_u32); let r: u32 = simd_reduce_or(x); @@ -107,7 +107,7 @@ fn main() { } unsafe { - let x = f32x4(1., -2., 3., 4.); + let x = f32x4([1., -2., 3., 4.]); let r: f32 = simd_reduce_add_unordered(x); assert_eq!(r, 6_f32); let r: f32 = simd_reduce_mul_unordered(x); @@ -128,19 +128,19 @@ fn main() { } unsafe { - let x = b8x4(!0, !0, !0, !0); + let x = b8x4([!0, !0, !0, !0]); let r: bool = simd_reduce_all(x); assert_eq!(r, true); let r: bool = simd_reduce_any(x); assert_eq!(r, true); - let x = b8x4(!0, !0, 0, !0); + let x = b8x4([!0, !0, 0, !0]); let r: bool = simd_reduce_all(x); assert_eq!(r, false); let r: bool = simd_reduce_any(x); assert_eq!(r, true); - let x = b8x4(0, 0, 0, 0); + let x = b8x4([0, 0, 0, 0]); let r: bool = simd_reduce_all(x); assert_eq!(r, false); let r: bool = simd_reduce_any(x); diff --git a/tests/ui/simd/intrinsic/generic-reduction.rs b/tests/ui/simd/intrinsic/generic-reduction.rs index 96df73591693f..1986deafb6ab5 100644 --- a/tests/ui/simd/intrinsic/generic-reduction.rs +++ b/tests/ui/simd/intrinsic/generic-reduction.rs @@ -9,11 +9,11 @@ #[repr(simd)] #[derive(Copy, Clone)] -pub struct f32x4(pub f32, pub f32, pub f32, pub f32); +pub struct f32x4(pub [f32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -pub struct u32x4(pub u32, pub u32, pub u32, pub u32); +pub struct u32x4(pub [u32; 4]); extern "rust-intrinsic" { @@ -27,8 +27,8 @@ extern "rust-intrinsic" { } fn main() { - let x = u32x4(0, 0, 0, 0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); + let x = u32x4([0, 0, 0, 0]); + let z = f32x4([0.0, 0.0, 0.0, 0.0]); unsafe { simd_reduce_add_ordered(z, 0); diff --git a/tests/ui/simd/intrinsic/generic-select-pass.rs b/tests/ui/simd/intrinsic/generic-select-pass.rs index 98e1534e6e622..5690bad504844 100644 --- a/tests/ui/simd/intrinsic/generic-select-pass.rs +++ b/tests/ui/simd/intrinsic/generic-select-pass.rs @@ -11,23 +11,23 @@ #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct i32x4(pub i32, pub i32, pub i32, pub i32); +struct i32x4(pub [i32; 4]); #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); +struct u32x4(pub [u32; 4]); #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct u32x8(u32, u32, u32, u32, u32, u32, u32, u32); +struct u32x8([u32; 8]); #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); +struct f32x4(pub [f32; 4]); #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct b8x4(pub i8, pub i8, pub i8, pub i8); +struct b8x4(pub [i8; 4]); extern "rust-intrinsic" { fn simd_select(x: T, a: U, b: U) -> U; @@ -35,15 +35,15 @@ extern "rust-intrinsic" { } fn main() { - let m0 = b8x4(!0, !0, !0, !0); - let m1 = b8x4(0, 0, 0, 0); - let m2 = b8x4(!0, !0, 0, 0); - let m3 = b8x4(0, 0, !0, !0); - let m4 = b8x4(!0, 0, !0, 0); + let m0 = b8x4([!0, !0, !0, !0]); + let m1 = b8x4([0, 0, 0, 0]); + let m2 = b8x4([!0, !0, 0, 0]); + let m3 = b8x4([0, 0, !0, !0]); + let m4 = b8x4([!0, 0, !0, 0]); unsafe { - let a = i32x4(1, -2, 3, 4); - let b = i32x4(5, 6, -7, 8); + let a = i32x4([1, -2, 3, 4]); + let b = i32x4([5, 6, -7, 8]); let r: i32x4 = simd_select(m0, a, b); let e = a; @@ -54,21 +54,21 @@ fn main() { assert_eq!(r, e); let r: i32x4 = simd_select(m2, a, b); - let e = i32x4(1, -2, -7, 8); + let e = i32x4([1, -2, -7, 8]); assert_eq!(r, e); let r: i32x4 = simd_select(m3, a, b); - let e = i32x4(5, 6, 3, 4); + let e = i32x4([5, 6, 3, 4]); assert_eq!(r, e); let r: i32x4 = simd_select(m4, a, b); - let e = i32x4(1, 6, 3, 8); + let e = i32x4([1, 6, 3, 8]); assert_eq!(r, e); } unsafe { - let a = u32x4(1, 2, 3, 4); - let b = u32x4(5, 6, 7, 8); + let a = u32x4([1, 2, 3, 4]); + let b = u32x4([5, 6, 7, 8]); let r: u32x4 = simd_select(m0, a, b); let e = a; @@ -79,21 +79,21 @@ fn main() { assert_eq!(r, e); let r: u32x4 = simd_select(m2, a, b); - let e = u32x4(1, 2, 7, 8); + let e = u32x4([1, 2, 7, 8]); assert_eq!(r, e); let r: u32x4 = simd_select(m3, a, b); - let e = u32x4(5, 6, 3, 4); + let e = u32x4([5, 6, 3, 4]); assert_eq!(r, e); let r: u32x4 = simd_select(m4, a, b); - let e = u32x4(1, 6, 3, 8); + let e = u32x4([1, 6, 3, 8]); assert_eq!(r, e); } unsafe { - let a = f32x4(1., 2., 3., 4.); - let b = f32x4(5., 6., 7., 8.); + let a = f32x4([1., 2., 3., 4.]); + let b = f32x4([5., 6., 7., 8.]); let r: f32x4 = simd_select(m0, a, b); let e = a; @@ -104,23 +104,23 @@ fn main() { assert_eq!(r, e); let r: f32x4 = simd_select(m2, a, b); - let e = f32x4(1., 2., 7., 8.); + let e = f32x4([1., 2., 7., 8.]); assert_eq!(r, e); let r: f32x4 = simd_select(m3, a, b); - let e = f32x4(5., 6., 3., 4.); + let e = f32x4([5., 6., 3., 4.]); assert_eq!(r, e); let r: f32x4 = simd_select(m4, a, b); - let e = f32x4(1., 6., 3., 8.); + let e = f32x4([1., 6., 3., 8.]); assert_eq!(r, e); } unsafe { let t = !0 as i8; let f = 0 as i8; - let a = b8x4(t, f, t, f); - let b = b8x4(f, f, f, t); + let a = b8x4([t, f, t, f]); + let b = b8x4([f, f, f, t]); let r: b8x4 = simd_select(m0, a, b); let e = a; @@ -131,21 +131,21 @@ fn main() { assert_eq!(r, e); let r: b8x4 = simd_select(m2, a, b); - let e = b8x4(t, f, f, t); + let e = b8x4([t, f, f, t]); assert_eq!(r, e); let r: b8x4 = simd_select(m3, a, b); - let e = b8x4(f, f, t, f); + let e = b8x4([f, f, t, f]); assert_eq!(r, e); let r: b8x4 = simd_select(m4, a, b); - let e = b8x4(t, f, t, t); + let e = b8x4([t, f, t, t]); assert_eq!(r, e); } unsafe { - let a = u32x8(0, 1, 2, 3, 4, 5, 6, 7); - let b = u32x8(8, 9, 10, 11, 12, 13, 14, 15); + let a = u32x8([0, 1, 2, 3, 4, 5, 6, 7]); + let b = u32x8([8, 9, 10, 11, 12, 13, 14, 15]); let r: u32x8 = simd_select_bitmask(0u8, a, b); let e = b; @@ -156,21 +156,21 @@ fn main() { assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b); - let e = u32x8(0, 9, 2, 11, 4, 13, 6, 15); + let e = u32x8([0, 9, 2, 11, 4, 13, 6, 15]); assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b); - let e = u32x8(8, 1, 10, 3, 12, 5, 14, 7); + let e = u32x8([8, 1, 10, 3, 12, 5, 14, 7]); assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b); - let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7); + let e = u32x8([8, 9, 10, 11, 4, 5, 6, 7]); assert_eq!(r, e); } unsafe { - let a = u32x4(0, 1, 2, 3); - let b = u32x4(4, 5, 6, 7); + let a = u32x4([0, 1, 2, 3]); + let b = u32x4([4, 5, 6, 7]); let r: u32x4 = simd_select_bitmask(0u8, a, b); let e = b; @@ -181,15 +181,15 @@ fn main() { assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b0101u8, a, b); - let e = u32x4(0, 5, 2, 7); + let e = u32x4([0, 5, 2, 7]); assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b1010u8, a, b); - let e = u32x4(4, 1, 6, 3); + let e = u32x4([4, 1, 6, 3]); assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b1100u8, a, b); - let e = u32x4(4, 5, 2, 3); + let e = u32x4([4, 5, 2, 3]); assert_eq!(r, e); } } diff --git a/tests/ui/simd/intrinsic/generic-select.rs b/tests/ui/simd/intrinsic/generic-select.rs index 215ae405c37e2..52e02649590ab 100644 --- a/tests/ui/simd/intrinsic/generic-select.rs +++ b/tests/ui/simd/intrinsic/generic-select.rs @@ -8,19 +8,19 @@ #[repr(simd)] #[derive(Copy, Clone)] -pub struct f32x4(pub f32, pub f32, pub f32, pub f32); +pub struct f32x4(pub [f32; 4]); #[repr(simd)] #[derive(Copy, Clone)] -pub struct u32x4(pub u32, pub u32, pub u32, pub u32); +pub struct u32x4(pub [u32; 4]); #[repr(simd)] #[derive(Copy, Clone, PartialEq)] -struct b8x4(pub i8, pub i8, pub i8, pub i8); +struct b8x4(pub [i8; 4]); #[repr(simd)] #[derive(Copy, Clone, PartialEq)] -struct b8x8(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8); +struct b8x8(pub [i8; 8]); extern "rust-intrinsic" { fn simd_select(x: T, a: U, b: U) -> U; @@ -28,10 +28,10 @@ extern "rust-intrinsic" { } fn main() { - let m4 = b8x4(0, 0, 0, 0); - let m8 = b8x8(0, 0, 0, 0, 0, 0, 0, 0); - let x = u32x4(0, 0, 0, 0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); + let m4 = b8x4([0, 0, 0, 0]); + let m8 = b8x8([0, 0, 0, 0, 0, 0, 0, 0]); + let x = u32x4([0, 0, 0, 0]); + let z = f32x4([0.0, 0.0, 0.0, 0.0]); unsafe { simd_select(m4, x, x); diff --git a/tests/ui/simd/intrinsic/generic-shuffle.rs b/tests/ui/simd/intrinsic/generic-shuffle.rs index c0888f6778414..2752718d99d6b 100644 --- a/tests/ui/simd/intrinsic/generic-shuffle.rs +++ b/tests/ui/simd/intrinsic/generic-shuffle.rs @@ -14,13 +14,16 @@ extern "rust-intrinsic" { } fn main() { - const I: [u32; 2] = [0; 2]; - const I2: [f32; 2] = [0.; 2]; + const I: Simd = Simd([0; 2]); + const I2: Simd = Simd([0.; 2]); let v = Simd::([0; 4]); unsafe { let _: Simd = simd_shuffle(v, v, I); + let _: Simd = simd_shuffle(v, v, const { [0u32; 2] }); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + let _: Simd = simd_shuffle(v, v, I); //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic diff --git a/tests/ui/simd/intrinsic/generic-shuffle.stderr b/tests/ui/simd/intrinsic/generic-shuffle.stderr index 81e641612ce00..7e6d51a5f6555 100644 --- a/tests/ui/simd/intrinsic/generic-shuffle.stderr +++ b/tests/ui/simd/intrinsic/generic-shuffle.stderr @@ -1,21 +1,27 @@ -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd` with length 4 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: simd_shuffle index must be a SIMD vector of `u32`, got `[u32; 2]` --> $DIR/generic-shuffle.rs:24:31 | +LL | let _: Simd = simd_shuffle(v, v, const { [0u32; 2] }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd` with length 4 + --> $DIR/generic-shuffle.rs:27:31 + | LL | let _: Simd = simd_shuffle(v, v, I); | ^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd`), found `Simd` with element type `f32` - --> $DIR/generic-shuffle.rs:27:31 + --> $DIR/generic-shuffle.rs:30:31 | LL | let _: Simd = simd_shuffle(v, v, I); | ^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: simd_shuffle index must be an array of `u32`, got `[f32; 2]` - --> $DIR/generic-shuffle.rs:30:31 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: simd_shuffle index must be a SIMD vector of `u32`, got `Simd` + --> $DIR/generic-shuffle.rs:33:31 | LL | let _: Simd = simd_shuffle(v, v, I2); | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0511`. diff --git a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs index 928d3824703e7..d9239ef5801ae 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs @@ -11,7 +11,10 @@ extern "rust-intrinsic" { #[repr(simd)] #[derive(Debug, PartialEq)] -struct Simd2(u8, u8); +struct Simd2([u8; 2]); + +#[repr(simd)] +struct SimdShuffleIdx([u32; LEN]); fn main() { unsafe { @@ -21,6 +24,6 @@ fn main() { #[inline(always)] unsafe fn inline_me() -> Simd2 { - const IDX: [u32; 2] = [0, 3]; - simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX) + const IDX: SimdShuffleIdx<2> = SimdShuffleIdx([0, 3]); + simd_shuffle(Simd2([10, 11]), Simd2([12, 13]), IDX) } diff --git a/tests/ui/simd/intrinsic/inlining-issue67557.rs b/tests/ui/simd/intrinsic/inlining-issue67557.rs index b8b8dbba547d1..23dd5075f96b6 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557.rs @@ -11,12 +11,15 @@ extern "rust-intrinsic" { #[repr(simd)] #[derive(Debug, PartialEq)] -struct Simd2(u8, u8); +struct Simd2([u8; 2]); + +#[repr(simd)] +struct SimdShuffleIdx([u32; LEN]); fn main() { unsafe { - const IDX: [u32; 2] = [0, 1]; - let p_res: Simd2 = simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX); + const IDX: SimdShuffleIdx<2> = SimdShuffleIdx([0, 1]); + let p_res: Simd2 = simd_shuffle(Simd2([10, 11]), Simd2([12, 13]), IDX); let a_res: Simd2 = inline_me(); assert_10_11(p_res); @@ -26,17 +29,17 @@ fn main() { #[inline(never)] fn assert_10_11(x: Simd2) { - assert_eq!(x, Simd2(10, 11)); + assert_eq!(x, Simd2([10, 11])); } #[inline(never)] fn assert_10_13(x: Simd2) { - assert_eq!(x, Simd2(10, 13)); + assert_eq!(x, Simd2([10, 13])); } #[inline(always)] unsafe fn inline_me() -> Simd2 { - const IDX: [u32; 2] = [0, 3]; - simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX) + const IDX: SimdShuffleIdx<2> = SimdShuffleIdx([0, 3]); + simd_shuffle(Simd2([10, 11]), Simd2([12, 13]), IDX) } diff --git a/tests/ui/simd/issue-17170.rs b/tests/ui/simd/issue-17170.rs index abfc1c25ffb78..2d13962843c44 100644 --- a/tests/ui/simd/issue-17170.rs +++ b/tests/ui/simd/issue-17170.rs @@ -2,9 +2,9 @@ #![feature(repr_simd)] #[repr(simd)] -struct T(f64, f64, f64); +struct T([f64; 3]); -static X: T = T(0.0, 0.0, 0.0); +static X: T = T([0.0, 0.0, 0.0]); fn main() { let _ = X; diff --git a/tests/ui/simd/issue-32947.rs b/tests/ui/simd/issue-32947.rs index bccca25c52b1d..dc5e7a4ec9153 100644 --- a/tests/ui/simd/issue-32947.rs +++ b/tests/ui/simd/issue-32947.rs @@ -6,7 +6,7 @@ extern crate test; #[repr(simd)] -pub struct Mu64(pub u64, pub u64, pub u64, pub u64); +pub struct Mu64(pub [u64; 4]); fn main() { // This ensures an unaligned pointer even in optimized builds, though LLVM @@ -18,7 +18,7 @@ fn main() { let misaligned_ptr: &mut [u8; 32] = { std::mem::transmute(memory.offset(1)) }; - *misaligned_ptr = std::mem::transmute(Mu64(1, 1, 1, 1)); + *misaligned_ptr = std::mem::transmute(Mu64([1, 1, 1, 1])); test::black_box(memory); } } diff --git a/tests/ui/simd/issue-39720.rs b/tests/ui/simd/issue-39720.rs index 4610b1d50044b..2b51c0224c633 100644 --- a/tests/ui/simd/issue-39720.rs +++ b/tests/ui/simd/issue-39720.rs @@ -5,18 +5,18 @@ #[repr(simd)] #[derive(Copy, Clone, Debug)] -pub struct Char3(pub i8, pub i8, pub i8); +pub struct Char3(pub [i8; 3]); #[repr(simd)] #[derive(Copy, Clone, Debug)] -pub struct Short3(pub i16, pub i16, pub i16); +pub struct Short3(pub [i16; 3]); extern "rust-intrinsic" { fn simd_cast(x: T) -> U; } fn main() { - let cast: Short3 = unsafe { simd_cast(Char3(10, -3, -9)) }; + let cast: Short3 = unsafe { simd_cast(Char3([10, -3, -9])) }; println!("{:?}", cast); } diff --git a/tests/ui/simd/issue-89193.rs b/tests/ui/simd/issue-89193.rs index a4ed9be9962fb..9530124a7cc81 100644 --- a/tests/ui/simd/issue-89193.rs +++ b/tests/ui/simd/issue-89193.rs @@ -8,7 +8,7 @@ #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] -struct x4(pub T, pub T, pub T, pub T); +struct x4(pub [T; 4]); extern "rust-intrinsic" { fn simd_gather(x: T, y: U, z: V) -> T; @@ -16,36 +16,36 @@ extern "rust-intrinsic" { fn main() { let x: [usize; 4] = [10, 11, 12, 13]; - let default = x4(0_usize, 1, 2, 3); + let default = x4([0_usize, 1, 2, 3]); let all_set = u8::MAX as i8; // aka -1 - let mask = x4(all_set, all_set, all_set, all_set); - let expected = x4(10_usize, 11, 12, 13); + let mask = x4([all_set, all_set, all_set, all_set]); + let expected = x4([10_usize, 11, 12, 13]); unsafe { let pointer = x.as_ptr(); - let pointers = x4( + let pointers = x4([ pointer.offset(0), pointer.offset(1), pointer.offset(2), pointer.offset(3) - ); + ]); let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } // and again for isize let x: [isize; 4] = [10, 11, 12, 13]; - let default = x4(0_isize, 1, 2, 3); - let expected = x4(10_isize, 11, 12, 13); + let default = x4([0_isize, 1, 2, 3]); + let expected = x4([10_isize, 11, 12, 13]); unsafe { let pointer = x.as_ptr(); - let pointers = x4( + let pointers = x4([ pointer.offset(0), pointer.offset(1), pointer.offset(2), pointer.offset(3) - ); + ]); let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } diff --git a/tests/ui/simd/monomorphize-heterogeneous.rs b/tests/ui/simd/monomorphize-heterogeneous.rs index 42e380dbb779b..326e52acc34d1 100644 --- a/tests/ui/simd/monomorphize-heterogeneous.rs +++ b/tests/ui/simd/monomorphize-heterogeneous.rs @@ -2,7 +2,11 @@ #[repr(simd)] struct I64F64(i64, f64); -//~^ ERROR SIMD vector should be homogeneous +//~^ ERROR SIMD vector's only field must be an array + +#[repr(simd)] +struct I64x4F64x0([i64; 4], [f64; 0]); +//~^ ERROR SIMD vector cannot have multiple fields static X: I64F64 = I64F64(1, 2.0); diff --git a/tests/ui/simd/monomorphize-heterogeneous.stderr b/tests/ui/simd/monomorphize-heterogeneous.stderr index 58e2b7c834766..610a1a49038aa 100644 --- a/tests/ui/simd/monomorphize-heterogeneous.stderr +++ b/tests/ui/simd/monomorphize-heterogeneous.stderr @@ -1,9 +1,16 @@ -error[E0076]: SIMD vector should be homogeneous +error[E0076]: SIMD vector's only field must be an array --> $DIR/monomorphize-heterogeneous.rs:4:1 | LL | struct I64F64(i64, f64); - | ^^^^^^^^^^^^^ SIMD elements must have the same type + | ^^^^^^^^^^^^^ --- not an array -error: aborting due to 1 previous error +error[E0075]: SIMD vector cannot have multiple fields + --> $DIR/monomorphize-heterogeneous.rs:8:1 + | +LL | struct I64x4F64x0([i64; 4], [f64; 0]); + | ^^^^^^^^^^^^^^^^^ -------- excess field + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0076`. +Some errors have detailed explanations: E0075, E0076. +For more information about an error, try `rustc --explain E0075`. diff --git a/tests/ui/simd/monomorphize-shuffle-index.generic.stderr b/tests/ui/simd/monomorphize-shuffle-index.generic.stderr index c4cfca7be1d5e..2d1fa1f8da225 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.generic.stderr +++ b/tests/ui/simd/monomorphize-shuffle-index.generic.stderr @@ -1,8 +1,8 @@ error: overly complex generic constant --> $DIR/monomorphize-shuffle-index.rs:29:45 | -LL | return simd_shuffle_generic::<_, _, { &Self::I }>(a, b); - | ^^--------^^ +LL | return simd_shuffle_generic::<_, _, { &Self::I.0 }>(a, b); + | ^^----------^^ | | | pointer casts are not allowed in generic constants | diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index 30c345cb90471..140cf6fbe96a9 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -16,8 +16,8 @@ extern "rust-intrinsic" { struct Simd([T; N]); trait Shuffle { - const I: [u32; N]; - const J: &'static [u32] = &Self::I; + const I: Simd; + const J: &'static [u32] = &Self::I.0; unsafe fn shuffle(&self, a: Simd, b: Simd) -> Simd where @@ -26,7 +26,7 @@ trait Shuffle { #[cfg(old)] return simd_shuffle(a, b, Self::I); #[cfg(generic)] - return simd_shuffle_generic::<_, _, { &Self::I }>(a, b); + return simd_shuffle_generic::<_, _, { &Self::I.0 }>(a, b); //[generic]~^ overly complex generic constant #[cfg(generic_with_fn)] return simd_shuffle_generic::<_, _, { Self::J }>(a, b); @@ -38,12 +38,12 @@ struct Thing; fn main() { struct I1; impl Shuffle<4> for I1 { - const I: [u32; 4] = [0, 2, 4, 6]; + const I: Simd = Simd([0, 2, 4, 6]); } struct I2; impl Shuffle<2> for I2 { - const I: [u32; 2] = [1, 5]; + const I: Simd = Simd([1, 5]); } let a = Simd::([0, 1, 2, 3]); diff --git a/tests/ui/simd/monomorphize-too-long.rs b/tests/ui/simd/monomorphize-too-long.rs new file mode 100644 index 0000000000000..4bcde782292d6 --- /dev/null +++ b/tests/ui/simd/monomorphize-too-long.rs @@ -0,0 +1,11 @@ +//@ build-fail +//@ error-pattern: monomorphising SIMD type `Simd` of length greater than 32768 + +#![feature(repr_simd)] + +#[repr(simd)] +struct Simd([T; N]); + +fn main() { + let _too_big = Simd([1_u16; 54321]); +} diff --git a/tests/ui/simd/monomorphize-too-long.stderr b/tests/ui/simd/monomorphize-too-long.stderr new file mode 100644 index 0000000000000..978eef307abd1 --- /dev/null +++ b/tests/ui/simd/monomorphize-too-long.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `Simd` of length greater than 32768 + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/monomorphize-zero-length.rs b/tests/ui/simd/monomorphize-zero-length.rs new file mode 100644 index 0000000000000..44b4cfc0bcfab --- /dev/null +++ b/tests/ui/simd/monomorphize-zero-length.rs @@ -0,0 +1,11 @@ +//@ build-fail +//@ error-pattern: monomorphising SIMD type `Simd` of zero length + +#![feature(repr_simd)] + +#[repr(simd)] +struct Simd([T; N]); + +fn main() { + let _empty = Simd([1.0; 0]); +} diff --git a/tests/ui/simd/monomorphize-zero-length.stderr b/tests/ui/simd/monomorphize-zero-length.stderr new file mode 100644 index 0000000000000..738c20fe51a46 --- /dev/null +++ b/tests/ui/simd/monomorphize-zero-length.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `Simd` of zero length + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/not-out-of-bounds.rs b/tests/ui/simd/not-out-of-bounds.rs index 36d7a5865bc54..4bd2a69edbf5e 100644 --- a/tests/ui/simd/not-out-of-bounds.rs +++ b/tests/ui/simd/not-out-of-bounds.rs @@ -30,6 +30,9 @@ struct u8x64([u8; 64]); use std::intrinsics::simd::*; +#[repr(simd)] +struct SimdShuffleIdx([u32; LEN]); + // Test vectors by lane size. Since LLVM does not distinguish between a shuffle // over two f32s and a shuffle over two u64s, or any other such combination, // it is not necessary to test every possible vector, only lane counts. @@ -37,26 +40,26 @@ macro_rules! test_shuffle_lanes { ($n:literal, $x:ident, $y:ident) => { unsafe { let shuffle: $x = { - const ARR: [u32; $n] = { + const IDX: SimdShuffleIdx<$n> = SimdShuffleIdx({ let mut arr = [0; $n]; arr[0] = $n * 2; arr - }; + }); let mut n: u8 = $n; let vals = [0; $n].map(|_| { n = n - 1; n }); let vec1 = $x(vals); let vec2 = $x(vals); - $y(vec1, vec2, ARR) + $y(vec1, vec2, IDX) }; } } } -//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic -//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic +//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds +//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds // Because the test is mostly embedded in a macro, all the errors have the same origin point. // And unfortunately, standard comments, as in the UI test harness, disappear in macros! @@ -69,15 +72,15 @@ fn main() { test_shuffle_lanes!(64, u8x64, simd_shuffle); let v = u8x2([0, 0]); - const I: [u32; 2] = [4, 4]; + const I: SimdShuffleIdx<2> = SimdShuffleIdx([4, 4]); unsafe { let _: u8x2 = simd_shuffle(v, v, I); - //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds } // also check insert/extract unsafe { - simd_insert(v, 2, 0); //~ ERROR invalid monomorphization of `simd_insert` intrinsic - let _val: u8 = simd_extract(v, 2); //~ ERROR invalid monomorphization of `simd_extract` intrinsic + simd_insert(v, 2, 0u8); //~ ERROR invalid monomorphization of `simd_insert` intrinsic: SIMD index #1 is out of bounds + let _val: u8 = simd_extract(v, 2); //~ ERROR invalid monomorphization of `simd_extract` intrinsic: SIMD index #1 is out of bounds } } diff --git a/tests/ui/simd/not-out-of-bounds.stderr b/tests/ui/simd/not-out-of-bounds.stderr index 5682935c1f1ae..4b6bda93e4561 100644 --- a/tests/ui/simd/not-out-of-bounds.stderr +++ b/tests/ui/simd/not-out-of-bounds.stderr @@ -1,7 +1,7 @@ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 4) - --> $DIR/not-out-of-bounds.rs:49:21 + --> $DIR/not-out-of-bounds.rs:52:21 | -LL | $y(vec1, vec2, ARR) +LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ ... LL | test_shuffle_lanes!(2, u8x2, simd_shuffle); @@ -10,9 +10,9 @@ LL | test_shuffle_lanes!(2, u8x2, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 8) - --> $DIR/not-out-of-bounds.rs:49:21 + --> $DIR/not-out-of-bounds.rs:52:21 | -LL | $y(vec1, vec2, ARR) +LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ ... LL | test_shuffle_lanes!(4, u8x4, simd_shuffle); @@ -21,9 +21,9 @@ LL | test_shuffle_lanes!(4, u8x4, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 16) - --> $DIR/not-out-of-bounds.rs:49:21 + --> $DIR/not-out-of-bounds.rs:52:21 | -LL | $y(vec1, vec2, ARR) +LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ ... LL | test_shuffle_lanes!(8, u8x8, simd_shuffle); @@ -32,9 +32,9 @@ LL | test_shuffle_lanes!(8, u8x8, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 32) - --> $DIR/not-out-of-bounds.rs:49:21 + --> $DIR/not-out-of-bounds.rs:52:21 | -LL | $y(vec1, vec2, ARR) +LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ ... LL | test_shuffle_lanes!(16, u8x16, simd_shuffle); @@ -43,9 +43,9 @@ LL | test_shuffle_lanes!(16, u8x16, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 64) - --> $DIR/not-out-of-bounds.rs:49:21 + --> $DIR/not-out-of-bounds.rs:52:21 | -LL | $y(vec1, vec2, ARR) +LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ ... LL | test_shuffle_lanes!(32, u8x32, simd_shuffle); @@ -54,9 +54,9 @@ LL | test_shuffle_lanes!(32, u8x32, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 128) - --> $DIR/not-out-of-bounds.rs:49:21 + --> $DIR/not-out-of-bounds.rs:52:21 | -LL | $y(vec1, vec2, ARR) +LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ ... LL | test_shuffle_lanes!(64, u8x64, simd_shuffle); @@ -65,19 +65,19 @@ LL | test_shuffle_lanes!(64, u8x64, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 4) - --> $DIR/not-out-of-bounds.rs:74:23 + --> $DIR/not-out-of-bounds.rs:77:23 | LL | let _: u8x2 = simd_shuffle(v, v, I); | ^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `u8` (element of input `u8x2`), found `i32` - --> $DIR/not-out-of-bounds.rs:80:9 +error[E0511]: invalid monomorphization of `simd_insert` intrinsic: SIMD index #1 is out of bounds (limit 2) + --> $DIR/not-out-of-bounds.rs:83:9 | -LL | simd_insert(v, 2, 0); - | ^^^^^^^^^^^^^^^^^^^^ +LL | simd_insert(v, 2, 0u8); + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_extract` intrinsic: SIMD index #1 is out of bounds (limit 2) - --> $DIR/not-out-of-bounds.rs:81:24 + --> $DIR/not-out-of-bounds.rs:84:24 | LL | let _val: u8 = simd_extract(v, 2); | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/shuffle.rs b/tests/ui/simd/shuffle.rs index dc0d688284e3c..96c0ed2118f9e 100644 --- a/tests/ui/simd/shuffle.rs +++ b/tests/ui/simd/shuffle.rs @@ -16,16 +16,13 @@ extern "rust-intrinsic" { #[repr(simd)] struct Simd([T; N]); -unsafe fn __shuffle_vector16(x: T, y: T) -> U { - simd_shuffle(x, y, IDX) -} -unsafe fn __shuffle_vector16_v2, T, U>(x: T, y: T) -> U { +unsafe fn __shuffle_vector16, T, U>(x: T, y: T) -> U { simd_shuffle(x, y, IDX) } fn main() { - const I1: [u32; 4] = [0, 2, 4, 6]; - const I2: [u32; 2] = [1, 5]; + const I1: Simd = Simd([0, 2, 4, 6]); + const I2: Simd = Simd([1, 5]); let a = Simd::([0, 1, 2, 3]); let b = Simd::([4, 5, 6, 7]); unsafe { @@ -35,16 +32,6 @@ fn main() { let y: Simd = simd_shuffle(a, b, I2); assert_eq!(y.0, [1, 5]); } - // Test that we can also use a SIMD vector instead of a normal array for the shuffle. - const I1_SIMD: Simd = Simd([0, 2, 4, 6]); - const I2_SIMD: Simd = Simd([1, 5]); - unsafe { - let x: Simd = simd_shuffle(a, b, I1_SIMD); - assert_eq!(x.0, [0, 2, 4, 6]); - - let y: Simd = simd_shuffle(a, b, I2_SIMD); - assert_eq!(y.0, [1, 5]); - } // Test that an indirection (via an unnamed constant) // through a const generic parameter also works. @@ -53,13 +40,6 @@ fn main() { let b = Simd::([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]); unsafe { __shuffle_vector16::< - { [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] }, - Simd, - Simd, - >(a, b); - } - unsafe { - __shuffle_vector16_v2::< { Simd([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) }, Simd, Simd, diff --git a/tests/ui/simd/simd-bitmask-notpow2.rs b/tests/ui/simd/simd-bitmask-notpow2.rs index ff43206a3fd6b..3499bf33ed577 100644 --- a/tests/ui/simd/simd-bitmask-notpow2.rs +++ b/tests/ui/simd/simd-bitmask-notpow2.rs @@ -1,7 +1,6 @@ //@run-pass -// SEGFAULTS on LLVM 17. This should be merged into `simd-bitmask` once we require LLVM 18. -//@ min-llvm-version: 18 // FIXME: broken codegen on big-endian (https://github.com/rust-lang/rust/issues/127205) +// This should be merged into `simd-bitmask` once that's fixed. //@ ignore-endian-big #![feature(repr_simd, intrinsics)] diff --git a/tests/ui/simd/target-feature-mixup.rs b/tests/ui/simd/target-feature-mixup.rs index 034cb867c95fc..62d87c3a6dc6c 100644 --- a/tests/ui/simd/target-feature-mixup.rs +++ b/tests/ui/simd/target-feature-mixup.rs @@ -54,17 +54,17 @@ mod test { // An SSE type #[repr(simd)] #[derive(PartialEq, Debug, Clone, Copy)] - struct __m128i(u64, u64); + struct __m128i([u64; 2]); // An AVX type #[repr(simd)] #[derive(PartialEq, Debug, Clone, Copy)] - struct __m256i(u64, u64, u64, u64); + struct __m256i([u64; 4]); // An AVX-512 type #[repr(simd)] #[derive(PartialEq, Debug, Clone, Copy)] - struct __m512i(u64, u64, u64, u64, u64, u64, u64, u64); + struct __m512i([u64; 8]); pub fn main(level: &str) { unsafe { @@ -90,9 +90,9 @@ mod test { )*) => ($( $(#[$attr])* unsafe fn $main(level: &str) { - let m128 = __m128i(1, 2); - let m256 = __m256i(3, 4, 5, 6); - let m512 = __m512i(7, 8, 9, 10, 11, 12, 13, 14); + let m128 = __m128i([1, 2]); + let m256 = __m256i([3, 4, 5, 6]); + let m512 = __m512i([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); @@ -127,55 +127,55 @@ mod test { #[target_feature(enable = "sse2")] unsafe fn id_sse_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i(1, 2)); + assert_eq!(a, __m128i([1, 2])); a.clone() } #[target_feature(enable = "sse2")] unsafe fn id_sse_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i(3, 4, 5, 6)); + assert_eq!(a, __m256i([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "sse2")] unsafe fn id_sse_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i(1, 2)); + assert_eq!(a, __m128i([1, 2])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i(3, 4, 5, 6)); + assert_eq!(a, __m256i([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i(1, 2)); + assert_eq!(a, __m128i([1, 2])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i(3, 4, 5, 6)); + assert_eq!(a, __m256i([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } } diff --git a/tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs b/tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs index dbe2d9ddd54a7..a969295c9f9cd 100644 --- a/tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs +++ b/tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs @@ -11,7 +11,7 @@ extern { } #[repr(simd)] -struct S(T); +struct S([T; 4]); #[inline(never)] fn identity(v: T) -> T { @@ -19,5 +19,5 @@ fn identity(v: T) -> T { } fn main() { - let _v: S<[Option>; 4]> = identity(S([None; 4])); + let _v: S>> = identity(S([None; 4])); } diff --git a/tests/ui/simd/type-generic-monomorphisation-wide-ptr.rs b/tests/ui/simd/type-generic-monomorphisation-wide-ptr.rs index 564118e9b1343..18fc075343069 100644 --- a/tests/ui/simd/type-generic-monomorphisation-wide-ptr.rs +++ b/tests/ui/simd/type-generic-monomorphisation-wide-ptr.rs @@ -2,11 +2,11 @@ #![feature(repr_simd)] -//@ error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` +//@ error-pattern:monomorphising SIMD type `S<*mut [u8]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` #[repr(simd)] -struct S(T); +struct S([T; 4]); fn main() { - let _v: Option> = None; + let _v: Option> = None; } diff --git a/tests/ui/simd/type-generic-monomorphisation-wide-ptr.stderr b/tests/ui/simd/type-generic-monomorphisation-wide-ptr.stderr index 7ac8d71536034..13b8b0315ba75 100644 --- a/tests/ui/simd/type-generic-monomorphisation-wide-ptr.stderr +++ b/tests/ui/simd/type-generic-monomorphisation-wide-ptr.stderr @@ -1,4 +1,4 @@ -error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` +error: monomorphising SIMD type `S<*mut [u8]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` error: aborting due to 1 previous error diff --git a/tests/ui/simd/type-generic-monomorphisation.rs b/tests/ui/simd/type-generic-monomorphisation.rs index 2eeba55ef913a..8b8d645a2649b 100644 --- a/tests/ui/simd/type-generic-monomorphisation.rs +++ b/tests/ui/simd/type-generic-monomorphisation.rs @@ -7,8 +7,8 @@ struct X(Vec); #[repr(simd)] -struct Simd2(T, T); +struct Simd2([T; 2]); fn main() { - let _ = Simd2(X(vec![]), X(vec![])); + let _ = Simd2([X(vec![]), X(vec![])]); } diff --git a/tests/ui/simd/type-len.rs b/tests/ui/simd/type-len.rs index d82c70b8d8268..a971177e1543a 100644 --- a/tests/ui/simd/type-len.rs +++ b/tests/ui/simd/type-len.rs @@ -1,7 +1,6 @@ #![feature(repr_simd)] #![allow(non_camel_case_types)] - #[repr(simd)] struct empty; //~ ERROR SIMD vector cannot be empty @@ -12,12 +11,12 @@ struct empty2([f32; 0]); //~ ERROR SIMD vector cannot be empty struct pow2([f32; 7]); #[repr(simd)] -struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous +struct i64f64(i64, f64); //~ ERROR SIMD vector's only field must be an array struct Foo; #[repr(simd)] -struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type +struct FooV(Foo, Foo); //~ ERROR SIMD vector's only field must be an array #[repr(simd)] struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type @@ -29,11 +28,11 @@ struct TooBig([f32; 65536]); //~ ERROR SIMD vector cannot have more than 32768 e struct JustRight([u128; 32768]); #[repr(simd)] -struct RGBA { +struct RGBA { //~ ERROR SIMD vector's only field must be an array r: f32, g: f32, b: f32, - a: f32 + a: f32, } fn main() {} diff --git a/tests/ui/simd/type-len.stderr b/tests/ui/simd/type-len.stderr index 2a6bd1b0fd58a..04c4ca7677cfc 100644 --- a/tests/ui/simd/type-len.stderr +++ b/tests/ui/simd/type-len.stderr @@ -1,40 +1,48 @@ error[E0075]: SIMD vector cannot be empty - --> $DIR/type-len.rs:6:1 + --> $DIR/type-len.rs:5:1 | LL | struct empty; | ^^^^^^^^^^^^ error[E0075]: SIMD vector cannot be empty - --> $DIR/type-len.rs:9:1 + --> $DIR/type-len.rs:8:1 | LL | struct empty2([f32; 0]); | ^^^^^^^^^^^^^ -error[E0076]: SIMD vector should be homogeneous - --> $DIR/type-len.rs:15:1 +error[E0076]: SIMD vector's only field must be an array + --> $DIR/type-len.rs:14:1 | LL | struct i64f64(i64, f64); - | ^^^^^^^^^^^^^ SIMD elements must have the same type + | ^^^^^^^^^^^^^ --- not an array -error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type - --> $DIR/type-len.rs:20:1 +error[E0076]: SIMD vector's only field must be an array + --> $DIR/type-len.rs:19:1 | LL | struct FooV(Foo, Foo); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ --- not an array error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type - --> $DIR/type-len.rs:23:1 + --> $DIR/type-len.rs:22:1 | LL | struct FooV2([Foo; 2]); | ^^^^^^^^^^^^ error[E0075]: SIMD vector cannot have more than 32768 elements - --> $DIR/type-len.rs:26:1 + --> $DIR/type-len.rs:25:1 | LL | struct TooBig([f32; 65536]); | ^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error[E0076]: SIMD vector's only field must be an array + --> $DIR/type-len.rs:31:1 + | +LL | struct RGBA { + | ^^^^^^^^^^^ +LL | r: f32, + | ------ not an array + +error: aborting due to 7 previous errors Some errors have detailed explanations: E0075, E0076, E0077. For more information about an error, try `rustc --explain E0075`. diff --git a/tests/ui/span/gated-features-attr-spans.rs b/tests/ui/span/gated-features-attr-spans.rs index 69511ab8e1fc7..55527fa8add01 100644 --- a/tests/ui/span/gated-features-attr-spans.rs +++ b/tests/ui/span/gated-features-attr-spans.rs @@ -1,7 +1,6 @@ #[repr(simd)] //~ ERROR are experimental struct Coord { - x: u32, - y: u32, + v: [u32; 2], } fn main() {} diff --git a/tests/ui/span/multiline-span-simple.stderr b/tests/ui/span/multiline-span-simple.stderr index 2454769863b9c..d815f141fa090 100644 --- a/tests/ui/span/multiline-span-simple.stderr +++ b/tests/ui/span/multiline-span-simple.stderr @@ -6,8 +6,8 @@ LL | foo(1 as u32 + | = help: the trait `Add<()>` is not implemented for `u32` = help: the following other types implement trait `Add`: - `&'a u32` implements `Add` - `&u32` implements `Add<&u32>` + `&u32` implements `Add` + `&u32` implements `Add` `u32` implements `Add<&u32>` `u32` implements `Add` diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs index 858fba2132aae..fb962ad24bf93 100644 --- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs +++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs @@ -14,6 +14,5 @@ struct Wrapper::Type> {} impl Wrapper {} //~^ ERROR the constant `C` is not of type `::Type` -//~| ERROR: mismatched types fn main() {} diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr index 71d4277275fee..7094ee8c67ca0 100644 --- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr +++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr @@ -20,17 +20,5 @@ note: required by a const generic parameter in `Wrapper` LL | struct Wrapper::Type> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `Wrapper` -error[E0308]: mismatched types - --> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:15:30 - | -LL | impl Wrapper {} - | ^ expected associated type, found `usize` - | - = note: expected associated type `::Type` - found type `usize` - = help: consider constraining the associated type `::Type` to `usize` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs index f89a463bc5805..a0ee771441772 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs @@ -6,7 +6,6 @@ struct S; impl Copy for S {} -//~^ ERROR: mismatched types impl Copy for S {} //~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>` diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index 1dac58e1f694e..2953bc95917c9 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -1,19 +1,11 @@ error[E0119]: conflicting implementations of trait `Copy` for type `S<_>` - --> $DIR/bad-const-wf-doesnt-specialize.rs:10:1 + --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1 | LL | impl Copy for S {} | -------------------------------- first implementation here -LL | LL | impl Copy for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>` -error[E0308]: mismatched types - --> $DIR/bad-const-wf-doesnt-specialize.rs:8:31 - | -LL | impl Copy for S {} - | ^ expected `usize`, found `i32` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0119, E0308. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/crashes/124164.rs b/tests/ui/static/missing-type.rs similarity index 52% rename from tests/crashes/124164.rs rename to tests/ui/static/missing-type.rs index 8c9b4bddbe80d..2569f47b7c38c 100644 --- a/tests/crashes/124164.rs +++ b/tests/ui/static/missing-type.rs @@ -1,4 +1,5 @@ -//@ known-bug: #124164 +// reported as #124164 static S_COUNT: = std::sync::atomic::AtomicUsize::new(0); +//~^ ERROR: missing type for `static` item fn main() {} diff --git a/tests/ui/static/missing-type.stderr b/tests/ui/static/missing-type.stderr new file mode 100644 index 0000000000000..6489ceb700a2e --- /dev/null +++ b/tests/ui/static/missing-type.stderr @@ -0,0 +1,8 @@ +error: missing type for `static` item + --> $DIR/missing-type.rs:2:16 + | +LL | static S_COUNT: = std::sync::atomic::AtomicUsize::new(0); + | ^ help: provide a type for the static variable: `AtomicUsize` + +error: aborting due to 1 previous error + diff --git a/tests/ui/static/raw-ref-deref-with-unsafe.rs b/tests/ui/static/raw-ref-deref-with-unsafe.rs index 4b8f72de5b77d..0974948b3a06b 100644 --- a/tests/ui/static/raw-ref-deref-with-unsafe.rs +++ b/tests/ui/static/raw-ref-deref-with-unsafe.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(const_mut_refs)] use std::ptr; // This code should remain unsafe because of the two unsafe operations here, diff --git a/tests/ui/static/raw-ref-deref-without-unsafe.rs b/tests/ui/static/raw-ref-deref-without-unsafe.rs index f9bce4368c179..289e55b76382f 100644 --- a/tests/ui/static/raw-ref-deref-without-unsafe.rs +++ b/tests/ui/static/raw-ref-deref-without-unsafe.rs @@ -1,5 +1,3 @@ -#![feature(const_mut_refs)] - use std::ptr; // This code should remain unsafe because of the two unsafe operations here, diff --git a/tests/ui/static/raw-ref-deref-without-unsafe.stderr b/tests/ui/static/raw-ref-deref-without-unsafe.stderr index ac4df8b410c0e..f034499bbb5ff 100644 --- a/tests/ui/static/raw-ref-deref-without-unsafe.stderr +++ b/tests/ui/static/raw-ref-deref-without-unsafe.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/raw-ref-deref-without-unsafe.rs:12:56 + --> $DIR/raw-ref-deref-without-unsafe.rs:10:56 | LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); | ^^^^^^^^^ dereference of raw pointer @@ -7,7 +7,7 @@ LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/raw-ref-deref-without-unsafe.rs:12:57 + --> $DIR/raw-ref-deref-without-unsafe.rs:10:57 | LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); | ^^^^^^^^ use of mutable static diff --git a/tests/ui/static/reference-to-mut-static-safe.e2021.stderr b/tests/ui/static/reference-to-mut-static-safe.e2021.stderr deleted file mode 100644 index 9fdfc00dfcd91..0000000000000 --- a/tests/ui/static/reference-to-mut-static-safe.e2021.stderr +++ /dev/null @@ -1,26 +0,0 @@ -warning: creating a shared reference to mutable static is discouraged - --> $DIR/reference-to-mut-static-safe.rs:9:14 - | -LL | let _x = &X; - | ^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer - | -LL | let _x = addr_of!(X); - | ~~~~~~~~~ + - -error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/reference-to-mut-static-safe.rs:9:15 - | -LL | let _x = &X; - | ^ use of mutable static - | - = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - -error: aborting due to 1 previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/static/reference-to-mut-static-safe.e2024.stderr b/tests/ui/static/reference-to-mut-static-safe.e2024.stderr deleted file mode 100644 index b3e0c84d1d89d..0000000000000 --- a/tests/ui/static/reference-to-mut-static-safe.e2024.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static-safe.rs:9:14 - | -LL | let _x = &X; - | ^^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let _x = addr_of!(X); - | ~~~~~~~~~ + - -error[E0133]: use of mutable static is unsafe and requires unsafe block - --> $DIR/reference-to-mut-static-safe.rs:9:15 - | -LL | let _x = &X; - | ^ use of mutable static - | - = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0133, E0796. -For more information about an error, try `rustc --explain E0133`. diff --git a/tests/ui/static/reference-to-mut-static-safe.rs b/tests/ui/static/reference-to-mut-static-safe.rs deleted file mode 100644 index 98afdadf4d255..0000000000000 --- a/tests/ui/static/reference-to-mut-static-safe.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ revisions: e2021 e2024 - -//@ [e2021] edition:2021 -//@ [e2024] compile-flags: --edition 2024 -Z unstable-options - -fn main() { - static mut X: i32 = 1; - - let _x = &X; - //[e2024]~^ creating a shared reference to a mutable static [E0796] - //~^^ use of mutable static is unsafe and requires unsafe - //[e2021]~^^^ shared reference to mutable static is discouraged [static_mut_refs] -} diff --git a/tests/ui/static/reference-to-mut-static-unsafe-fn.rs b/tests/ui/static/reference-to-mut-static-unsafe-fn.rs deleted file mode 100644 index d63fd5460d840..0000000000000 --- a/tests/ui/static/reference-to-mut-static-unsafe-fn.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: --edition 2024 -Z unstable-options - -fn main() {} - -unsafe fn _foo() { - unsafe { - static mut X: i32 = 1; - static mut Y: i32 = 1; - - let _y = &X; - //~^ ERROR creating a shared reference to a mutable static [E0796] - - let ref _a = X; - //~^ ERROR creating a shared reference to a mutable static [E0796] - - let ref mut _a = X; - //~^ ERROR creating a mutable reference to a mutable static [E0796] - - let (_b, _c) = (&X, &mut Y); - //~^ ERROR creating a shared reference to a mutable static [E0796] - //~^^ ERROR creating a mutable reference to a mutable static [E0796] - - foo(&X); - //~^ ERROR creating a shared reference to a mutable static [E0796] - } -} - -fn foo<'a>(_x: &'a i32) {} diff --git a/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr deleted file mode 100644 index ca9cfbf7ac787..0000000000000 --- a/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr +++ /dev/null @@ -1,75 +0,0 @@ -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static-unsafe-fn.rs:10:18 - | -LL | let _y = &X; - | ^^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let _y = addr_of!(X); - | ~~~~~~~~~ + - -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static-unsafe-fn.rs:13:22 - | -LL | let ref _a = X; - | ^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let ref _a = addr_of!(X); - | +++++++++ + - -error[E0796]: creating a mutable reference to a mutable static - --> $DIR/reference-to-mut-static-unsafe-fn.rs:16:26 - | -LL | let ref mut _a = X; - | ^ mutable reference to mutable static - | - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | let ref mut _a = addr_of_mut!(X); - | +++++++++++++ + - -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static-unsafe-fn.rs:19:25 - | -LL | let (_b, _c) = (&X, &mut Y); - | ^^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let (_b, _c) = (addr_of!(X), &mut Y); - | ~~~~~~~~~ + - -error[E0796]: creating a mutable reference to a mutable static - --> $DIR/reference-to-mut-static-unsafe-fn.rs:19:29 - | -LL | let (_b, _c) = (&X, &mut Y); - | ^^^^^^ mutable reference to mutable static - | - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | let (_b, _c) = (&X, addr_of_mut!(Y)); - | ~~~~~~~~~~~~~ + - -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static-unsafe-fn.rs:23:13 - | -LL | foo(&X); - | ^^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | foo(addr_of!(X)); - | ~~~~~~~~~ + - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-to-mut-static.e2021.stderr b/tests/ui/static/reference-to-mut-static.e2021.stderr deleted file mode 100644 index 667d7602f34a5..0000000000000 --- a/tests/ui/static/reference-to-mut-static.e2021.stderr +++ /dev/null @@ -1,91 +0,0 @@ -error: creating a shared reference to mutable static is discouraged - --> $DIR/reference-to-mut-static.rs:16:18 - | -LL | let _y = &X; - | ^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -note: the lint level is defined here - --> $DIR/reference-to-mut-static.rs:6:9 - | -LL | #![deny(static_mut_refs)] - | ^^^^^^^^^^^^^^^ -help: use `addr_of!` instead to create a raw pointer - | -LL | let _y = addr_of!(X); - | ~~~~~~~~~ + - -error: creating a mutable reference to mutable static is discouraged - --> $DIR/reference-to-mut-static.rs:20:18 - | -LL | let _y = &mut X; - | ^^^^^^ mutable reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | let _y = addr_of_mut!(X); - | ~~~~~~~~~~~~~ + - -error: creating a shared reference to mutable static is discouraged - --> $DIR/reference-to-mut-static.rs:28:22 - | -LL | let ref _a = X; - | ^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let ref _a = addr_of!(X); - | +++++++++ + - -error: creating a shared reference to mutable static is discouraged - --> $DIR/reference-to-mut-static.rs:32:25 - | -LL | let (_b, _c) = (&X, &Y); - | ^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let (_b, _c) = (addr_of!(X), &Y); - | ~~~~~~~~~ + - -error: creating a shared reference to mutable static is discouraged - --> $DIR/reference-to-mut-static.rs:32:29 - | -LL | let (_b, _c) = (&X, &Y); - | ^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let (_b, _c) = (&X, addr_of!(Y)); - | ~~~~~~~~~ + - -error: creating a shared reference to mutable static is discouraged - --> $DIR/reference-to-mut-static.rs:38:13 - | -LL | foo(&X); - | ^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | foo(addr_of!(X)); - | ~~~~~~~~~ + - -error: aborting due to 6 previous errors - diff --git a/tests/ui/static/reference-to-mut-static.e2024.stderr b/tests/ui/static/reference-to-mut-static.e2024.stderr deleted file mode 100644 index e77f43554666c..0000000000000 --- a/tests/ui/static/reference-to-mut-static.e2024.stderr +++ /dev/null @@ -1,75 +0,0 @@ -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static.rs:16:18 - | -LL | let _y = &X; - | ^^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let _y = addr_of!(X); - | ~~~~~~~~~ + - -error[E0796]: creating a mutable reference to a mutable static - --> $DIR/reference-to-mut-static.rs:20:18 - | -LL | let _y = &mut X; - | ^^^^^^ mutable reference to mutable static - | - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior -help: use `addr_of_mut!` instead to create a raw pointer - | -LL | let _y = addr_of_mut!(X); - | ~~~~~~~~~~~~~ + - -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static.rs:28:22 - | -LL | let ref _a = X; - | ^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let ref _a = addr_of!(X); - | +++++++++ + - -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static.rs:32:25 - | -LL | let (_b, _c) = (&X, &Y); - | ^^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let (_b, _c) = (addr_of!(X), &Y); - | ~~~~~~~~~ + - -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static.rs:32:29 - | -LL | let (_b, _c) = (&X, &Y); - | ^^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let (_b, _c) = (&X, addr_of!(Y)); - | ~~~~~~~~~ + - -error[E0796]: creating a shared reference to a mutable static - --> $DIR/reference-to-mut-static.rs:38:13 - | -LL | foo(&X); - | ^^ shared reference to mutable static - | - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | foo(addr_of!(X)); - | ~~~~~~~~~ + - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-to-mut-static.rs b/tests/ui/static/reference-to-mut-static.rs deleted file mode 100644 index af2cab7dd8723..0000000000000 --- a/tests/ui/static/reference-to-mut-static.rs +++ /dev/null @@ -1,50 +0,0 @@ -//@ revisions: e2021 e2024 - -//@ [e2021] edition:2021 -//@ [e2024] compile-flags: --edition 2024 -Z unstable-options - -#![deny(static_mut_refs)] - -use std::ptr::{addr_of, addr_of_mut}; - -fn main() { - static mut X: i32 = 1; - - static mut Y: i32 = 1; - - unsafe { - let _y = &X; - //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796] - //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] - - let _y = &mut X; - //[e2024]~^ ERROR creating a mutable reference to a mutable static [E0796] - //[e2021]~^^ ERROR mutable reference to mutable static is discouraged [static_mut_refs] - - let _z = addr_of_mut!(X); - - let _p = addr_of!(X); - - let ref _a = X; - //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796] - //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] - - let (_b, _c) = (&X, &Y); - //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796] - //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] - //[e2024]~^^^ ERROR creating a shared reference to a mutable static [E0796] - //[e2021]~^^^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] - - foo(&X); - //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796] - //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs] - - static mut Z: &[i32; 3] = &[0, 1, 2]; - - let _ = Z.len(); - let _ = Z[0]; - let _ = format!("{:?}", Z); - } -} - -fn foo<'a>(_x: &'a i32) {} diff --git a/tests/ui/static/safe-extern-statics-mut.rs b/tests/ui/static/safe-extern-statics-mut.rs index 05a1bee8891e8..4dfcd41b73c13 100644 --- a/tests/ui/static/safe-extern-statics-mut.rs +++ b/tests/ui/static/safe-extern-statics-mut.rs @@ -10,8 +10,6 @@ extern "C" { fn main() { let b = B; //~ ERROR use of mutable static is unsafe let rb = &B; //~ ERROR use of mutable static is unsafe - //~^ WARN shared reference to mutable static is discouraged [static_mut_refs] let xb = XB; //~ ERROR use of mutable static is unsafe let xrb = &XB; //~ ERROR use of mutable static is unsafe - //~^ WARN shared reference to mutable static is discouraged [static_mut_refs] } diff --git a/tests/ui/static/safe-extern-statics-mut.stderr b/tests/ui/static/safe-extern-statics-mut.stderr index 7705a897e2717..e390625f20a98 100644 --- a/tests/ui/static/safe-extern-statics-mut.stderr +++ b/tests/ui/static/safe-extern-statics-mut.stderr @@ -1,32 +1,3 @@ -warning: creating a shared reference to mutable static is discouraged - --> $DIR/safe-extern-statics-mut.rs:12:14 - | -LL | let rb = &B; - | ^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer - | -LL | let rb = addr_of!(B); - | ~~~~~~~~~ + - -warning: creating a shared reference to mutable static is discouraged - --> $DIR/safe-extern-statics-mut.rs:15:15 - | -LL | let xrb = &XB; - | ^^^ shared reference to mutable static - | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior -help: use `addr_of!` instead to create a raw pointer - | -LL | let xrb = addr_of!(XB); - | ~~~~~~~~~ + - error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/safe-extern-statics-mut.rs:11:13 | @@ -44,7 +15,7 @@ LL | let rb = &B; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:14:14 + --> $DIR/safe-extern-statics-mut.rs:13:14 | LL | let xb = XB; | ^^ use of mutable static @@ -52,13 +23,13 @@ LL | let xb = XB; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:15:16 + --> $DIR/safe-extern-statics-mut.rs:14:16 | LL | let xrb = &XB; | ^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 4 previous errors; 2 warnings emitted +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr index 6035eef5b7140..417dbae9db18f 100644 --- a/tests/ui/statics/issue-15261.stderr +++ b/tests/ui/statics/issue-15261.stderr @@ -4,14 +4,13 @@ warning: creating a shared reference to mutable static is discouraged LL | static n: &'static usize = unsafe { &n_mut }; | ^^^^^^ shared reference to mutable static | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer +help: use `&raw const` instead to create a raw pointer | -LL | static n: &'static usize = unsafe { addr_of!(n_mut) }; - | ~~~~~~~~~ + +LL | static n: &'static usize = unsafe { &raw const n_mut }; + | ~~~~~~~~~~ warning: 1 warning emitted diff --git a/tests/ui/statics/mutable_memory_validation.rs b/tests/ui/statics/mutable_memory_validation.rs index 470229d5fa7cd..d16b787fef84e 100644 --- a/tests/ui/statics/mutable_memory_validation.rs +++ b/tests/ui/statics/mutable_memory_validation.rs @@ -4,7 +4,6 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" -#![feature(const_mut_refs)] #![feature(const_refs_to_static)] use std::cell::UnsafeCell; diff --git a/tests/ui/statics/mutable_memory_validation.stderr b/tests/ui/statics/mutable_memory_validation.stderr index f21269235e9b8..60d1356467927 100644 --- a/tests/ui/statics/mutable_memory_validation.stderr +++ b/tests/ui/statics/mutable_memory_validation.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_memory_validation.rs:16:1 + --> $DIR/mutable_memory_validation.rs:15:1 | LL | const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } }; | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory diff --git a/tests/ui/statics/nested_thread_local.rs b/tests/ui/statics/nested_thread_local.rs index a512016335a00..2590cc579cd27 100644 --- a/tests/ui/statics/nested_thread_local.rs +++ b/tests/ui/statics/nested_thread_local.rs @@ -1,6 +1,5 @@ // Check that we forbid nested statics in `thread_local` statics. -#![feature(const_refs_to_cell)] #![feature(thread_local)] #[thread_local] diff --git a/tests/ui/statics/nested_thread_local.stderr b/tests/ui/statics/nested_thread_local.stderr index 30c742626fa96..b078c28696519 100644 --- a/tests/ui/statics/nested_thread_local.stderr +++ b/tests/ui/statics/nested_thread_local.stderr @@ -1,5 +1,5 @@ error: #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead - --> $DIR/nested_thread_local.rs:7:1 + --> $DIR/nested_thread_local.rs:6:1 | LL | static mut FOO: &u32 = { | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/statics/static-mut-xc.rs b/tests/ui/statics/static-mut-xc.rs index a772d4151f7cd..c23cc822ce741 100644 --- a/tests/ui/statics/static-mut-xc.rs +++ b/tests/ui/statics/static-mut-xc.rs @@ -17,14 +17,19 @@ fn static_bound_set(a: &'static mut isize) { unsafe fn run() { assert_eq!(static_mut_xc::a, 3); + //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] static_mut_xc::a = 4; assert_eq!(static_mut_xc::a, 4); + //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] static_mut_xc::a += 1; assert_eq!(static_mut_xc::a, 5); + //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] static_mut_xc::a *= 3; assert_eq!(static_mut_xc::a, 15); + //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] static_mut_xc::a = -3; assert_eq!(static_mut_xc::a, -3); + //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] static_bound(&static_mut_xc::a); //~^ WARN shared reference to mutable static is discouraged [static_mut_refs] static_bound_set(&mut static_mut_xc::a); diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr index 9751f754332c9..176deb518fce0 100644 --- a/tests/ui/statics/static-mut-xc.stderr +++ b/tests/ui/statics/static-mut-xc.stderr @@ -1,31 +1,74 @@ warning: creating a shared reference to mutable static is discouraged - --> $DIR/static-mut-xc.rs:28:18 + --> $DIR/static-mut-xc.rs:19:16 + | +LL | assert_eq!(static_mut_xc::a, 3); + | ^^^^^^^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = note: `#[warn(static_mut_refs)]` on by default + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-xc.rs:22:16 + | +LL | assert_eq!(static_mut_xc::a, 4); + | ^^^^^^^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-xc.rs:25:16 + | +LL | assert_eq!(static_mut_xc::a, 5); + | ^^^^^^^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-xc.rs:28:16 + | +LL | assert_eq!(static_mut_xc::a, 15); + | ^^^^^^^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-xc.rs:31:16 + | +LL | assert_eq!(static_mut_xc::a, -3); + | ^^^^^^^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-xc.rs:33:18 | LL | static_bound(&static_mut_xc::a); | ^^^^^^^^^^^^^^^^^ shared reference to mutable static | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior - = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives +help: use `&raw const` instead to create a raw pointer | -LL | static_bound(addr_of!(static_mut_xc::a)); - | ~~~~~~~~~ + +LL | static_bound(&raw const static_mut_xc::a); + | ~~~~~~~~~~ warning: creating a mutable reference to mutable static is discouraged - --> $DIR/static-mut-xc.rs:30:22 + --> $DIR/static-mut-xc.rs:35:22 | LL | static_bound_set(&mut static_mut_xc::a); | ^^^^^^^^^^^^^^^^^^^^^ mutable reference to mutable static | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior -help: use `addr_of_mut!` instead to create a raw pointer + = note: for more information, see + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives +help: use `&raw mut` instead to create a raw pointer | -LL | static_bound_set(addr_of_mut!(static_mut_xc::a)); - | ~~~~~~~~~~~~~ + +LL | static_bound_set(&raw mut static_mut_xc::a); + | ~~~~~~~~ -warning: 2 warnings emitted +warning: 7 warnings emitted diff --git a/tests/ui/statics/static-recursive.rs b/tests/ui/statics/static-recursive.rs index 29b80818b7d46..da23b54d1fca0 100644 --- a/tests/ui/statics/static-recursive.rs +++ b/tests/ui/statics/static-recursive.rs @@ -17,6 +17,7 @@ static L3: StaticDoubleLinked = StaticDoubleLinked { prev: &L2, next: &L1, data: pub fn main() { unsafe { assert_eq!(S, *(S as *const *const u8)); + //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs] } let mut test_vec = Vec::new(); diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr index a7a1a1610afbb..f2dd5b8a6cfe8 100644 --- a/tests/ui/statics/static-recursive.stderr +++ b/tests/ui/statics/static-recursive.stderr @@ -4,14 +4,22 @@ warning: creating a shared reference to mutable static is discouraged LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; | ^^ shared reference to mutable static | - = note: for more information, see issue #114447 - = note: this will be a hard error in the 2024 edition - = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives = note: `#[warn(static_mut_refs)]` on by default -help: use `addr_of!` instead to create a raw pointer +help: use `&raw const` instead to create a raw pointer | -LL | static mut S: *const u8 = unsafe { addr_of!(S) as *const *const u8 as *const u8 }; - | ~~~~~~~~~ + +LL | static mut S: *const u8 = unsafe { &raw const S as *const *const u8 as *const u8 }; + | ~~~~~~~~~~ -warning: 1 warning emitted +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-recursive.rs:19:20 + | +LL | assert_eq!(S, *(S as *const *const u8)); + | ^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + +warning: 2 warnings emitted diff --git a/tests/ui/stats/hir-stats.rs b/tests/ui/stats/hir-stats.rs index 249413d80e82a..7c5da8cf554b6 100644 --- a/tests/ui/stats/hir-stats.rs +++ b/tests/ui/stats/hir-stats.rs @@ -1,12 +1,15 @@ //@ check-pass //@ compile-flags: -Zhir-stats //@ only-x86_64 +// layout randomization affects the hir stat output +//@ needs-deterministic-layouts // Type layouts sometimes change. When that happens, until the next bootstrap // bump occurs, stage1 and stage2 will give different outputs for this test. // Add an `ignore-stage1` comment marker to work around that problem during // that time. + // The aim here is to include at least one of every different type of top-level // AST/HIR node reported by `-Zhir-stats`. diff --git a/tests/ui/std/windows-bat-args.rs b/tests/ui/std/windows-bat-args.rs index a9b6252b78c85..cc4a43692abd8 100644 --- a/tests/ui/std/windows-bat-args.rs +++ b/tests/ui/std/windows-bat-args.rs @@ -32,7 +32,9 @@ fn parent() { let bat2 = String::from(bat.to_str().unwrap()); bat.set_file_name("windows-bat-args3.bat"); let bat3 = String::from(bat.to_str().unwrap()); - let bat = [bat1.as_str(), bat2.as_str(), bat3.as_str()]; + bat.set_file_name("windows-bat-args1.bat .. "); + let bat4 = String::from(bat.to_str().unwrap()); + let bat = [bat1.as_str(), bat2.as_str(), bat3.as_str(), bat4.as_str()]; check_args(&bat, &["a", "b"]).unwrap(); check_args(&bat, &["c is for cat", "d is for dog"]).unwrap(); diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs index 9c933a9ef1c4f..f49ce33841af3 100644 --- a/tests/ui/structs-enums/type-sizes.rs +++ b/tests/ui/structs-enums/type-sizes.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ needs-deterministic-layouts #![allow(non_camel_case_types)] #![allow(dead_code)] @@ -208,6 +209,23 @@ struct ReorderEndNiche { b: MiddleNiche4, } +// We want that the niche selection doesn't depend on order of the fields. See issue #125630. +pub enum NicheFieldOrder1 { + A { + x: NonZero, + y: [NonZero; 2], + }, + B([u64; 2]), +} + +pub enum NicheFieldOrder2 { + A { + y: [NonZero; 2], + x: NonZero, + }, + B([u64; 2]), +} + // standins for std types which we want to be laid out in a reasonable way struct RawVecDummy { @@ -259,6 +277,9 @@ pub fn main() { size_of::>()); assert_eq!(size_of::(), size_of::<&'static ()>()); + assert_eq!(size_of::(), 24); + assert_eq!(size_of::(), 24); + assert_eq!(size_of::>>(), size_of::<(bool, &())>()); assert_eq!(size_of::>>(), size_of::<(bool, &())>()); assert_eq!(size_of::>>(), size_of::<(bool, &())>()); diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr index b27d9aef06614..bfcc2307fd7fb 100644 --- a/tests/ui/suggestions/deref-path-method.stderr +++ b/tests/ui/suggestions/deref-path-method.stderr @@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<_, _>` consider using one of the foll Vec::::with_capacity Vec::::try_with_capacity Vec::::from_raw_parts - and 4 others + and 6 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: the function `contains` is implemented on `[_]` | diff --git a/tests/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr b/tests/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr index 2733bbff36b54..530d868163b8d 100644 --- a/tests/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr +++ b/tests/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr @@ -6,7 +6,7 @@ LL | foo::(s); | | | required by a bound introduced by this call | - = help: the trait `Trait` is implemented for `&'a mut S` + = help: the trait `Trait` is implemented for `&mut S` = note: `for<'b> Trait` is implemented for `&'b mut S`, but not for `&'b S` note: required by a bound in `foo` --> $DIR/imm-ref-trait-object-literal-bound-regions.rs:11:20 diff --git a/tests/ui/suggestions/imm-ref-trait-object-literal.stderr b/tests/ui/suggestions/imm-ref-trait-object-literal.stderr index e01102e3864ea..79fa468dc4947 100644 --- a/tests/ui/suggestions/imm-ref-trait-object-literal.stderr +++ b/tests/ui/suggestions/imm-ref-trait-object-literal.stderr @@ -6,7 +6,7 @@ LL | foo(&s); | | | required by a bound introduced by this call | - = help: the trait `Trait` is implemented for `&'a mut S` + = help: the trait `Trait` is implemented for `&mut S` note: required by a bound in `foo` --> $DIR/imm-ref-trait-object-literal.rs:7:11 | diff --git a/tests/ui/suggestions/into-str.stderr b/tests/ui/suggestions/into-str.stderr index 6c1e1ec428fe7..ac6e531fee2b7 100644 --- a/tests/ui/suggestions/into-str.stderr +++ b/tests/ui/suggestions/into-str.stderr @@ -12,7 +12,7 @@ LL | foo(String::new()); `String` implements `From<&mut str>` `String` implements `From<&str>` `String` implements `From>` - `String` implements `From>` + `String` implements `From>` `String` implements `From` = note: required for `String` to implement `Into<&str>` note: required by a bound in `foo` diff --git a/tests/ui/suggestions/issue-84700.stderr b/tests/ui/suggestions/issue-84700.stderr index ac9f5ab0b0cbb..d07055826606d 100644 --- a/tests/ui/suggestions/issue-84700.stderr +++ b/tests/ui/suggestions/issue-84700.stderr @@ -12,6 +12,11 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `Farm | LL | FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(), | ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: the struct variant's field is being ignored + | +LL | FarmAnimal::Chicken { num_eggs: _ } => "cluck, cluck!".to_string(), + | ~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs index 06ee421fc3279..71e5a0c728d6b 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs @@ -1,8 +1,8 @@ pub fn foo(num: i32) -> i32 { let foo: i32::from_be(num); //~^ ERROR expected type, found local variable `num` - //~| ERROR parenthesized type parameters may only be used with a `Fn` trait - //~| ERROR ambiguous associated type + //~| ERROR argument types not allowed with return type notation + //~| ERROR return type notation not allowed in this position yet foo } diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr index b90ae051fb776..83a5441e3c0c6 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr @@ -6,29 +6,22 @@ LL | let foo: i32::from_be(num); | | | help: use `=` if you meant to assign -error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/let-binding-init-expr-as-ty.rs:2:19 +error: argument types not allowed with return type notation + --> $DIR/let-binding-init-expr-as-ty.rs:2:26 | LL | let foo: i32::from_be(num); - | ^^^^^^^^^^^^ only `Fn` traits may use parentheses + | ^^^^^ help: remove the input types: `()` | -help: use angle brackets instead - | -LL | let foo: i32::from_be; - | ~ ~ + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0223]: ambiguous associated type +error: return type notation not allowed in this position yet --> $DIR/let-binding-init-expr-as-ty.rs:2:14 | LL | let foo: i32::from_be(num); | ^^^^^^^^^^^^^^^^^ - | -help: if there were a trait named `Example` with associated type `from_be` implemented for `i32`, you could use the fully-qualified path - | -LL | let foo: ::from_be; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 3 previous errors -Some errors have detailed explanations: E0214, E0223, E0573. -For more information about an error, try `rustc --explain E0214`. +For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr b/tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr index 73fa5ddb146e7..fa203150444c8 100644 --- a/tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr +++ b/tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn foo(value: &T) -> Box { | - let's call the lifetime of this reference `'1` LL | Box::new(value) as Box - | ^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static` | help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound | diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.rs b/tests/ui/suggestions/mut-borrow-needed-by-trait.rs index 924bfd82eb832..66e1e77c905e0 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.rs +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.rs @@ -17,7 +17,6 @@ fn main() { let fp = BufWriter::new(fp); //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied writeln!(fp, "hello world").unwrap(); //~ ERROR the method } diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr index b2f9150142fe4..09a9b1d3b3482 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -10,16 +10,6 @@ LL | let fp = BufWriter::new(fp); note: required by a bound in `BufWriter::::new` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL -error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:17:14 - | -LL | let fp = BufWriter::new(fp); - | ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` - | - = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` -note: required by a bound in `BufWriter` - --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL - error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied --> $DIR/mut-borrow-needed-by-trait.rs:17:14 | @@ -31,13 +21,13 @@ note: required by a bound in `BufWriter` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:22:14 + --> $DIR/mut-borrow-needed-by-trait.rs:21:14 | LL | writeln!(fp, "hello world").unwrap(); | ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds | note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method - --> $DIR/mut-borrow-needed-by-trait.rs:22:14 + --> $DIR/mut-borrow-needed-by-trait.rs:21:14 | LL | writeln!(fp, "hello world").unwrap(); | ^^ @@ -45,7 +35,7 @@ LL | writeln!(fp, "hello world").unwrap(); `&dyn std::io::Write: std::io::Write` which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/suggestions/remove-as_str.rs b/tests/ui/suggestions/remove-as_str.rs deleted file mode 100644 index 289a784ba6af3..0000000000000 --- a/tests/ui/suggestions/remove-as_str.rs +++ /dev/null @@ -1,21 +0,0 @@ -fn foo1(s: &str) { - s.as_str(); - //~^ ERROR no method named `as_str` found -} - -fn foo2<'a>(s: &'a str) { - s.as_str(); - //~^ ERROR no method named `as_str` found -} - -fn foo3(s: &mut str) { - s.as_str(); - //~^ ERROR no method named `as_str` found -} - -fn foo4(s: &&str) { - s.as_str(); - //~^ ERROR no method named `as_str` found -} - -fn main() {} diff --git a/tests/ui/suggestions/remove-as_str.stderr b/tests/ui/suggestions/remove-as_str.stderr deleted file mode 100644 index 534c497780a95..0000000000000 --- a/tests/ui/suggestions/remove-as_str.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0599]: no method named `as_str` found for reference `&str` in the current scope - --> $DIR/remove-as_str.rs:2:7 - | -LL | s.as_str(); - | -^^^^^^-- help: remove this method call - -error[E0599]: no method named `as_str` found for reference `&'a str` in the current scope - --> $DIR/remove-as_str.rs:7:7 - | -LL | s.as_str(); - | -^^^^^^-- help: remove this method call - -error[E0599]: no method named `as_str` found for mutable reference `&mut str` in the current scope - --> $DIR/remove-as_str.rs:12:7 - | -LL | s.as_str(); - | -^^^^^^-- help: remove this method call - -error[E0599]: no method named `as_str` found for reference `&&str` in the current scope - --> $DIR/remove-as_str.rs:17:7 - | -LL | s.as_str(); - | -^^^^^^-- help: remove this method call - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs index 35a06d396f2bb..f882a159f9834 100644 --- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs +++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs @@ -3,7 +3,6 @@ fn main() -> Result<(), ()> { a(|| { - //~^ HELP: try adding a return type b() //~^ ERROR: mismatched types [E0308] //~| NOTE: expected `()`, found `i32` diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr index 5506456afe9ca..939285498fb69 100644 --- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr +++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr @@ -1,20 +1,13 @@ error[E0308]: mismatched types - --> $DIR/try-operator-dont-suggest-semicolon.rs:7:9 + --> $DIR/try-operator-dont-suggest-semicolon.rs:6:9 | LL | b() - | ^^^ expected `()`, found `i32` - | -help: consider using a semicolon here - | -LL | b(); - | + -help: try adding a return type - | -LL | a(|| -> i32 { - | ++++++ + | ^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `i32` error[E0308]: mismatched types - --> $DIR/try-operator-dont-suggest-semicolon.rs:17:9 + --> $DIR/try-operator-dont-suggest-semicolon.rs:16:9 | LL | / if true { LL | | diff --git a/tests/ui/thread-local/thread-local-issue-37508.rs b/tests/ui/thread-local/thread-local-issue-37508.rs index db430a3229c7b..34c3945345184 100644 --- a/tests/ui/thread-local/thread-local-issue-37508.rs +++ b/tests/ui/thread-local/thread-local-issue-37508.rs @@ -4,6 +4,9 @@ // // Regression test for issue #37508 +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + #![no_main] #![no_std] #![feature(thread_local, lang_items)] diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs index 05df0471b1430..af30f53836618 100644 --- a/tests/ui/thread-local/thread-local-static.rs +++ b/tests/ui/thread-local/thread-local-static.rs @@ -7,10 +7,8 @@ #[thread_local] static mut STATIC_VAR_2: [u32; 8] = [4; 8]; const fn g(x: &mut [u32; 8]) { - //~^ ERROR mutable references are not allowed std::mem::swap(x, &mut STATIC_VAR_2) //~^ ERROR thread-local statics cannot be accessed - //~| ERROR mutable references are not allowed //~| ERROR use of mutable static is unsafe } diff --git a/tests/ui/thread-local/thread-local-static.stderr b/tests/ui/thread-local/thread-local-static.stderr index a6499fd15ec64..3bc1aec00c11e 100644 --- a/tests/ui/thread-local/thread-local-static.stderr +++ b/tests/ui/thread-local/thread-local-static.stderr @@ -1,38 +1,18 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/thread-local-static.rs:11:28 + --> $DIR/thread-local-static.rs:10:28 | LL | std::mem::swap(x, &mut STATIC_VAR_2) | ^^^^^^^^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/thread-local-static.rs:9:12 - | -LL | const fn g(x: &mut [u32; 8]) { - | ^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-static.rs:11:28 + --> $DIR/thread-local-static.rs:10:28 | LL | std::mem::swap(x, &mut STATIC_VAR_2) | ^^^^^^^^^^^^ -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/thread-local-static.rs:11:23 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0133, E0625, E0658. +Some errors have detailed explanations: E0133, E0625. For more information about an error, try `rustc --explain E0133`. diff --git a/tests/ui/traits/coherence-alias-hang.rs b/tests/ui/traits/coherence-alias-hang.rs new file mode 100644 index 0000000000000..c2b4d2e42d214 --- /dev/null +++ b/tests/ui/traits/coherence-alias-hang.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ revisions: current next +//[next]@ compile-flags: -Znext-solver + +// Regression test for nalgebra hang . + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Id = T; +trait NotImplemented {} + +struct W(*const T, *const U); +trait Trait { + type Assoc: ?Sized; +} +impl Trait for W { + type Assoc = W>; +} + +trait Overlap {} +impl Overlap for W {} +impl Overlap for T {} + +fn main() {} diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.rs b/tests/ui/traits/custom-on-unimplemented-diagnostic.rs new file mode 100644 index 0000000000000..d7e257ef3bbe3 --- /dev/null +++ b/tests/ui/traits/custom-on-unimplemented-diagnostic.rs @@ -0,0 +1,19 @@ +#[diagnostic::on_unimplemented(message = "my message", label = "my label", note = "my note")] +pub trait ProviderLt {} + +pub trait ProviderExt { + fn request(&self) { + todo!() + } +} + +impl ProviderExt for T {} + +struct B; + +fn main() { + B.request(); + //~^ my message [E0599] + //~| my label + //~| my note +} diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr b/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr new file mode 100644 index 0000000000000..f9788360d06ad --- /dev/null +++ b/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr @@ -0,0 +1,32 @@ +error[E0599]: my message + --> $DIR/custom-on-unimplemented-diagnostic.rs:15:7 + | +LL | struct B; + | -------- method `request` not found for this struct because it doesn't satisfy `B: ProviderExt` or `B: ProviderLt` +... +LL | B.request(); + | ^^^^^^^ my label + | +note: trait bound `B: ProviderLt` was not satisfied + --> $DIR/custom-on-unimplemented-diagnostic.rs:10:18 + | +LL | impl ProviderExt for T {} + | ^^^^^^^^^^ ----------- - + | | + | unsatisfied trait bound introduced here + = note: my note +note: the trait `ProviderLt` must be implemented + --> $DIR/custom-on-unimplemented-diagnostic.rs:2:1 + | +LL | pub trait ProviderLt {} + | ^^^^^^^^^^^^^^^^^^^^ + = help: items from traits can only be used if the trait is implemented and in scope +note: `ProviderExt` defines an item `request`, perhaps you need to implement it + --> $DIR/custom-on-unimplemented-diagnostic.rs:4:1 + | +LL | pub trait ProviderExt { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/traits/impl.rs b/tests/ui/traits/impl.rs index 348096f37f7be..b45935fd86a41 100644 --- a/tests/ui/traits/impl.rs +++ b/tests/ui/traits/impl.rs @@ -3,6 +3,9 @@ //@ aux-build:traitimpl.rs +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] + extern crate traitimpl; use traitimpl::Bar; diff --git a/tests/ui/traits/impl.stderr b/tests/ui/traits/impl.stderr index 98b6fb03d836f..9216a33c1d075 100644 --- a/tests/ui/traits/impl.stderr +++ b/tests/ui/traits/impl.stderr @@ -1,5 +1,5 @@ warning: method `t` is never used - --> $DIR/impl.rs:12:8 + --> $DIR/impl.rs:15:8 | LL | trait T { | - method in this trait diff --git a/tests/ui/traits/incoherent-impl-ambiguity.rs b/tests/ui/traits/incoherent-impl-ambiguity.rs new file mode 100644 index 0000000000000..b5fed95e11c44 --- /dev/null +++ b/tests/ui/traits/incoherent-impl-ambiguity.rs @@ -0,0 +1,14 @@ +// Make sure that an invalid inherent impl doesn't totally clobber all of the +// other inherent impls, which lead to mysterious method/assoc-item probing errors. + +impl () {} +//~^ ERROR cannot define inherent `impl` for primitive types + +struct W; +impl W { + const CONST: u32 = 0; +} + +fn main() { + let _ = W::CONST; +} diff --git a/tests/ui/traits/incoherent-impl-ambiguity.stderr b/tests/ui/traits/incoherent-impl-ambiguity.stderr new file mode 100644 index 0000000000000..9c050a7295581 --- /dev/null +++ b/tests/ui/traits/incoherent-impl-ambiguity.stderr @@ -0,0 +1,11 @@ +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/incoherent-impl-ambiguity.rs:4:1 + | +LL | impl () {} + | ^^^^^^^ + | + = help: consider using an extension trait instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0390`. diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr index 8d7d8cee08ae3..150100f2c531c 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr @@ -4,6 +4,7 @@ error[E0275]: overflow evaluating the requirement `W<_>: Trait` LL | impls::>(); | ^^^^ | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`fixpoint_exponential_growth`) note: required by a bound in `impls` --> $DIR/fixpoint-exponential-growth.rs:30:13 | diff --git a/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.rs b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.rs new file mode 100644 index 0000000000000..2b4f7ba9fa29e --- /dev/null +++ b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Zthreads=16 + +// original issue: https://github.com/rust-lang/rust/issues/129112 +// Previously, the "next" solver asserted that each successful solution is only obtained once. +// This test exhibits a repro that, with next-solver + -Zthreads, triggered that old assert. +// In the presence of multithreaded solving, it's possible to concurrently evaluate things twice, +// which leads to replacing already-solved solutions in the global solution cache! +// We assume this is fine if we check to make sure they are solved the same way each time. + +// This test only nondeterministically fails but that's okay, as it will be rerun by CI many times, +// so it should almost always fail before anything is merged. As other thread tests already exist, +// we already face this difficulty, probably. If we need to fix this by reducing the error margin, +// we should improve compiletest. + +#[derive(Clone, Eq)] //~ ERROR [E0277] +pub struct Struct(T); + +impl PartialEq for Struct +where + U: Into> + Clone +{ + fn eq(&self, _other: &U) -> bool { + todo!() + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr new file mode 100644 index 0000000000000..65e7dd2ab34bc --- /dev/null +++ b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `T: Clone` is not satisfied + --> $DIR/global-cache-and-parallel-frontend.rs:15:17 + | +LL | #[derive(Clone, Eq)] + | ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct: PartialEq` + | +note: required for `Struct` to implement `PartialEq` + --> $DIR/global-cache-and-parallel-frontend.rs:18:19 + | +LL | impl PartialEq for Struct + | ----- ^^^^^^^^^^^^ ^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `Eq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL + = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +LL | pub struct Struct(T); + | +++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index d14b9d217da23..7c3e22fb4014a 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -37,6 +37,8 @@ LL | impl Overlap for T {} LL | LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(_)` + | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs index 1b80287d9da3b..86d428cc0f059 100644 --- a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs +++ b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs @@ -1,6 +1,7 @@ +//~ ERROR overflow evaluating the requirement `Self: Trait` +//~^ ERROR overflow evaluating the requirement `Self well-formed` // This is a non-regression test for issue #115351, where a recursion limit of 0 caused an ICE. //@ compile-flags: -Znext-solver --crate-type=lib -//@ check-pass #![recursion_limit = "0"] trait Trait {} diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr new file mode 100644 index 0000000000000..2eed7e8f7233e --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow evaluating the requirement `Self: Trait` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) + +error[E0275]: overflow evaluating the requirement `Self well-formed` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 66276bcbe3bb0..0e0ae6d59901f 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -35,7 +35,7 @@ LL | .map_err(|_| ())?; `String` implements `From<&mut str>` `String` implements `From<&str>` `String` implements `From>` - `String` implements `From>` + `String` implements `From>` `String` implements `From` = note: required for `Result<(), String>` to implement `FromResidual>` diff --git a/tests/ui/traits/sized-coniductive.rs b/tests/ui/traits/sized-coniductive.rs new file mode 100644 index 0000000000000..5f63b166f988b --- /dev/null +++ b/tests/ui/traits/sized-coniductive.rs @@ -0,0 +1,14 @@ +//@ check-pass +// https://github.com/rust-lang/rust/issues/129541 + +#[derive(Clone)] +struct Test { + field: std::borrow::Cow<'static, [Self]>, +} + +#[derive(Clone)] +struct Hello { + a: <[Hello] as std::borrow::ToOwned>::Owned, +} + +fn main(){} diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr index a3ed51ace0880..85d6cdf779b44 100644 --- a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr @@ -23,7 +23,7 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip, &std::slice::Iter<'_, {integer}>>: IntoIterator` - = help: the trait `Iterator` is implemented for `std::slice::Iter<'a, T>` + = help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` @@ -52,7 +52,7 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip, &std::slice::Iter<'_, {integer}>>: IntoIterator` - = help: the trait `Iterator` is implemented for `std::slice::Iter<'a, T>` + = help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` diff --git a/tests/ui/traits/trait-object-lifetime-default-note.rs b/tests/ui/traits/trait-object-lifetime-default-note.rs index 31e3eb4ba4155..275411ff61c85 100644 --- a/tests/ui/traits/trait-object-lifetime-default-note.rs +++ b/tests/ui/traits/trait-object-lifetime-default-note.rs @@ -8,7 +8,7 @@ fn main() { //~| NOTE borrowed value does not live long enough //~| NOTE due to object lifetime defaults, `Box` actually means `Box<(dyn A + 'static)>` require_box(Box::new(r)); - //~^ NOTE cast requires that `local` is borrowed for `'static` + //~^ NOTE coercion requires that `local` is borrowed for `'static` let _ = 0; } //~ NOTE `local` dropped here while still borrowed diff --git a/tests/ui/traits/trait-object-lifetime-default-note.stderr b/tests/ui/traits/trait-object-lifetime-default-note.stderr index 4244e34873ad1..8cb9bc0d80072 100644 --- a/tests/ui/traits/trait-object-lifetime-default-note.stderr +++ b/tests/ui/traits/trait-object-lifetime-default-note.stderr @@ -7,7 +7,7 @@ LL | let r = &local; | ^^^^^^ borrowed value does not live long enough ... LL | require_box(Box::new(r)); - | ----------- cast requires that `local` is borrowed for `'static` + | ----------- coercion requires that `local` is borrowed for `'static` ... LL | } | - `local` dropped here while still borrowed diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr index e6cb6a753998f..0a969b611e9d3 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr @@ -1,18 +1,18 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:11:13 + --> $DIR/type-checking-test-3.rs:11:18 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'a>; // Error - | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:16:13 + --> $DIR/type-checking-test-3.rs:16:18 | LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'static>; // Error - | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr index ccced5875778d..090120a2327a8 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -1,18 +1,18 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:19:13 + --> $DIR/type-checking-test-4.rs:19:18 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'static, 'a>; // Error - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:24:13 + --> $DIR/type-checking-test-4.rs:24:18 | LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'a, 'static>; // Error - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/type-checking-test-4.rs:30:5 diff --git a/tests/ui/traits/upcast_soundness_bug.rs b/tests/ui/traits/upcast_soundness_bug.rs index 5eaa58f7efe7f..0ddae1d1417c7 100644 --- a/tests/ui/traits/upcast_soundness_bug.rs +++ b/tests/ui/traits/upcast_soundness_bug.rs @@ -57,7 +57,7 @@ pub fn user2() -> &'static dyn Trait { fn main() { let p: *const dyn Trait = &(); let p = p as *const dyn Trait; // <- this is bad! - //~^ error: mismatched types + //~^ error: casting `*const dyn Trait` as `*const dyn Trait` is invalid let p = p as *const dyn Super; // <- this upcast accesses improper vtable entry // accessing from L__unnamed_2 the position for the 'Super vtable (pointer)', // thus reading 'null pointer for missing_method' diff --git a/tests/ui/traits/upcast_soundness_bug.stderr b/tests/ui/traits/upcast_soundness_bug.stderr index 5864abcdb41f5..19d1a5e5926e0 100644 --- a/tests/ui/traits/upcast_soundness_bug.stderr +++ b/tests/ui/traits/upcast_soundness_bug.stderr @@ -1,13 +1,11 @@ -error[E0308]: mismatched types +error[E0606]: casting `*const dyn Trait` as `*const dyn Trait` is invalid --> $DIR/upcast_soundness_bug.rs:59:13 | LL | let p = p as *const dyn Trait; // <- this is bad! - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `u16` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected trait object `dyn Trait` - found trait object `dyn Trait` - = help: `dyn Trait` implements `Trait` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well + = note: the trait objects may have different vtables error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/transmutability/arrays/huge-len.stderr b/tests/ui/transmutability/arrays/huge-len.stderr index 1fa16c649d423..2f8a86df0a7e3 100644 --- a/tests/ui/transmutability/arrays/huge-len.stderr +++ b/tests/ui/transmutability/arrays/huge-len.stderr @@ -2,7 +2,7 @@ error[E0277]: `()` cannot be safely transmuted into `ExplicitlyPadded` --> $DIR/huge-len.rs:21:41 | LL | assert::is_maybe_transmutable::<(), ExplicitlyPadded>(); - | ^^^^^^^^^^^^^^^^ values of the type `ExplicitlyPadded` are too big for the current architecture + | ^^^^^^^^^^^^^^^^ values of the type `ExplicitlyPadded` are too big for the target architecture | note: required by a bound in `is_maybe_transmutable` --> $DIR/huge-len.rs:8:14 @@ -17,7 +17,7 @@ error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()` --> $DIR/huge-len.rs:24:55 | LL | assert::is_maybe_transmutable::(); - | ^^ values of the type `ExplicitlyPadded` are too big for the current architecture + | ^^ values of the type `ExplicitlyPadded` are too big for the target architecture | note: required by a bound in `is_maybe_transmutable` --> $DIR/huge-len.rs:8:14 diff --git a/tests/ui/transmutability/enums/niche_optimization.rs b/tests/ui/transmutability/enums/niche_optimization.rs index 802d174756868..2436be500279f 100644 --- a/tests/ui/transmutability/enums/niche_optimization.rs +++ b/tests/ui/transmutability/enums/niche_optimization.rs @@ -154,3 +154,12 @@ fn no_niche() { assert::is_transmutable::>, OptionLike>(); assert::is_transmutable::>, OptionLike>(); } + +fn niche_fields() { + enum Kind { + A(bool, bool), + B(bool), + } + + assert::is_maybe_transmutable::(); +} diff --git a/tests/ui/transmutability/issue-101739-1.rs b/tests/ui/transmutability/issue-101739-1.rs index fcc1db073ee0e..4fde120e2be8b 100644 --- a/tests/ui/transmutability/issue-101739-1.rs +++ b/tests/ui/transmutability/issue-101739-1.rs @@ -7,7 +7,6 @@ mod assert { where Dst: TransmuteFrom, //~ ERROR cannot find type `Dst` in this scope //~| the constant `ASSUME_ALIGNMENT` is not of type `Assume` - //~| ERROR: mismatched types { } } diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index 3687631dc5119..b3c640a00b4c4 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -13,13 +13,6 @@ LL | Dst: TransmuteFrom, note: required by a const generic parameter in `TransmuteFrom` --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL -error[E0308]: mismatched types - --> $DIR/issue-101739-1.rs:8:33 - | -LL | Dst: TransmuteFrom, - | ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0412. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/transmutability/issue-101739-2.rs b/tests/ui/transmutability/issue-101739-2.rs index 02aa4669e05ef..613626accbb18 100644 --- a/tests/ui/transmutability/issue-101739-2.rs +++ b/tests/ui/transmutability/issue-101739-2.rs @@ -17,7 +17,7 @@ mod assert { Dst: TransmuteFrom< //~^ ERROR trait takes at most 2 generic arguments but 5 generic arguments were supplied Src, - ASSUME_ALIGNMENT, //~ ERROR: mismatched types + ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_VALIDITY, ASSUME_VISIBILITY, diff --git a/tests/ui/transmutability/issue-101739-2.stderr b/tests/ui/transmutability/issue-101739-2.stderr index 526fcabe14e9f..b436ab0e2f915 100644 --- a/tests/ui/transmutability/issue-101739-2.stderr +++ b/tests/ui/transmutability/issue-101739-2.stderr @@ -11,13 +11,6 @@ LL | | ASSUME_VALIDITY, LL | | ASSUME_VISIBILITY, | |_________________________________- help: remove the unnecessary generic arguments -error[E0308]: mismatched types - --> $DIR/issue-101739-2.rs:20:17 - | -LL | ASSUME_ALIGNMENT, - | ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0107, E0308. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr b/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr index c21c59397c79e..714b4fd7d25f6 100644 --- a/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr +++ b/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr @@ -14,12 +14,22 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia | LL | let Alias::Braced = panic!(); | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant + | +help: use the struct variant pattern syntax + | +LL | let Alias::Braced {} = panic!(); + | ++ error[E0164]: expected tuple struct or tuple variant, found struct variant `Alias::Braced` --> $DIR/incorrect-variant-form-through-alias-caught.rs:12:9 | LL | let Alias::Braced(..) = panic!(); | ^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | let Alias::Braced {} = panic!(); + | ~~ error[E0618]: expected function, found enum variant `Alias::Unit` --> $DIR/incorrect-variant-form-through-alias-caught.rs:15:5 diff --git a/tests/crashes/126896.rs b/tests/ui/type-alias-impl-trait/taint.rs similarity index 59% rename from tests/crashes/126896.rs rename to tests/ui/type-alias-impl-trait/taint.rs index 49c539d7acc8a..dfb947637c042 100644 --- a/tests/crashes/126896.rs +++ b/tests/ui/type-alias-impl-trait/taint.rs @@ -1,6 +1,7 @@ -//@ known-bug: rust-lang/rust#126896 //@ compile-flags: -Zvalidate-mir -Zinline-mir=yes +// reported as rust-lang/rust#126896 + #![feature(type_alias_impl_trait)] type Two<'a, 'b> = impl std::fmt::Debug; @@ -9,9 +10,8 @@ fn set(x: &mut isize) -> isize { } fn d(x: Two) { - let c1 = || set(x); + let c1 = || set(x); //~ ERROR: expected generic lifetime parameter, found `'_` c1; } -fn main() { -} +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/taint.stderr b/tests/ui/type-alias-impl-trait/taint.stderr new file mode 100644 index 0000000000000..17fcd4b7e9325 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/taint.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/taint.rs:13:17 + | +LL | type Two<'a, 'b> = impl std::fmt::Debug; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | let c1 = || set(x); + | ^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type/type-check-defaults.stderr b/tests/ui/type/type-check-defaults.stderr index 499e8142cc8f4..9c48250612971 100644 --- a/tests/ui/type/type-check-defaults.stderr +++ b/tests/ui/type/type-check-defaults.stderr @@ -66,8 +66,8 @@ LL | trait ProjectionPred> where T::Item : Add {} | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - `&'a i32` implements `Add` - `&i32` implements `Add<&i32>` + `&i32` implements `Add` + `&i32` implements `Add` `i32` implements `Add<&i32>` `i32` implements `Add` diff --git a/tests/ui/typeck/auxiliary/foreign_struct_trait_unimplemented.rs b/tests/ui/typeck/auxiliary/foreign_struct_trait_unimplemented.rs new file mode 100644 index 0000000000000..097a269e8ee6b --- /dev/null +++ b/tests/ui/typeck/auxiliary/foreign_struct_trait_unimplemented.rs @@ -0,0 +1 @@ +pub struct B; diff --git a/tests/ui/typeck/foreign_struct_trait_unimplemented.rs b/tests/ui/typeck/foreign_struct_trait_unimplemented.rs new file mode 100644 index 0000000000000..8ac56bac9b0a6 --- /dev/null +++ b/tests/ui/typeck/foreign_struct_trait_unimplemented.rs @@ -0,0 +1,15 @@ +//@ aux-build:foreign_struct_trait_unimplemented.rs + +extern crate foreign_struct_trait_unimplemented; + +pub trait Test {} + +struct A; +impl Test for A {} + +fn needs_test(_: impl Test) {} + +fn main() { + needs_test(foreign_struct_trait_unimplemented::B); + //~^ ERROR the trait bound `B: Test` is not satisfied +} diff --git a/tests/ui/typeck/foreign_struct_trait_unimplemented.stderr b/tests/ui/typeck/foreign_struct_trait_unimplemented.stderr new file mode 100644 index 0000000000000..b9bb97548f67c --- /dev/null +++ b/tests/ui/typeck/foreign_struct_trait_unimplemented.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `B: Test` is not satisfied + --> $DIR/foreign_struct_trait_unimplemented.rs:13:16 + | +LL | needs_test(foreign_struct_trait_unimplemented::B); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `B` + | | + | required by a bound introduced by this call + | +help: there are multiple different versions of crate `foreign_struct_trait_unimplemented` in the dependency graph + --> $DIR/foreign_struct_trait_unimplemented.rs:3:1 + | +LL | extern crate foreign_struct_trait_unimplemented; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `foreign_struct_trait_unimplemented` is used here, as a direct dependency of the current crate + = help: you can use `cargo tree` to explore your dependency tree +note: required by a bound in `needs_test` + --> $DIR/foreign_struct_trait_unimplemented.rs:10:23 + | +LL | fn needs_test(_: impl Test) {} + | ^^^^ required by this bound in `needs_test` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs index 92c1999e1544b..5eef268872113 100644 --- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs +++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs @@ -6,7 +6,6 @@ trait Trait { fn func() -> [(); N]; //~^ ERROR: the constant `N` is not of type `usize` - //~| ERROR: mismatched types } struct S {} diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr index bb8025d47a18f..8017e5446cc71 100644 --- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr +++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/const-in-impl-fn-return-type.rs:16:39 + --> $DIR/const-in-impl-fn-return-type.rs:15:39 | LL | fn func() -> [(); { () }] { | ^^ expected `usize`, found `()` @@ -10,12 +10,6 @@ error: the constant `N` is not of type `usize` LL | fn func() -> [(); N]; | ^^^^^^^ expected `usize`, found `u32` -error[E0308]: mismatched types - --> $DIR/const-in-impl-fn-return-type.rs:7:37 - | -LL | fn func() -> [(); N]; - | ^ expected `usize`, found `u32` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/issue-81293.stderr b/tests/ui/typeck/issue-81293.stderr index 3c48db335b5f0..82661fc717233 100644 --- a/tests/ui/typeck/issue-81293.stderr +++ b/tests/ui/typeck/issue-81293.stderr @@ -21,8 +21,8 @@ LL | a = c + b * 5; | = help: the trait `Add` is not implemented for `usize` = help: the following other types implement trait `Add`: - `&'a usize` implements `Add` - `&usize` implements `Add<&usize>` + `&usize` implements `Add` + `&usize` implements `Add` `usize` implements `Add<&usize>` `usize` implements `Add` diff --git a/tests/ui/typeck/issue-81943.stderr b/tests/ui/typeck/issue-81943.stderr index f8da9ef0d180f..041ff10752cf0 100644 --- a/tests/ui/typeck/issue-81943.stderr +++ b/tests/ui/typeck/issue-81943.stderr @@ -2,9 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-81943.rs:7:9 | LL | f(|x| lib::d!(x)); - | -^^^^^^^^^^ expected `()`, found `i32` - | | - | help: try adding a return type: `-> i32` + | ^^^^^^^^^^ expected `()`, found `i32` | = note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -12,22 +10,28 @@ error[E0308]: mismatched types --> $DIR/issue-81943.rs:8:28 | LL | f(|x| match x { tmp => { g(tmp) } }); - | ^^^^^^ expected `()`, found `i32` + | -------------------^^^^^^---- + | | | + | | expected `()`, found `i32` + | expected this to be `()` | help: consider using a semicolon here | LL | f(|x| match x { tmp => { g(tmp); } }); | + -help: try adding a return type +help: consider using a semicolon here | -LL | f(|x| -> i32 match x { tmp => { g(tmp) } }); - | ++++++ +LL | f(|x| match x { tmp => { g(tmp) } };); + | + error[E0308]: mismatched types --> $DIR/issue-81943.rs:10:38 | LL | ($e:expr) => { match $e { x => { g(x) } } } - | ^^^^ expected `()`, found `i32` + | ------------------^^^^---- + | | | + | | expected `()`, found `i32` + | expected this to be `()` LL | } LL | f(|x| d!(x)); | ----- in this macro invocation @@ -37,10 +41,10 @@ help: consider using a semicolon here | LL | ($e:expr) => { match $e { x => { g(x); } } } | + -help: try adding a return type +help: consider using a semicolon here | -LL | f(|x| -> i32 d!(x)); - | ++++++ +LL | ($e:expr) => { match $e { x => { g(x) } }; } + | + error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr index d6832d1b34ffc..796e904a43829 100644 --- a/tests/ui/typeck/issue-90101.stderr +++ b/tests/ui/typeck/issue-90101.stderr @@ -9,7 +9,7 @@ LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world") = help: the following other types implement trait `From`: `PathBuf` implements `From<&T>` `PathBuf` implements `From>` - `PathBuf` implements `From>` + `PathBuf` implements `From>` `PathBuf` implements `From` `PathBuf` implements `From` = note: required for `Cow<'_, str>` to implement `Into` diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr index 9cfeb7a5d09d6..e466f94d0d842 100644 --- a/tests/ui/ufcs/bad-builder.stderr +++ b/tests/ui/ufcs/bad-builder.stderr @@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec` consider using one of the followi Vec::::with_capacity Vec::::try_with_capacity Vec::::from_raw_parts - and 4 others + and 6 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: there is an associated function `new` with a similar name | diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index a0430240dc43b..f8be11a24e3da 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -6,8 +6,8 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - `&'a i32` implements `Add` - `&i32` implements `Add<&i32>` + `&i32` implements `Add` + `&i32` implements `Add` `i32` implements `Add<&i32>` `i32` implements `Add` @@ -63,8 +63,8 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - `&'a i32` implements `Add` - `&i32` implements `Add<&i32>` + `&i32` implements `Add` + `&i32` implements `Add` `i32` implements `Add<&i32>` `i32` implements `Add` diff --git a/tests/ui/uninhabited/uninhabited-patterns.rs b/tests/ui/uninhabited/uninhabited-patterns.rs index 988383e691b4e..b7429464fa5a0 100644 --- a/tests/ui/uninhabited/uninhabited-patterns.rs +++ b/tests/ui/uninhabited/uninhabited-patterns.rs @@ -1,3 +1,4 @@ +#![feature(exhaustive_patterns)] #![feature(box_patterns)] #![feature(never_type)] #![deny(unreachable_patterns)] diff --git a/tests/ui/uninhabited/uninhabited-patterns.stderr b/tests/ui/uninhabited/uninhabited-patterns.stderr index 0e1c9d31a731f..7a872767d959a 100644 --- a/tests/ui/uninhabited/uninhabited-patterns.stderr +++ b/tests/ui/uninhabited/uninhabited-patterns.stderr @@ -1,26 +1,32 @@ error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:29:9 + --> $DIR/uninhabited-patterns.rs:30:9 | LL | Ok(box _) => (), - | ^^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited + | ^^^^^^^^^------- + | | + | matches no values because `NotSoSecretlyEmpty` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here - --> $DIR/uninhabited-patterns.rs:3:9 + --> $DIR/uninhabited-patterns.rs:4:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:38:9 + --> $DIR/uninhabited-patterns.rs:39:9 | LL | Err(Ok(_y)) => (), - | ^^^^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited + | ^^^^^^^^^^^------- + | | + | matches no values because `NotSoSecretlyEmpty` is uninhabited + | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:41:15 + --> $DIR/uninhabited-patterns.rs:42:15 | LL | while let Some(_y) = foo() { | ^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited diff --git a/tests/ui/union/union-drop-assign.rs b/tests/ui/union/union-drop-assign.rs index e9165fddc51e4..451fb14eddf93 100644 --- a/tests/ui/union/union-drop-assign.rs +++ b/tests/ui/union/union-drop-assign.rs @@ -3,6 +3,9 @@ // Drop works for union itself. +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] + use std::mem::ManuallyDrop; struct S; diff --git a/tests/ui/union/union-drop.rs b/tests/ui/union/union-drop.rs index e467eda293504..6f6d5c1416534 100644 --- a/tests/ui/union/union-drop.rs +++ b/tests/ui/union/union-drop.rs @@ -2,6 +2,8 @@ #![allow(dead_code)] #![allow(unused_variables)] +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] // Drop works for union itself. diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs new file mode 100644 index 0000000000000..a83141f0e4eda --- /dev/null +++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs @@ -0,0 +1,34 @@ +fn main() { + let a = ["_"; unsafe { break; 1 + 2 }]; + //~^ ERROR `break` outside of a loop or labeled block + + unsafe { + { + //~^ HELP consider labeling this block to be able to break within it + break; + //~^ ERROR `break` outside of a loop or labeled block + } + } + + unsafe { + break; + //~^ ERROR `break` outside of a loop or labeled block + } + + { + //~^ HELP consider labeling this block to be able to break within it + unsafe { + break; + //~^ ERROR `break` outside of a loop or labeled block + } + } + + while 2 > 1 { + unsafe { + if true || false { + break; + } + } + } + +} diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr new file mode 100644 index 0000000000000..b7cbe1a5cf461 --- /dev/null +++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr @@ -0,0 +1,42 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28 + | +LL | let a = ["_"; unsafe { break; 1 + 2 }]; + | ^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:14:9 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:8:13 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL | +LL ~ break 'block; + | + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:21:13 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL | +LL | unsafe { +LL ~ break 'block; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/unsafe/ranged_ints2_const.rs b/tests/ui/unsafe/ranged_ints2_const.rs index b7178c2b52bfb..a9f5b2089c4d8 100644 --- a/tests/ui/unsafe/ranged_ints2_const.rs +++ b/tests/ui/unsafe/ranged_ints2_const.rs @@ -8,19 +8,19 @@ fn main() { const fn foo() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = &mut x.0; //~ ERROR mutable references + let y = &mut x.0; //~^ ERROR mutation of layout constrained field is unsafe unsafe { NonZero(1) } } const fn bar() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = unsafe { &mut x.0 }; //~ ERROR mutable references + let y = unsafe { &mut x.0 }; unsafe { NonZero(1) } } const fn boo() -> NonZero { let mut x = unsafe { NonZero(1) }; - unsafe { let y = &mut x.0; } //~ ERROR mutable references + unsafe { let y = &mut x.0; } unsafe { NonZero(1) } } diff --git a/tests/ui/unsafe/ranged_ints2_const.stderr b/tests/ui/unsafe/ranged_ints2_const.stderr index 2d25084314eaf..3373d627b5e12 100644 --- a/tests/ui/unsafe/ranged_ints2_const.stderr +++ b/tests/ui/unsafe/ranged_ints2_const.stderr @@ -6,37 +6,6 @@ LL | let y = &mut x.0; | = note: mutating layout constrained fields cannot statically be checked for valid values -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/ranged_ints2_const.rs:11:13 - | -LL | let y = &mut x.0; - | ^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/ranged_ints2_const.rs:18:22 - | -LL | let y = unsafe { &mut x.0 }; - | ^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/ranged_ints2_const.rs:24:22 - | -LL | unsafe { let y = &mut x.0; } - | ^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0133, E0658. -For more information about an error, try `rustc --explain E0133`. +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/unsafe/ranged_ints3_const.rs b/tests/ui/unsafe/ranged_ints3_const.rs index c069ae7da0212..91e84f7ffbd1b 100644 --- a/tests/ui/unsafe/ranged_ints3_const.rs +++ b/tests/ui/unsafe/ranged_ints3_const.rs @@ -9,13 +9,13 @@ fn main() {} const fn foo() -> NonZero> { let mut x = unsafe { NonZero(Cell::new(1)) }; - let y = &x.0; //~ ERROR the borrowed element may contain interior mutability + let y = &x.0; //~^ ERROR borrow of layout constrained field with interior mutability unsafe { NonZero(Cell::new(1)) } } const fn bar() -> NonZero> { let mut x = unsafe { NonZero(Cell::new(1)) }; - let y = unsafe { &x.0 }; //~ ERROR the borrowed element may contain interior mutability + let y = unsafe { &x.0 }; unsafe { NonZero(Cell::new(1)) } } diff --git a/tests/ui/unsafe/ranged_ints3_const.stderr b/tests/ui/unsafe/ranged_ints3_const.stderr index c388a66f6315c..a72ab1a3b7449 100644 --- a/tests/ui/unsafe/ranged_ints3_const.stderr +++ b/tests/ui/unsafe/ranged_ints3_const.stderr @@ -6,27 +6,6 @@ LL | let y = &x.0; | = note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/ranged_ints3_const.rs:12:13 - | -LL | let y = &x.0; - | ^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/ranged_ints3_const.rs:19:22 - | -LL | let y = unsafe { &x.0 }; - | ^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0133, E0658. -For more information about an error, try `rustc --explain E0133`. +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/unsafe/union-pat-in-param.rs b/tests/ui/unsafe/union-pat-in-param.rs new file mode 100644 index 0000000000000..8454bfb20dcb8 --- /dev/null +++ b/tests/ui/unsafe/union-pat-in-param.rs @@ -0,0 +1,19 @@ +union U { + a: &'static i32, + b: usize, +} + +fn fun(U { a }: U) { + //~^ ERROR access to union field is unsafe + dbg!(*a); +} + +fn main() { + fun(U { b: 0 }); + + let closure = |U { a }| { + //~^ ERROR access to union field is unsafe + dbg!(*a); + }; + closure(U { b: 0 }); +} diff --git a/tests/ui/unsafe/union-pat-in-param.stderr b/tests/ui/unsafe/union-pat-in-param.stderr new file mode 100644 index 0000000000000..b9709b7cc9bf1 --- /dev/null +++ b/tests/ui/unsafe/union-pat-in-param.stderr @@ -0,0 +1,19 @@ +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-pat-in-param.rs:6:12 + | +LL | fn fun(U { a }: U) { + | ^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-pat-in-param.rs:14:24 + | +LL | let closure = |U { a }| { + | ^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/wf/ice-wf-missing-span-in-error-130012.rs b/tests/ui/wf/ice-wf-missing-span-in-error-130012.rs new file mode 100644 index 0000000000000..e107069d0dfa9 --- /dev/null +++ b/tests/ui/wf/ice-wf-missing-span-in-error-130012.rs @@ -0,0 +1,18 @@ +// Regression test for ICE #130012 +// Checks that we do not ICE while reporting +// lifetime mistmatch error + +trait Fun { + type Assoc; +} + +trait MyTrait: for<'a> Fun {} +//~^ ERROR binding for associated type `Assoc` references lifetime `'a`, which does not appear in the trait input types +//~| ERROR binding for associated type `Assoc` references lifetime `'a`, which does not appear in the trait input types +//~| ERROR binding for associated type `Assoc` references lifetime `'a`, which does not appear in the trait input types + +impl Fun> MyTrait for F {} +//~^ ERROR binding for associated type `Assoc` references lifetime `'b`, which does not appear in the trait input types +//~| ERROR mismatched types + +fn main() {} diff --git a/tests/ui/wf/ice-wf-missing-span-in-error-130012.stderr b/tests/ui/wf/ice-wf-missing-span-in-error-130012.stderr new file mode 100644 index 0000000000000..357e504bd5eb9 --- /dev/null +++ b/tests/ui/wf/ice-wf-missing-span-in-error-130012.stderr @@ -0,0 +1,41 @@ +error[E0582]: binding for associated type `Assoc` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/ice-wf-missing-span-in-error-130012.rs:9:28 + | +LL | trait MyTrait: for<'a> Fun {} + | ^^^^^^^^^^^^^^ + +error[E0582]: binding for associated type `Assoc` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/ice-wf-missing-span-in-error-130012.rs:9:28 + | +LL | trait MyTrait: for<'a> Fun {} + | ^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0582]: binding for associated type `Assoc` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/ice-wf-missing-span-in-error-130012.rs:9:28 + | +LL | trait MyTrait: for<'a> Fun {} + | ^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0582]: binding for associated type `Assoc` references lifetime `'b`, which does not appear in the trait input types + --> $DIR/ice-wf-missing-span-in-error-130012.rs:14:21 + | +LL | impl Fun> MyTrait for F {} + | ^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/ice-wf-missing-span-in-error-130012.rs:14:50 + | +LL | impl Fun> MyTrait for F {} + | ^ lifetime mismatch + | + = note: expected reference `&()` + found reference `&'b ()` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0308, E0582. +For more information about an error, try `rustc --explain E0308`. diff --git a/triagebot.toml b/triagebot.toml index d3333b67d155b..5d80b9e656ea0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -570,7 +570,7 @@ cc = ["@bjorn3"] cc = ["@antoyo", "@GuillaumeGomez"] [mentions."compiler/rustc_const_eval/src/interpret"] -message = "Some changes occurred to the CTFE / Miri engine" +message = "Some changes occurred to the CTFE / Miri interpreter" cc = ["@rust-lang/miri"] [mentions."compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs"] @@ -590,7 +590,7 @@ message = "changes to `inspect_obligations.rs`" cc = ["@compiler-errors", "@lcnr"] [mentions."compiler/rustc_middle/src/mir/interpret"] -message = "Some changes occurred to the CTFE / Miri engine" +message = "Some changes occurred to the CTFE / Miri interpreter" cc = ["@rust-lang/miri"] [mentions."compiler/rustc_mir_transform/src/"] @@ -659,6 +659,13 @@ LLVM backend as well as portable-simd gets adapted for the changes. """ cc = ["@antoyo", "@GuillaumeGomez", "@bjorn3", "@calebzulawski", "@programmerjake"] +[mentions."library/core/src/intrinsics"] +message = """ +Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter +gets adapted for the changes, if necessary. +""" +cc = ["@rust-lang/miri"] + [mentions."library/portable-simd"] message = """ Portable SIMD is developed in its own repository. If possible, consider \ @@ -913,7 +920,12 @@ cc = ["@kobzol"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "jhpratt", "oli-obk", "kobzol", "joboet"] +users_on_vacation = [ + "fmease", + "jhpratt", + "jyn514", + "oli-obk", +] [assign.adhoc_groups] compiler-team = [ @@ -952,6 +964,7 @@ libs = [ "@jhpratt", "@tgross35", "@thomcc", + "@ibraheemdev", ] bootstrap = [ "@Mark-Simulacrum",