Merge pull request #18566 from lnicola/sync-from-rust
minor: Sync from downstream
This commit is contained in:
commit
8cf30c2356
4016 changed files with 79307 additions and 36828 deletions
2
.github/ISSUE_TEMPLATE/tracking_issue.md
vendored
2
.github/ISSUE_TEMPLATE/tracking_issue.md
vendored
|
@ -46,7 +46,7 @@ for larger features an implementation could be broken up into multiple PRs.
|
||||||
|
|
||||||
[stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr
|
[stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr
|
||||||
[doc-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#documentation-prs
|
[doc-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#documentation-prs
|
||||||
[nightly-style-procedure]: https://github.com/rust-lang/style-team/blob/master/nightly-style-procedure.md
|
[nightly-style-procedure]: https://github.com/rust-lang/style-team/blob/main/nightly-style-procedure.md
|
||||||
[Style Guide]: https://github.com/rust-lang/rust/tree/master/src/doc/style-guide
|
[Style Guide]: https://github.com/rust-lang/rust/tree/master/src/doc/style-guide
|
||||||
|
|
||||||
### Unresolved Questions
|
### Unresolved Questions
|
||||||
|
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -65,7 +65,7 @@ jobs:
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}
|
shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}
|
||||||
timeout-minutes: 240
|
timeout-minutes: 360
|
||||||
env:
|
env:
|
||||||
CI_JOB_NAME: ${{ matrix.image }}
|
CI_JOB_NAME: ${{ matrix.image }}
|
||||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
|
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
|
||||||
|
@ -110,11 +110,7 @@ jobs:
|
||||||
# less disk space.
|
# less disk space.
|
||||||
- name: free up disk space
|
- name: free up disk space
|
||||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
if: contains(matrix.os, 'ubuntu')
|
if: matrix.free_disk
|
||||||
with:
|
|
||||||
# Removing packages with APT saves ~5 GiB, but takes several
|
|
||||||
# minutes (and potentially removes important packages).
|
|
||||||
large-packages: false
|
|
||||||
|
|
||||||
# Rust Log Analyzer can't currently detect the PR number of a GitHub
|
# Rust Log Analyzer can't currently detect the PR number of a GitHub
|
||||||
# Actions build on its own, so a hint in the log message is needed to
|
# Actions build on its own, so a hint in the log message is needed to
|
||||||
|
|
22
.mailmap
22
.mailmap
|
@ -31,6 +31,7 @@ Alexis Beingessner <a.beingessner@gmail.com>
|
||||||
Alfie John <alfie@alfie.wtf> Alfie John <alfiej@fastmail.fm>
|
Alfie John <alfie@alfie.wtf> Alfie John <alfiej@fastmail.fm>
|
||||||
Alona Enraght-Moony <code@alona.page> <nixon.emoony@gmail.com>
|
Alona Enraght-Moony <code@alona.page> <nixon.emoony@gmail.com>
|
||||||
Alona Enraght-Moony <code@alona.page> <nixon@caminus.local>
|
Alona Enraght-Moony <code@alona.page> <nixon@caminus.local>
|
||||||
|
Alona Enraght-Moony <code@alona.page> <contact@alona.page>
|
||||||
Amanda Stjerna <mail@amandastjerna.se> <albin.stjerna@gmail.com>
|
Amanda Stjerna <mail@amandastjerna.se> <albin.stjerna@gmail.com>
|
||||||
Amanda Stjerna <mail@amandastjerna.se> <amanda.stjerna@it.uu.se>
|
Amanda Stjerna <mail@amandastjerna.se> <amanda.stjerna@it.uu.se>
|
||||||
Amos Onn <amosonn@gmail.com>
|
Amos Onn <amosonn@gmail.com>
|
||||||
|
@ -75,6 +76,7 @@ Benjamin Jackman <ben@jackman.biz>
|
||||||
Benoît Cortier <benoit.cortier@fried-world.eu>
|
Benoît Cortier <benoit.cortier@fried-world.eu>
|
||||||
Bheesham Persaud <bheesham123@hotmail.com> Bheesham Persaud <bheesham.persaud@live.ca>
|
Bheesham Persaud <bheesham123@hotmail.com> Bheesham Persaud <bheesham.persaud@live.ca>
|
||||||
bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3@users.noreply.github.com>
|
bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3@users.noreply.github.com>
|
||||||
|
bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3_gh@protonmail.com>
|
||||||
Björn Steinbrink <bsteinbr@gmail.com> <B.Steinbrink@gmx.de>
|
Björn Steinbrink <bsteinbr@gmail.com> <B.Steinbrink@gmx.de>
|
||||||
blake2-ppc <ulrik.sverdrup@gmail.com> <blake2-ppc>
|
blake2-ppc <ulrik.sverdrup@gmail.com> <blake2-ppc>
|
||||||
blyxyas <blyxyas@gmail.com> Alejandra González <blyxyas@gmail.com>
|
blyxyas <blyxyas@gmail.com> Alejandra González <blyxyas@gmail.com>
|
||||||
|
@ -172,6 +174,7 @@ Dzmitry Malyshau <kvarkus@gmail.com>
|
||||||
E. Dunham <edunham@mozilla.com> edunham <edunham@mozilla.com>
|
E. Dunham <edunham@mozilla.com> edunham <edunham@mozilla.com>
|
||||||
Ed Barnard <eabarnard@gmail.com>
|
Ed Barnard <eabarnard@gmail.com>
|
||||||
Eduard-Mihai Burtescu <edy.burt@gmail.com>
|
Eduard-Mihai Burtescu <edy.burt@gmail.com>
|
||||||
|
Eduard-Mihai Burtescu <edy.burt@gmail.com> <eddyb@lyken.rs>
|
||||||
Eduardo Bautista <me@eduardobautista.com> <=>
|
Eduardo Bautista <me@eduardobautista.com> <=>
|
||||||
Eduardo Bautista <me@eduardobautista.com> <mail@eduardobautista.com>
|
Eduardo Bautista <me@eduardobautista.com> <mail@eduardobautista.com>
|
||||||
Eduardo Broto <ebroto@tutanota.com>
|
Eduardo Broto <ebroto@tutanota.com>
|
||||||
|
@ -186,6 +189,7 @@ Erick Tryzelaar <erick.tryzelaar@gmail.com> <etryzelaar@iqt.org>
|
||||||
Erik Desjardins <erikdesjardins@users.noreply.github.com>
|
Erik Desjardins <erikdesjardins@users.noreply.github.com>
|
||||||
Erik Jensen <erikjensen@rkjnsn.net>
|
Erik Jensen <erikjensen@rkjnsn.net>
|
||||||
Erin Power <xampprocky@gmail.com>
|
Erin Power <xampprocky@gmail.com>
|
||||||
|
Erin Power <xampprocky@gmail.com> <xampprocky@icloud.com>
|
||||||
Erin Power <xampprocky@gmail.com> <theaaronepower@gmail.com>
|
Erin Power <xampprocky@gmail.com> <theaaronepower@gmail.com>
|
||||||
Erin Power <xampprocky@gmail.com> <Aaronepower@users.noreply.github.com>
|
Erin Power <xampprocky@gmail.com> <Aaronepower@users.noreply.github.com>
|
||||||
Esteban Küber <esteban@kuber.com.ar>
|
Esteban Küber <esteban@kuber.com.ar>
|
||||||
|
@ -198,6 +202,7 @@ F001 <changchun.fan@qq.com>
|
||||||
Fabian Kössel <fkjogu@users.noreply.github.com>
|
Fabian Kössel <fkjogu@users.noreply.github.com>
|
||||||
Falco Hirschenberger <falco.hirschenberger@gmail.com> <hirschen@itwm.fhg.de>
|
Falco Hirschenberger <falco.hirschenberger@gmail.com> <hirschen@itwm.fhg.de>
|
||||||
Felix S. Klock II <pnkfelix@pnkfx.org> Felix S Klock II <pnkfelix@pnkfx.org>
|
Felix S. Klock II <pnkfelix@pnkfx.org> Felix S Klock II <pnkfelix@pnkfx.org>
|
||||||
|
Felix S. Klock II <pnkfelix@pnkfx.org> <pnkfelix@mozilla.com>
|
||||||
Félix Saparelli <felix@passcod.name>
|
Félix Saparelli <felix@passcod.name>
|
||||||
Flaper Fesp <flaper87@gmail.com>
|
Flaper Fesp <flaper87@gmail.com>
|
||||||
Florian Berger <fbergr@gmail.com>
|
Florian Berger <fbergr@gmail.com>
|
||||||
|
@ -245,7 +250,7 @@ Irina Popa <irinagpopa@gmail.com>
|
||||||
Ivan Ivaschenko <defuz.net@gmail.com>
|
Ivan Ivaschenko <defuz.net@gmail.com>
|
||||||
ivan tkachenko <me@ratijas.tk>
|
ivan tkachenko <me@ratijas.tk>
|
||||||
J. J. Weber <jjweber@gmail.com>
|
J. J. Weber <jjweber@gmail.com>
|
||||||
Jack Huey <jack.huey@umassmed.edu>
|
Jack Huey <jack.huey@umassmed.edu> <jackh726@gmail.com>
|
||||||
Jacob <jacob.macritchie@gmail.com>
|
Jacob <jacob.macritchie@gmail.com>
|
||||||
Jacob Greenfield <xales@naveria.com>
|
Jacob Greenfield <xales@naveria.com>
|
||||||
Jacob Pratt <jacob@jhpratt.dev> <the.z.cuber@gmail.com>
|
Jacob Pratt <jacob@jhpratt.dev> <the.z.cuber@gmail.com>
|
||||||
|
@ -292,6 +297,7 @@ John Clements <clements@racket-lang.org> <clements@brinckerhoff.org>
|
||||||
John Hodge <acessdev@gmail.com> John Hodge <tpg@mutabah.net>
|
John Hodge <acessdev@gmail.com> John Hodge <tpg@mutabah.net>
|
||||||
John Hörnvall <trolledwoods@gmail.com>
|
John Hörnvall <trolledwoods@gmail.com>
|
||||||
John Kåre Alsaker <john.kare.alsaker@gmail.com>
|
John Kåre Alsaker <john.kare.alsaker@gmail.com>
|
||||||
|
John Kåre Alsaker <john.kare.alsaker@gmail.com> <zoxc32@gmail.com>
|
||||||
John Talling <inrustwetrust@users.noreply.github.com>
|
John Talling <inrustwetrust@users.noreply.github.com>
|
||||||
John Van Enk <vanenkj@gmail.com>
|
John Van Enk <vanenkj@gmail.com>
|
||||||
Jonas Tepe <jonasprogrammer@gmail.com>
|
Jonas Tepe <jonasprogrammer@gmail.com>
|
||||||
|
@ -368,6 +374,7 @@ Lukas Lueg <lukas.lueg@gmail.com>
|
||||||
Luke Metz <luke.metz@students.olin.edu>
|
Luke Metz <luke.metz@students.olin.edu>
|
||||||
Luqman Aden <me@luqman.ca> <laden@csclub.uwaterloo.ca>
|
Luqman Aden <me@luqman.ca> <laden@csclub.uwaterloo.ca>
|
||||||
Luqman Aden <me@luqman.ca> <laden@mozilla.com>
|
Luqman Aden <me@luqman.ca> <laden@mozilla.com>
|
||||||
|
Luqman Aden <me@luqman.ca> <rust@luqman.ca>
|
||||||
Lzu Tao <taolzu@gmail.com>
|
Lzu Tao <taolzu@gmail.com>
|
||||||
Maik Klein <maikklein@googlemail.com>
|
Maik Klein <maikklein@googlemail.com>
|
||||||
Malo Jaffré <jaffre.malo@gmail.com>
|
Malo Jaffré <jaffre.malo@gmail.com>
|
||||||
|
@ -409,6 +416,7 @@ mental <m3nta1@yahoo.com>
|
||||||
mibac138 <5672750+mibac138@users.noreply.github.com>
|
mibac138 <5672750+mibac138@users.noreply.github.com>
|
||||||
Michael Williams <m.t.williams@live.com>
|
Michael Williams <m.t.williams@live.com>
|
||||||
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail>
|
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail>
|
||||||
|
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail.com>
|
||||||
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@users.noreply.github.com>
|
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@users.noreply.github.com>
|
||||||
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@posteo.net>
|
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@posteo.net>
|
||||||
Michael Zhang <hmperson1@gmail.com>
|
Michael Zhang <hmperson1@gmail.com>
|
||||||
|
@ -422,6 +430,7 @@ Ms2ger <ms2ger@gmail.com> <Ms2ger@gmail.com>
|
||||||
msizanoen1 <qtmlabs@protonmail.com>
|
msizanoen1 <qtmlabs@protonmail.com>
|
||||||
Mukilan Thiagarajan <mukilanthiagarajan@gmail.com>
|
Mukilan Thiagarajan <mukilanthiagarajan@gmail.com>
|
||||||
Nadrieril Feneanar <Nadrieril@users.noreply.github.com>
|
Nadrieril Feneanar <Nadrieril@users.noreply.github.com>
|
||||||
|
Nadrieril Feneanar <Nadrieril@users.noreply.github.com> <nadrieril+git@gmail.com>
|
||||||
NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm@gmail.com>
|
NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm@gmail.com>
|
||||||
NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm+github@gmail.com>
|
NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm+github@gmail.com>
|
||||||
Nathan Ringo <remexre@gmail.com>
|
Nathan Ringo <remexre@gmail.com>
|
||||||
|
@ -442,6 +451,8 @@ Niclas Schwarzlose <15schnic@gmail.com>
|
||||||
Nicolas Abram <abramlujan@gmail.com>
|
Nicolas Abram <abramlujan@gmail.com>
|
||||||
Nicole Mazzuca <npmazzuca@gmail.com>
|
Nicole Mazzuca <npmazzuca@gmail.com>
|
||||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com>
|
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com>
|
||||||
|
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nilstrieb@gmail.com>
|
||||||
|
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nora@noratrieb.dev>
|
||||||
Nif Ward <nif.ward@gmail.com>
|
Nif Ward <nif.ward@gmail.com>
|
||||||
Nika Layzell <nika@thelayzells.com> <michael@thelayzells.com>
|
Nika Layzell <nika@thelayzells.com> <michael@thelayzells.com>
|
||||||
NODA Kai <nodakai@gmail.com>
|
NODA Kai <nodakai@gmail.com>
|
||||||
|
@ -460,6 +471,7 @@ Oliver Scherer <oli-obk@users.noreply.github.com> <github6541940@oli-obk.de>
|
||||||
Oliver Scherer <oli-obk@users.noreply.github.com> <public.oliver.schneider@kit.edu>
|
Oliver Scherer <oli-obk@users.noreply.github.com> <public.oliver.schneider@kit.edu>
|
||||||
Oliver Scherer <oli-obk@users.noreply.github.com> <oliver.schneider@kit.edu>
|
Oliver Scherer <oli-obk@users.noreply.github.com> <oliver.schneider@kit.edu>
|
||||||
Oliver Scherer <oli-obk@users.noreply.github.com> <obk8176014uqher834@olio-obk.de>
|
Oliver Scherer <oli-obk@users.noreply.github.com> <obk8176014uqher834@olio-obk.de>
|
||||||
|
Oliver Scherer <oli-obk@users.noreply.github.com> <rustc-contact@oli-obk.de>
|
||||||
Oliver Scherer <oli-obk@users.noreply.github.com>
|
Oliver Scherer <oli-obk@users.noreply.github.com>
|
||||||
Onur Özkan <onurozkan.dev@outlook.com> <work@onurozkan.dev>
|
Onur Özkan <onurozkan.dev@outlook.com> <work@onurozkan.dev>
|
||||||
Onur Özkan <onurozkan.dev@outlook.com>
|
Onur Özkan <onurozkan.dev@outlook.com>
|
||||||
|
@ -496,6 +508,7 @@ Raphaël Huchet <rap2hpoutre@users.noreply.github.com>
|
||||||
rChaser53 <tayoshizawa29@gmail.com>
|
rChaser53 <tayoshizawa29@gmail.com>
|
||||||
Rémy Rakic <remy.rakic@gmail.com>
|
Rémy Rakic <remy.rakic@gmail.com>
|
||||||
Rémy Rakic <remy.rakic@gmail.com> <remy.rakic+github@gmail.com>
|
Rémy Rakic <remy.rakic@gmail.com> <remy.rakic+github@gmail.com>
|
||||||
|
Rémy Rakic <remy.rakic@gmail.com> <remy.rakic+rust@gmail.com>
|
||||||
Renato Riccieri Santos Zannon <renato@rrsz.com.br>
|
Renato Riccieri Santos Zannon <renato@rrsz.com.br>
|
||||||
Richard Diamond <wichard@vitalitystudios.com> <wichard@hahbee.co>
|
Richard Diamond <wichard@vitalitystudios.com> <wichard@hahbee.co>
|
||||||
Ricky Hosfelt <ricky@hosfelt.io>
|
Ricky Hosfelt <ricky@hosfelt.io>
|
||||||
|
@ -525,6 +538,7 @@ Samuel Tardieu <sam@rfc1149.net>
|
||||||
Santiago Pastorino <spastorino@gmail.com>
|
Santiago Pastorino <spastorino@gmail.com>
|
||||||
Santiago Pastorino <spastorino@gmail.com> <santiago@wyeworks.com>
|
Santiago Pastorino <spastorino@gmail.com> <santiago@wyeworks.com>
|
||||||
Scott McMurray <scottmcm@users.noreply.github.com>
|
Scott McMurray <scottmcm@users.noreply.github.com>
|
||||||
|
Scott McMurray <scottmcm@users.noreply.github.com> <smcmurray@acm.org>
|
||||||
Scott Olson <scott@solson.me> Scott Olson <scott@scott-olson.org>
|
Scott Olson <scott@solson.me> Scott Olson <scott@scott-olson.org>
|
||||||
Sean Gillespie <sean.william.g@gmail.com> swgillespie <sean.william.g@gmail.com>
|
Sean Gillespie <sean.william.g@gmail.com> swgillespie <sean.william.g@gmail.com>
|
||||||
Seiichi Uchida <seuchida@gmail.com>
|
Seiichi Uchida <seuchida@gmail.com>
|
||||||
|
@ -536,6 +550,7 @@ Shyam Sundar B <shyambaskaran@outlook.com>
|
||||||
Simon Barber-Dueck <sbarberdueck@gmail.com> Simon BD <simon@server>
|
Simon Barber-Dueck <sbarberdueck@gmail.com> Simon BD <simon@server>
|
||||||
Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org>
|
Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org>
|
||||||
Simonas Kazlauskas <git@kazlauskas.me> Simonas Kazlauskas <github@kazlauskas.me>
|
Simonas Kazlauskas <git@kazlauskas.me> Simonas Kazlauskas <github@kazlauskas.me>
|
||||||
|
Simonas Kazlauskas <git@kazlauskas.me> <simonas+t-compiler@kazlauskas.me>
|
||||||
Siva Prasad <sivaauturic@gmail.com>
|
Siva Prasad <sivaauturic@gmail.com>
|
||||||
Smittyvb <me@smitop.com>
|
Smittyvb <me@smitop.com>
|
||||||
Srinivas Reddy Thatiparthy <thatiparthysreenivas@gmail.com>
|
Srinivas Reddy Thatiparthy <thatiparthysreenivas@gmail.com>
|
||||||
|
@ -556,6 +571,8 @@ Tatsuyuki Ishi <ishitatsuyuki@gmail.com>
|
||||||
Tau Gärtli <git@tau.garden> <ruben.schmidmeister@icloud.com>
|
Tau Gärtli <git@tau.garden> <ruben.schmidmeister@icloud.com>
|
||||||
Tero Hänninen <lgvz@users.noreply.github.com> Tero Hänninen <tejohann@kapsi.fi>
|
Tero Hänninen <lgvz@users.noreply.github.com> Tero Hänninen <tejohann@kapsi.fi>
|
||||||
The8472 <git@infinite-source.de>
|
The8472 <git@infinite-source.de>
|
||||||
|
The8472 <git@infinite-source.de> <the8472.rs@infinite-source.de>
|
||||||
|
The8472 <git@infinite-source.de> <the8472@users.noreply.github.com>
|
||||||
Theo Belaire <theo.belaire@gmail.com> Theo Belaire <tyr.god.of.war.42@gmail.com>
|
Theo Belaire <theo.belaire@gmail.com> Theo Belaire <tyr.god.of.war.42@gmail.com>
|
||||||
Theodore Luo Wang <wangtheo662@gmail.com>
|
Theodore Luo Wang <wangtheo662@gmail.com>
|
||||||
Thiago Pontes <email@thiago.me> thiagopnts <thiagopnts@gmail.com>
|
Thiago Pontes <email@thiago.me> thiagopnts <thiagopnts@gmail.com>
|
||||||
|
@ -593,7 +610,8 @@ Waffle Lapkin <waffle.lapkin@tasking.com>
|
||||||
Wesley Wiser <wwiser@gmail.com> <wesleywiser@microsoft.com>
|
Wesley Wiser <wwiser@gmail.com> <wesleywiser@microsoft.com>
|
||||||
whitequark <whitequark@whitequark.org>
|
whitequark <whitequark@whitequark.org>
|
||||||
William Ting <io@williamting.com> <william.h.ting@gmail.com>
|
William Ting <io@williamting.com> <william.h.ting@gmail.com>
|
||||||
Wim Looman <wim@nemo157.com>
|
Wim Looman <wim@nemo157.com> <rust-lang@nemo157.com>
|
||||||
|
Wim Looman <wim@nemo157.com> <git@nemo157.com>
|
||||||
Without Boats <woboats@gmail.com>
|
Without Boats <woboats@gmail.com>
|
||||||
Without Boats <woboats@gmail.com> <boats@mozilla.com>
|
Without Boats <woboats@gmail.com> <boats@mozilla.com>
|
||||||
Xinye Tao <xy.tao@outlook.com>
|
Xinye Tao <xy.tao@outlook.com>
|
||||||
|
|
73
COPYRIGHT
73
COPYRIGHT
|
@ -343,49 +343,42 @@ their own copyright notices and license terms:
|
||||||
* Portions of internationalization code use code or data from Unicode, which
|
* Portions of internationalization code use code or data from Unicode, which
|
||||||
carry the following license:
|
carry the following license:
|
||||||
|
|
||||||
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
|
UNICODE LICENSE V3
|
||||||
|
|
||||||
See Terms of Use <https://www.unicode.org/copyright.html>
|
|
||||||
for definitions of Unicode Inc.’s Data Files and Software.
|
|
||||||
|
|
||||||
NOTICE TO USER: Carefully read the following legal agreement.
|
|
||||||
BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
|
|
||||||
DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
|
|
||||||
YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
|
||||||
TERMS AND CONDITIONS OF THIS AGREEMENT.
|
|
||||||
IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
|
|
||||||
THE DATA FILES OR SOFTWARE.
|
|
||||||
|
|
||||||
COPYRIGHT AND PERMISSION NOTICE
|
COPYRIGHT AND PERMISSION NOTICE
|
||||||
|
|
||||||
Copyright © 1991-2022 Unicode, Inc. All rights reserved.
|
Copyright © 1991-2024 Unicode, Inc.
|
||||||
Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
NOTICE TO USER: Carefully read the following legal agreement. BY
|
||||||
a copy of the Unicode data files and any associated documentation
|
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
|
||||||
(the "Data Files") or Unicode software and any associated documentation
|
SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
||||||
(the "Software") to deal in the Data Files or Software
|
TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
|
||||||
without restriction, including without limitation the rights to use,
|
DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
||||||
copy, modify, merge, publish, distribute, and/or sell copies of
|
|
||||||
the Data Files or Software, and to permit persons to whom the Data Files
|
|
||||||
or Software are furnished to do so, provided that either
|
|
||||||
(a) this copyright and permission notice appear with all copies
|
|
||||||
of the Data Files or Software, or
|
|
||||||
(b) this copyright and permission notice appear in associated
|
|
||||||
Documentation.
|
|
||||||
|
|
||||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
copy of data files and any associated documentation (the "Data Files") or
|
||||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
software and any associated documentation (the "Software") to deal in the
|
||||||
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
Data Files or Software without restriction, including without limitation
|
||||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||||
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
copies of the Data Files or Software, and to permit persons to whom the
|
||||||
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
Data Files or Software are furnished to do so, provided that either (a)
|
||||||
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
this copyright and permission notice appear with all copies of the Data
|
||||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
Files or Software, or (b) this copyright and permission notice appear in
|
||||||
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
associated Documentation.
|
||||||
|
|
||||||
Except as contained in this notice, the name of a copyright holder
|
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||||
shall not be used in advertising or otherwise to promote the sale,
|
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
use or other dealings in these Data Files or Software without prior
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||||
written authorization of the copyright holder.
|
THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
|
||||||
|
BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
|
||||||
|
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
|
||||||
|
FILES OR SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of a copyright holder shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or other
|
||||||
|
dealings in these Data Files or Software without prior written
|
||||||
|
authorization of the copyright holder.
|
||||||
|
|
550
Cargo.lock
550
Cargo.lock
File diff suppressed because it is too large
Load diff
|
@ -2,9 +2,12 @@
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"compiler/rustc",
|
"compiler/rustc",
|
||||||
|
"src/build_helper",
|
||||||
"src/etc/test-float-parse",
|
"src/etc/test-float-parse",
|
||||||
|
"src/rustc-std-workspace/rustc-std-workspace-core",
|
||||||
|
"src/rustc-std-workspace/rustc-std-workspace-alloc",
|
||||||
|
"src/rustc-std-workspace/rustc-std-workspace-std",
|
||||||
"src/rustdoc-json-types",
|
"src/rustdoc-json-types",
|
||||||
"src/tools/build_helper",
|
|
||||||
"src/tools/cargotest",
|
"src/tools/cargotest",
|
||||||
"src/tools/clippy",
|
"src/tools/clippy",
|
||||||
"src/tools/clippy/clippy_dev",
|
"src/tools/clippy/clippy_dev",
|
||||||
|
|
39
LICENSES/Unicode-3.0.txt
Normal file
39
LICENSES/Unicode-3.0.txt
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
UNICODE LICENSE V3
|
||||||
|
|
||||||
|
COPYRIGHT AND PERMISSION NOTICE
|
||||||
|
|
||||||
|
Copyright © 1991-2024 Unicode, Inc.
|
||||||
|
|
||||||
|
NOTICE TO USER: Carefully read the following legal agreement. BY
|
||||||
|
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
|
||||||
|
SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
||||||
|
TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
|
||||||
|
DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of data files and any associated documentation (the "Data Files") or
|
||||||
|
software and any associated documentation (the "Software") to deal in the
|
||||||
|
Data Files or Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||||
|
copies of the Data Files or Software, and to permit persons to whom the
|
||||||
|
Data Files or Software are furnished to do so, provided that either (a)
|
||||||
|
this copyright and permission notice appear with all copies of the Data
|
||||||
|
Files or Software, or (b) this copyright and permission notice appear in
|
||||||
|
associated Documentation.
|
||||||
|
|
||||||
|
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||||
|
THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
|
||||||
|
BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
|
||||||
|
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
|
||||||
|
FILES OR SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of a copyright holder shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or other
|
||||||
|
dealings in these Data Files or Software without prior written
|
||||||
|
authorization of the copyright holder.
|
|
@ -1,22 +0,0 @@
|
||||||
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
|
|
||||||
|
|
||||||
Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/.
|
|
||||||
|
|
||||||
Unicode Data Files do not include PDF online code charts under the directory http://www.unicode.org/Public/.
|
|
||||||
|
|
||||||
Software includes any source code published in the Unicode Standard or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/.
|
|
||||||
|
|
||||||
NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
|
||||||
|
|
||||||
COPYRIGHT AND PERMISSION NOTICE
|
|
||||||
|
|
||||||
Copyright © 1991-2016 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either
|
|
||||||
|
|
||||||
(a) this copyright and permission notice appear with all copies of the Data Files or Software, or
|
|
||||||
(b) this copyright and permission notice appear in associated Documentation.
|
|
||||||
|
|
||||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder.
|
|
241
RELEASES.md
241
RELEASES.md
|
@ -1,3 +1,235 @@
|
||||||
|
Version 1.83.0 (2024-11-28)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
<a id="1.83.0-Language"></a>
|
||||||
|
|
||||||
|
Language
|
||||||
|
--------
|
||||||
|
- [Stabilize `&mut`, `*mut`, `&Cell`, and `*const Cell` in const.](https://github.com/rust-lang/rust/pull/129195)
|
||||||
|
- [Allow creating references to statics in `const` initializers.](https://github.com/rust-lang/rust/pull/129759)
|
||||||
|
- [Implement raw lifetimes and labels (`'r#ident`).](https://github.com/rust-lang/rust/pull/126452)
|
||||||
|
- [Define behavior when atomic and non-atomic reads race.](https://github.com/rust-lang/rust/pull/128778)
|
||||||
|
- [Non-exhaustive structs may now be empty.](https://github.com/rust-lang/rust/pull/128934)
|
||||||
|
- [Disallow implicit coercions from places of type `!`](https://github.com/rust-lang/rust/pull/129392)
|
||||||
|
- [`const extern` functions can now be defined for other calling conventions.](https://github.com/rust-lang/rust/pull/129753)
|
||||||
|
- [Stabilize `expr_2021` macro fragment specifier in all editions.](https://github.com/rust-lang/rust/pull/129972)
|
||||||
|
- [The `non_local_definitions` lint now fires on less code and warns by default.](https://github.com/rust-lang/rust/pull/127117)
|
||||||
|
|
||||||
|
|
||||||
|
<a id="1.83.0-Compiler"></a>
|
||||||
|
|
||||||
|
Compiler
|
||||||
|
--------
|
||||||
|
- [Deprecate unsound `-Csoft-float` flag.](https://github.com/rust-lang/rust/pull/129897)
|
||||||
|
- Add many new tier 3 targets:
|
||||||
|
- [`aarch64_unknown_nto_qnx700`](https://github.com/rust-lang/rust/pull/127897)
|
||||||
|
- [`arm64e-apple-tvos`](https://github.com/rust-lang/rust/pull/130614)
|
||||||
|
- [`armv7-rtems-eabihf`](https://github.com/rust-lang/rust/pull/127021)
|
||||||
|
- [`loongarch64-unknown-linux-ohos`](https://github.com/rust-lang/rust/pull/130750)
|
||||||
|
- [`riscv32-wrs-vxworks` and `riscv64-wrs-vxworks`](https://github.com/rust-lang/rust/pull/130549)
|
||||||
|
- [`riscv32{e|em|emc}-unknown-none-elf`](https://github.com/rust-lang/rust/pull/130555)
|
||||||
|
- [`x86_64-unknown-hurd-gnu`](https://github.com/rust-lang/rust/pull/128345)
|
||||||
|
- [`x86_64-unknown-trusty`](https://github.com/rust-lang/rust/pull/130453)
|
||||||
|
|
||||||
|
Refer to Rust's [platform support page][platform-support-doc]
|
||||||
|
for more information on Rust's tiered platform support.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="1.83.0-Libraries"></a>
|
||||||
|
|
||||||
|
Libraries
|
||||||
|
---------
|
||||||
|
- [Implement `PartialEq` for `ExitCode`.](https://github.com/rust-lang/rust/pull/127633)
|
||||||
|
- [Document that `catch_unwind` can deal with foreign exceptions without UB, although the exact behavior is unspecified.](https://github.com/rust-lang/rust/pull/128321)
|
||||||
|
- [Implement `Default` for `HashMap`/`HashSet` iterators that don't already have it.](https://github.com/rust-lang/rust/pull/128711)
|
||||||
|
- [Bump Unicode to version 16.0.0.](https://github.com/rust-lang/rust/pull/130183)
|
||||||
|
- [Change documentation of `ptr::add`/`sub` to not claim equivalence with `offset`.](https://github.com/rust-lang/rust/pull/130229).
|
||||||
|
|
||||||
|
|
||||||
|
<a id="1.83.0-Stabilized-APIs"></a>
|
||||||
|
|
||||||
|
Stabilized APIs
|
||||||
|
---------------
|
||||||
|
|
||||||
|
- [`BufRead::skip_until`](https://doc.rust-lang.org/stable/std/io/trait.BufRead.html#method.skip_until)
|
||||||
|
- [`ControlFlow::break_value`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.break_value)
|
||||||
|
- [`ControlFlow::continue_value`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.continue_value)
|
||||||
|
- [`ControlFlow::map_break`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.map_break)
|
||||||
|
- [`ControlFlow::map_continue`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.map_continue)
|
||||||
|
- [`DebugList::finish_non_exhaustive`](https://doc.rust-lang.org/stable/core/fmt/struct.DebugList.html#method.finish_non_exhaustive)
|
||||||
|
- [`DebugMap::finish_non_exhaustive`](https://doc.rust-lang.org/stable/core/fmt/struct.DebugMap.html#method.finish_non_exhaustive)
|
||||||
|
- [`DebugSet::finish_non_exhaustive`](https://doc.rust-lang.org/stable/core/fmt/struct.DebugSet.html#method.finish_non_exhaustive)
|
||||||
|
- [`DebugTuple::finish_non_exhaustive`](https://doc.rust-lang.org/stable/core/fmt/struct.DebugTuple.html#method.finish_non_exhaustive)
|
||||||
|
- [`ErrorKind::ArgumentListTooLong`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.ArgumentListTooLong)
|
||||||
|
- [`ErrorKind::Deadlock`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.Deadlock)
|
||||||
|
- [`ErrorKind::DirectoryNotEmpty`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.DirectoryNotEmpty)
|
||||||
|
- [`ErrorKind::ExecutableFileBusy`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.ExecutableFileBusy)
|
||||||
|
- [`ErrorKind::FileTooLarge`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.FileTooLarge)
|
||||||
|
- [`ErrorKind::HostUnreachable`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.HostUnreachable)
|
||||||
|
- [`ErrorKind::IsADirectory`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.IsADirectory)
|
||||||
|
- [`ErrorKind::NetworkDown`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.NetworkDown)
|
||||||
|
- [`ErrorKind::NetworkUnreachable`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.NetworkUnreachable)
|
||||||
|
- [`ErrorKind::NotADirectory`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.NotADirectory)
|
||||||
|
- [`ErrorKind::NotSeekable`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.NotSeekable)
|
||||||
|
- [`ErrorKind::ReadOnlyFilesystem`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.ReadOnlyFilesystem)
|
||||||
|
- [`ErrorKind::ResourceBusy`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.ResourceBusy)
|
||||||
|
- [`ErrorKind::StaleNetworkFileHandle`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.StaleNetworkFileHandle)
|
||||||
|
- [`ErrorKind::StorageFull`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.StorageFull)
|
||||||
|
- [`ErrorKind::TooManyLinks`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.TooManyLinks)
|
||||||
|
- [`Option::get_or_insert_default`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.get_or_insert_default)
|
||||||
|
- [`Waker::data`](https://doc.rust-lang.org/stable/core/task/struct.Waker.html#method.data)
|
||||||
|
- [`Waker::new`](https://doc.rust-lang.org/stable/core/task/struct.Waker.html#method.new)
|
||||||
|
- [`Waker::vtable`](https://doc.rust-lang.org/stable/core/task/struct.Waker.html#method.vtable)
|
||||||
|
- [`char::MIN`](https://doc.rust-lang.org/stable/core/primitive.char.html#associatedconstant.MIN)
|
||||||
|
- [`hash_map::Entry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/hash_map/enum.Entry.html#method.insert_entry)
|
||||||
|
- [`hash_map::VacantEntry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/hash_map/struct.VacantEntry.html#method.insert_entry)
|
||||||
|
|
||||||
|
These APIs are now stable in const contexts:
|
||||||
|
|
||||||
|
- [`Cell::into_inner`](https://doc.rust-lang.org/stable/core/cell/struct.Cell.html#method.into_inner)
|
||||||
|
- [`Duration::as_secs_f32`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html#method.as_secs_f32)
|
||||||
|
- [`Duration::as_secs_f64`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html#method.as_secs_f64)
|
||||||
|
- [`Duration::div_duration_f32`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html#method.div_duration_f32)
|
||||||
|
- [`Duration::div_duration_f64`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html#method.div_duration_f64)
|
||||||
|
- [`MaybeUninit::as_mut_ptr`](https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html#method.as_mut_ptr)
|
||||||
|
- [`NonNull::as_mut`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.as_mut)
|
||||||
|
- [`NonNull::copy_from`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.copy_from)
|
||||||
|
- [`NonNull::copy_from_nonoverlapping`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.copy_from_nonoverlapping)
|
||||||
|
- [`NonNull::copy_to`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.copy_to)
|
||||||
|
- [`NonNull::copy_to_nonoverlapping`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.copy_to_nonoverlapping)
|
||||||
|
- [`NonNull::slice_from_raw_parts`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.slice_from_raw_parts)
|
||||||
|
- [`NonNull::write`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.write)
|
||||||
|
- [`NonNull::write_bytes`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.write_bytes)
|
||||||
|
- [`NonNull::write_unaligned`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.write_unaligned)
|
||||||
|
- [`OnceCell::into_inner`](https://doc.rust-lang.org/stable/core/cell/struct.OnceCell.html#method.into_inner)
|
||||||
|
- [`Option::as_mut`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.as_mut)
|
||||||
|
- [`Option::expect`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.expect)
|
||||||
|
- [`Option::replace`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.replace)
|
||||||
|
- [`Option::take`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.take)
|
||||||
|
- [`Option::unwrap`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.unwrap)
|
||||||
|
- [`Option::unwrap_unchecked`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.unwrap_unchecked)
|
||||||
|
- [`Option::<&_>::copied`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.copied)
|
||||||
|
- [`Option::<&mut _>::copied`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.copied-1)
|
||||||
|
- [`Option::<Option<_>>::flatten`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.flatten)
|
||||||
|
- [`Option::<Result<_, _>>::transpose`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.transpose)
|
||||||
|
- [`RefCell::into_inner`](https://doc.rust-lang.org/stable/core/cell/struct.RefCell.html#method.into_inner)
|
||||||
|
- [`Result::as_mut`](https://doc.rust-lang.org/stable/core/result/enum.Result.html#method.as_mut)
|
||||||
|
- [`Result::<&_, _>::copied`](https://doc.rust-lang.org/stable/core/result/enum.Result.html#method.copied)
|
||||||
|
- [`Result::<&mut _, _>::copied`](https://doc.rust-lang.org/stable/core/result/enum.Result.html#method.copied-1)
|
||||||
|
- [`Result::<Option<_>, _>::transpose`](https://doc.rust-lang.org/stable/core/result/enum.Result.html#method.transpose)
|
||||||
|
- [`UnsafeCell::get_mut`](https://doc.rust-lang.org/stable/core/cell/struct.UnsafeCell.html#method.get_mut)
|
||||||
|
- [`UnsafeCell::into_inner`](https://doc.rust-lang.org/stable/core/cell/struct.UnsafeCell.html#method.into_inner)
|
||||||
|
- [`array::from_mut`](https://doc.rust-lang.org/stable/core/array/fn.from_mut.html)
|
||||||
|
- [`char::encode_utf8`](https://doc.rust-lang.org/stable/core/primitive.char.html#method.encode_utf8)
|
||||||
|
- [`{float}::classify`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.classify)
|
||||||
|
- [`{float}::is_finite`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_finite)
|
||||||
|
- [`{float}::is_infinite`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_infinite)
|
||||||
|
- [`{float}::is_nan`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_nan)
|
||||||
|
- [`{float}::is_normal`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_normal)
|
||||||
|
- [`{float}::is_sign_negative`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_sign_negative)
|
||||||
|
- [`{float}::is_sign_positive`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_sign_positive)
|
||||||
|
- [`{float}::is_subnormal`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_subnormal)
|
||||||
|
- [`{float}::from_bits`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.from_bits)
|
||||||
|
- [`{float}::from_be_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.from_be_bytes)
|
||||||
|
- [`{float}::from_le_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.from_le_bytes)
|
||||||
|
- [`{float}::from_ne_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.from_ne_bytes)
|
||||||
|
- [`{float}::to_bits`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.to_bits)
|
||||||
|
- [`{float}::to_be_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.to_be_bytes)
|
||||||
|
- [`{float}::to_le_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.to_le_bytes)
|
||||||
|
- [`{float}::to_ne_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.to_ne_bytes)
|
||||||
|
- [`mem::replace`](https://doc.rust-lang.org/stable/core/mem/fn.replace.html)
|
||||||
|
- [`ptr::replace`](https://doc.rust-lang.org/stable/core/ptr/fn.replace.html)
|
||||||
|
- [`ptr::slice_from_raw_parts_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.slice_from_raw_parts_mut.html)
|
||||||
|
- [`ptr::write`](https://doc.rust-lang.org/stable/core/ptr/fn.write.html)
|
||||||
|
- [`ptr::write_unaligned`](https://doc.rust-lang.org/stable/core/ptr/fn.write_unaligned.html)
|
||||||
|
- [`<*const _>::copy_to`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_to)
|
||||||
|
- [`<*const _>::copy_to_nonoverlapping`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_to_nonoverlapping)
|
||||||
|
- [`<*mut _>::copy_from`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_from)
|
||||||
|
- [`<*mut _>::copy_from_nonoverlapping`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_from_nonoverlapping)
|
||||||
|
- [`<*mut _>::copy_to`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_to-1)
|
||||||
|
- [`<*mut _>::copy_to_nonoverlapping`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_to_nonoverlapping-1)
|
||||||
|
- [`<*mut _>::write`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.write)
|
||||||
|
- [`<*mut _>::write_bytes`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.write_bytes)
|
||||||
|
- [`<*mut _>::write_unaligned`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.write_unaligned)
|
||||||
|
- [`slice::from_mut`](https://doc.rust-lang.org/stable/core/slice/fn.from_mut.html)
|
||||||
|
- [`slice::from_raw_parts_mut`](https://doc.rust-lang.org/stable/core/slice/fn.from_raw_parts_mut.html)
|
||||||
|
- [`<[_]>::first_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.first_mut)
|
||||||
|
- [`<[_]>::last_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.last_mut)
|
||||||
|
- [`<[_]>::first_chunk_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.first_chunk_mut)
|
||||||
|
- [`<[_]>::last_chunk_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.last_chunk_mut)
|
||||||
|
- [`<[_]>::split_at_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut)
|
||||||
|
- [`<[_]>::split_at_mut_checked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut_checked)
|
||||||
|
- [`<[_]>::split_at_mut_unchecked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut_unchecked)
|
||||||
|
- [`<[_]>::split_first_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_first_mut)
|
||||||
|
- [`<[_]>::split_last_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_last_mut)
|
||||||
|
- [`<[_]>::split_first_chunk_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_first_chunk_mut)
|
||||||
|
- [`<[_]>::split_last_chunk_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_last_chunk_mut)
|
||||||
|
- [`str::as_bytes_mut`](https://doc.rust-lang.org/stable/core/primitive.str.html#method.as_bytes_mut)
|
||||||
|
- [`str::as_mut_ptr`](https://doc.rust-lang.org/stable/core/primitive.str.html#method.as_mut_ptr)
|
||||||
|
- [`str::from_utf8_unchecked_mut`](https://doc.rust-lang.org/stable/core/str/fn.from_utf8_unchecked_mut.html)
|
||||||
|
|
||||||
|
|
||||||
|
<a id="1.83.0-Cargo"></a>
|
||||||
|
|
||||||
|
Cargo
|
||||||
|
-----
|
||||||
|
- [Introduced a new `CARGO_MANIFEST_PATH` environment variable, similar to `CARGO_MANIFEST_DIR` but pointing directly to the manifest file.](https://github.com/rust-lang/cargo/pull/14404/)
|
||||||
|
- [Added `package.autolib` to the manifest, allowing `[lib]` auto-discovery to be disabled.](https://github.com/rust-lang/cargo/pull/14591/)
|
||||||
|
- [Declare support level for each crate in Cargo's Charter / crate docs.](https://github.com/rust-lang/cargo/pull/14600/)
|
||||||
|
- [Declare new Intentional Artifacts as 'small' changes.](https://github.com/rust-lang/cargo/pull/14599/)
|
||||||
|
|
||||||
|
|
||||||
|
<a id="1.83-Rustdoc"></a>
|
||||||
|
|
||||||
|
Rustdoc
|
||||||
|
-------
|
||||||
|
|
||||||
|
- [The sidebar / hamburger menu table of contents now includes the `# headers` from the main item's doc comment](https://github.com/rust-lang/rust/pull/120736). This is similar to a third-party feature provided by the rustdoc-search-enhancements browser extension.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="1.83.0-Compatibility-Notes"></a>
|
||||||
|
|
||||||
|
Compatibility Notes
|
||||||
|
-------------------
|
||||||
|
- [Warn against function pointers using unsupported ABI strings.](https://github.com/rust-lang/rust/pull/128784)
|
||||||
|
- [Check well-formedness of the source type's signature in fn pointer casts.](https://github.com/rust-lang/rust/pull/129021) This partly closes a soundness hole that comes when casting a function item to function pointer
|
||||||
|
- [Use equality instead of subtyping when resolving type dependent paths.](https://github.com/rust-lang/rust/pull/129073)
|
||||||
|
- Linking on macOS now correctly includes Rust's default deployment target. Due to a linker bug, you might have to pass `MACOSX_DEPLOYMENT_TARGET` or fix your `#[link]` attributes to point to the correct frameworks. See <https://github.com/rust-lang/rust/pull/129369>.
|
||||||
|
- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previous did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
|
||||||
|
- The future incompatibility lint `deprecated_cfg_attr_crate_type_name` [has been made into a hard error](https://github.com/rust-lang/rust/pull/129670). It was used to deny usage of `#![crate_type]` and `#![crate_name]` attributes in `#![cfg_attr]`, which required a hack in the compiler to be able to change the used crate type and crate name after cfg expansion.
|
||||||
|
Users can use `--crate-type` instead of `#![cfg_attr(..., crate_type = "...")]` and `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]` when running `rustc`/`cargo rustc` on the command line.
|
||||||
|
Use of those two attributes outside of `#![cfg_attr]` continue to be fully supported.
|
||||||
|
- Until now, paths into the sysroot were always prefixed with `/rustc/$hash` in diagnostics, codegen, backtrace, e.g.
|
||||||
|
```
|
||||||
|
thread 'main' panicked at 'hello world', map-panic.rs:2:50
|
||||||
|
stack backtrace:
|
||||||
|
0: std::panicking::begin_panic
|
||||||
|
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:616:12
|
||||||
|
1: map_panic::main::{{closure}}
|
||||||
|
at ./map-panic.rs:2:50
|
||||||
|
2: core::option::Option<T>::map
|
||||||
|
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/option.rs:929:29
|
||||||
|
3: map_panic::main
|
||||||
|
at ./map-panic.rs:2:30
|
||||||
|
4: core::ops::function::FnOnce::call_once
|
||||||
|
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/ops/function.rs:248:5
|
||||||
|
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
|
||||||
|
```
|
||||||
|
[RFC 3127 said](https://rust-lang.github.io/rfcs/3127-trim-paths.html#changing-handling-of-sysroot-path-in-rustc)
|
||||||
|
> We want to change this behaviour such that, when `rust-src` source files can be discovered, the virtual path is discarded and therefore the local path will be embedded, unless there is a `--remap-path-prefix` that causes this local path to be remapped in the usual way.
|
||||||
|
|
||||||
|
[#129687](https://github.com/rust-lang/rust/pull/129687) implements this behaviour, when `rust-src` is present at compile time, `rustc` replaces `/rustc/$hash` with a real path into the local `rust-src` component with best effort.
|
||||||
|
To sanitize this, users must explicitly supply `--remap-path-prefix=<path to rust-src>=foo` or not have the `rust-src` component installed.
|
||||||
|
- The allow-by-default `missing_docs` lint used to disable itself when invoked through `rustc --test`/`cargo test`, resulting in `#[expect(missing_docs)]` emitting false positives due to the expectation being wrongly unfulfilled. This behavior [has now been removed](https://github.com/rust-lang/rust/pull/130025), which allows `#[expect(missing_docs)]` to be fulfilled in all scenarios, but will also report new `missing_docs` diagnostics for publicly reachable `#[cfg(test)]` items, [integration test](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#integration-tests) crate-level documentation, and publicly reachable items in integration tests.
|
||||||
|
- [The `armv8r-none-eabihf` target now uses the Armv8-R required set of floating-point features.](https://github.com/rust-lang/rust/pull/130295)
|
||||||
|
- [Fix a soundness bug where rustc wouldn't detect unconstrained higher-ranked lifetimes in a `dyn Trait`'s associated types that occur due to supertraits.](https://github.com/rust-lang/rust/pull/130367)
|
||||||
|
- [Update the minimum external LLVM version to 18.](https://github.com/rust-lang/rust/pull/130487)
|
||||||
|
- [Remove `aarch64-fuchsia` and `x86_64-fuchsia` target aliases in favor of `aarch64-unknown-fuchsia` and `x86_64-unknown-fuchsia` respectively.](https://github.com/rust-lang/rust/pull/130657)
|
||||||
|
- [The ABI-level exception class of a Rust panic is now encoded with native-endian bytes, so it is legible in hex dumps.](https://github.com/rust-lang/rust/pull/130897)
|
||||||
|
- [Visual Studio 2013 is no longer supported for MSVC targets.](https://github.com/rust-lang/rust/pull/131070)
|
||||||
|
- [The sysroot no longer contains the `std` dynamic library in its top-level `lib/` dir.](https://github.com/rust-lang/rust/pull/131188)
|
||||||
|
|
||||||
|
|
||||||
Version 1.82.0 (2024-10-17)
|
Version 1.82.0 (2024-10-17)
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
@ -125,7 +357,7 @@ These APIs are now stable in const contexts:
|
||||||
- [`std::task::Waker::from_raw`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw)
|
- [`std::task::Waker::from_raw`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw)
|
||||||
- [`std::task::Context::from_waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.from_waker)
|
- [`std::task::Context::from_waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.from_waker)
|
||||||
- [`std::task::Context::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.waker)
|
- [`std::task::Context::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.waker)
|
||||||
- [`$integer::from_str_radix`](https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.from_str_radix)
|
- [`{integer}::from_str_radix`](https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.from_str_radix)
|
||||||
- [`std::num::ParseIntError::kind`](https://doc.rust-lang.org/nightly/std/num/struct.ParseIntError.html#method.kind)
|
- [`std::num::ParseIntError::kind`](https://doc.rust-lang.org/nightly/std/num/struct.ParseIntError.html#method.kind)
|
||||||
|
|
||||||
<a id="1.82.0-Cargo"></a>
|
<a id="1.82.0-Cargo"></a>
|
||||||
|
@ -670,13 +902,6 @@ Cargo
|
||||||
- [Support `target.<triple>.rustdocflags` officially](https://github.com/rust-lang/cargo/pull/13197/)
|
- [Support `target.<triple>.rustdocflags` officially](https://github.com/rust-lang/cargo/pull/13197/)
|
||||||
- [Stabilize global cache data tracking](https://github.com/rust-lang/cargo/pull/13492/)
|
- [Stabilize global cache data tracking](https://github.com/rust-lang/cargo/pull/13492/)
|
||||||
|
|
||||||
<a id="1.78.0-Misc"></a>
|
|
||||||
|
|
||||||
Misc
|
|
||||||
----
|
|
||||||
|
|
||||||
- [rustdoc: add `--test-builder-wrapper` arg to support wrappers such as RUSTC_WRAPPER when building doctests](https://github.com/rust-lang/rust/pull/114651/)
|
|
||||||
|
|
||||||
<a id="1.78.0-Compatibility-Notes"></a>
|
<a id="1.78.0-Compatibility-Notes"></a>
|
||||||
|
|
||||||
Compatibility Notes
|
Compatibility Notes
|
||||||
|
|
|
@ -28,6 +28,7 @@ path = [
|
||||||
"COPYRIGHT",
|
"COPYRIGHT",
|
||||||
"INSTALL.md",
|
"INSTALL.md",
|
||||||
"LICENSE-APACHE",
|
"LICENSE-APACHE",
|
||||||
|
"license-metadata.json",
|
||||||
"LICENSE-MIT",
|
"LICENSE-MIT",
|
||||||
"README.md",
|
"README.md",
|
||||||
"RELEASES.md",
|
"RELEASES.md",
|
||||||
|
@ -63,8 +64,8 @@ SPDX-License-Identifier = "Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT
|
||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = "library/core/src/unicode/unicode_data.rs"
|
path = "library/core/src/unicode/unicode_data.rs"
|
||||||
precedence = "override"
|
precedence = "override"
|
||||||
SPDX-FileCopyrightText = "1991-2022 Unicode, Inc. All rights reserved."
|
SPDX-FileCopyrightText = "1991-2024 Unicode, Inc."
|
||||||
SPDX-License-Identifier = "Unicode-DFS-2016"
|
SPDX-License-Identifier = "Unicode-3.0"
|
||||||
|
|
||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = "library/std/src/sync/mpmc/**"
|
path = "library/std/src/sync/mpmc/**"
|
||||||
|
|
|
@ -31,5 +31,4 @@ jemalloc = ['dep:jemalloc-sys']
|
||||||
llvm = ['rustc_driver_impl/llvm']
|
llvm = ['rustc_driver_impl/llvm']
|
||||||
max_level_info = ['rustc_driver_impl/max_level_info']
|
max_level_info = ['rustc_driver_impl/max_level_info']
|
||||||
rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
|
rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
|
||||||
rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler']
|
|
||||||
# tidy-alphabetical-end
|
# tidy-alphabetical-end
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`.
|
// We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`.
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
|
// Several crates are depended upon but unused so that they are present in the sysroot
|
||||||
|
#![expect(unused_crate_dependencies)]
|
||||||
|
|
||||||
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
||||||
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
||||||
|
|
|
@ -209,6 +209,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
|
||||||
|
where
|
||||||
|
Ty: TyAbiInterface<'a, C>,
|
||||||
|
C: HasDataLayout,
|
||||||
|
{
|
||||||
|
match self.backend_repr {
|
||||||
|
BackendRepr::Vector { .. } => self.size == expected_size,
|
||||||
|
BackendRepr::Memory { .. } => {
|
||||||
|
if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
|
||||||
|
self.field(cx, 0).is_single_vector_element(cx, expected_size)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_adt<C>(self) -> bool
|
pub fn is_adt<C>(self) -> bool
|
||||||
where
|
where
|
||||||
Ty: TyAbiInterface<'a, C>,
|
Ty: TyAbiInterface<'a, C>,
|
||||||
|
|
|
@ -638,7 +638,7 @@ impl AddAssign for Size {
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
impl Step for Size {
|
impl Step for Size {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
|
||||||
u64::steps_between(&start.bytes(), &end.bytes())
|
u64::steps_between(&start.bytes(), &end.bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1743,15 +1743,23 @@ pub enum PointerKind {
|
||||||
Box { unpin: bool, global: bool },
|
Box { unpin: bool, global: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note that this information is advisory only, and backends are free to ignore it.
|
/// Encodes extra information we have about a pointer.
|
||||||
/// It can only be used to encode potential optimizations, but no critical information.
|
/// Note that this information is advisory only, and backends are free to ignore it:
|
||||||
|
/// if the information is wrong, that can cause UB, but if the information is absent,
|
||||||
|
/// that must always be okay.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct PointeeInfo {
|
pub struct PointeeInfo {
|
||||||
pub size: Size,
|
|
||||||
pub align: Align,
|
|
||||||
/// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to
|
/// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to
|
||||||
/// be reliable.
|
/// be reliable.
|
||||||
pub safe: Option<PointerKind>,
|
pub safe: Option<PointerKind>,
|
||||||
|
/// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes.
|
||||||
|
/// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration
|
||||||
|
/// of this function call", i.e. it is UB for the memory that this pointer points to to be freed
|
||||||
|
/// while this function is still running.
|
||||||
|
/// The size can be zero if the pointer is not dereferenceable.
|
||||||
|
pub size: Size,
|
||||||
|
/// If `safe` is `Some`, then the pointer is aligned as indicated.
|
||||||
|
pub align: Align,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
|
|
|
@ -39,7 +39,9 @@ pub use crate::format::*;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::token::{self, CommentKind, Delimiter};
|
use crate::token::{self, CommentKind, Delimiter};
|
||||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||||
pub use crate::util::parser::ExprPrecedence;
|
use crate::util::parser::{
|
||||||
|
AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_RANGE, PREC_UNAMBIGUOUS,
|
||||||
|
};
|
||||||
|
|
||||||
/// A "Label" is an identifier of some point in sources,
|
/// A "Label" is an identifier of some point in sources,
|
||||||
/// e.g. in the following code:
|
/// e.g. in the following code:
|
||||||
|
@ -414,6 +416,12 @@ pub struct WhereClause {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WhereClause {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
!self.has_where_token && self.predicates.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for WhereClause {
|
impl Default for WhereClause {
|
||||||
fn default() -> WhereClause {
|
fn default() -> WhereClause {
|
||||||
WhereClause { has_where_token: false, predicates: ThinVec::new(), span: DUMMY_SP }
|
WhereClause { has_where_token: false, predicates: ThinVec::new(), span: DUMMY_SP }
|
||||||
|
@ -422,7 +430,15 @@ impl Default for WhereClause {
|
||||||
|
|
||||||
/// A single predicate in a where-clause.
|
/// A single predicate in a where-clause.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
pub enum WherePredicate {
|
pub struct WherePredicate {
|
||||||
|
pub kind: WherePredicateKind,
|
||||||
|
pub id: NodeId,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Predicate kind in where-clause.
|
||||||
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
|
pub enum WherePredicateKind {
|
||||||
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||||
BoundPredicate(WhereBoundPredicate),
|
BoundPredicate(WhereBoundPredicate),
|
||||||
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
|
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
|
||||||
|
@ -431,22 +447,11 @@ pub enum WherePredicate {
|
||||||
EqPredicate(WhereEqPredicate),
|
EqPredicate(WhereEqPredicate),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WherePredicate {
|
|
||||||
pub fn span(&self) -> Span {
|
|
||||||
match self {
|
|
||||||
WherePredicate::BoundPredicate(p) => p.span,
|
|
||||||
WherePredicate::RegionPredicate(p) => p.span,
|
|
||||||
WherePredicate::EqPredicate(p) => p.span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type bound.
|
/// A type bound.
|
||||||
///
|
///
|
||||||
/// E.g., `for<'c> Foo: Send + Clone + 'c`.
|
/// E.g., `for<'c> Foo: Send + Clone + 'c`.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
pub struct WhereBoundPredicate {
|
pub struct WhereBoundPredicate {
|
||||||
pub span: Span,
|
|
||||||
/// Any generics from a `for` binding.
|
/// Any generics from a `for` binding.
|
||||||
pub bound_generic_params: ThinVec<GenericParam>,
|
pub bound_generic_params: ThinVec<GenericParam>,
|
||||||
/// The type being bounded.
|
/// The type being bounded.
|
||||||
|
@ -460,7 +465,6 @@ pub struct WhereBoundPredicate {
|
||||||
/// E.g., `'a: 'b + 'c`.
|
/// E.g., `'a: 'b + 'c`.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
pub struct WhereRegionPredicate {
|
pub struct WhereRegionPredicate {
|
||||||
pub span: Span,
|
|
||||||
pub lifetime: Lifetime,
|
pub lifetime: Lifetime,
|
||||||
pub bounds: GenericBounds,
|
pub bounds: GenericBounds,
|
||||||
}
|
}
|
||||||
|
@ -470,7 +474,6 @@ pub struct WhereRegionPredicate {
|
||||||
/// E.g., `T = int`.
|
/// E.g., `T = int`.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
pub struct WhereEqPredicate {
|
pub struct WhereEqPredicate {
|
||||||
pub span: Span,
|
|
||||||
pub lhs_ty: P<Ty>,
|
pub lhs_ty: P<Ty>,
|
||||||
pub rhs_ty: P<Ty>,
|
pub rhs_ty: P<Ty>,
|
||||||
}
|
}
|
||||||
|
@ -1188,7 +1191,7 @@ impl Expr {
|
||||||
///
|
///
|
||||||
/// Does not ensure that the path resolves to a const param, the caller should check this.
|
/// Does not ensure that the path resolves to a const param, the caller should check this.
|
||||||
pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool {
|
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 };
|
let this = if strip_identity_block { self.maybe_unwrap_block() } else { self };
|
||||||
|
|
||||||
if let ExprKind::Path(None, path) = &this.kind
|
if let ExprKind::Path(None, path) = &this.kind
|
||||||
&& path.is_potential_trivial_const_arg()
|
&& path.is_potential_trivial_const_arg()
|
||||||
|
@ -1200,14 +1203,41 @@ impl Expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an expression with (when possible) *one* outter brace removed
|
/// Returns an expression with (when possible) *one* outter brace removed
|
||||||
pub fn maybe_unwrap_block(&self) -> (bool, &Expr) {
|
pub fn maybe_unwrap_block(&self) -> &Expr {
|
||||||
if let ExprKind::Block(block, None) = &self.kind
|
if let ExprKind::Block(block, None) = &self.kind
|
||||||
&& let [stmt] = block.stmts.as_slice()
|
&& let [stmt] = block.stmts.as_slice()
|
||||||
&& let StmtKind::Expr(expr) = &stmt.kind
|
&& let StmtKind::Expr(expr) = &stmt.kind
|
||||||
{
|
{
|
||||||
(true, expr)
|
expr
|
||||||
} else {
|
} else {
|
||||||
(false, self)
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether this expression is a macro call optionally wrapped in braces . If
|
||||||
|
/// `already_stripped_block` is set then we do not attempt to peel off a layer of braces.
|
||||||
|
///
|
||||||
|
/// Returns the [`NodeId`] of the macro call and whether a layer of braces has been peeled
|
||||||
|
/// either before, or part of, this function.
|
||||||
|
pub fn optionally_braced_mac_call(
|
||||||
|
&self,
|
||||||
|
already_stripped_block: bool,
|
||||||
|
) -> Option<(bool, NodeId)> {
|
||||||
|
match &self.kind {
|
||||||
|
ExprKind::Block(block, None)
|
||||||
|
if let [stmt] = &*block.stmts
|
||||||
|
&& !already_stripped_block =>
|
||||||
|
{
|
||||||
|
match &stmt.kind {
|
||||||
|
StmtKind::MacCall(_) => Some((true, stmt.id)),
|
||||||
|
StmtKind::Expr(expr) if let ExprKind::MacCall(_) = &expr.kind => {
|
||||||
|
Some((true, expr.id))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExprKind::MacCall(_) => Some((already_stripped_block, self.id)),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1286,53 +1316,71 @@ impl Expr {
|
||||||
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
|
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn precedence(&self) -> ExprPrecedence {
|
pub fn precedence(&self) -> i8 {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ExprKind::Array(_) => ExprPrecedence::Array,
|
ExprKind::Closure(..) => PREC_CLOSURE,
|
||||||
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
|
|
||||||
ExprKind::Call(..) => ExprPrecedence::Call,
|
ExprKind::Break(..)
|
||||||
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
|
| ExprKind::Continue(..)
|
||||||
ExprKind::Tup(_) => ExprPrecedence::Tup,
|
| ExprKind::Ret(..)
|
||||||
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
|
| ExprKind::Yield(..)
|
||||||
ExprKind::Unary(..) => ExprPrecedence::Unary,
|
| ExprKind::Yeet(..)
|
||||||
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit,
|
| ExprKind::Become(..) => PREC_JUMP,
|
||||||
ExprKind::Cast(..) => ExprPrecedence::Cast,
|
|
||||||
ExprKind::Let(..) => ExprPrecedence::Let,
|
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||||
ExprKind::If(..) => ExprPrecedence::If,
|
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||||
ExprKind::While(..) => ExprPrecedence::While,
|
// ensures that `pprust` will add parentheses in the right places to get the desired
|
||||||
ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
|
// parse.
|
||||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
ExprKind::Range(..) => PREC_RANGE,
|
||||||
ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match,
|
|
||||||
ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch,
|
// Binop-like expr kinds, handled by `AssocOp`.
|
||||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
|
||||||
ExprKind::Block(..) => ExprPrecedence::Block,
|
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
|
||||||
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
|
|
||||||
ExprKind::Gen(..) => ExprPrecedence::Gen,
|
ExprKind::Assign(..) |
|
||||||
ExprKind::Await(..) => ExprPrecedence::Await,
|
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
|
||||||
ExprKind::Assign(..) => ExprPrecedence::Assign,
|
|
||||||
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
|
// Unary, prefix
|
||||||
ExprKind::Field(..) => ExprPrecedence::Field,
|
ExprKind::AddrOf(..)
|
||||||
ExprKind::Index(..) => ExprPrecedence::Index,
|
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
|
||||||
ExprKind::Range(..) => ExprPrecedence::Range,
|
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
|
||||||
ExprKind::Underscore => ExprPrecedence::Path,
|
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
|
||||||
ExprKind::Path(..) => ExprPrecedence::Path,
|
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||||
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
|
| ExprKind::Let(..)
|
||||||
ExprKind::Break(..) => ExprPrecedence::Break,
|
| ExprKind::Unary(..) => PREC_PREFIX,
|
||||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
|
||||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
// Never need parens
|
||||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
ExprKind::Array(_)
|
||||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
| ExprKind::Await(..)
|
||||||
ExprKind::Paren(..) => ExprPrecedence::Paren,
|
| ExprKind::Block(..)
|
||||||
ExprKind::Try(..) => ExprPrecedence::Try,
|
| ExprKind::Call(..)
|
||||||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
| ExprKind::ConstBlock(_)
|
||||||
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
|
| ExprKind::Field(..)
|
||||||
ExprKind::Become(..) => ExprPrecedence::Become,
|
| ExprKind::ForLoop { .. }
|
||||||
ExprKind::InlineAsm(..)
|
|
||||||
| ExprKind::Type(..)
|
|
||||||
| ExprKind::OffsetOf(..)
|
|
||||||
| ExprKind::FormatArgs(..)
|
| ExprKind::FormatArgs(..)
|
||||||
| ExprKind::MacCall(..) => ExprPrecedence::Mac,
|
| ExprKind::Gen(..)
|
||||||
ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
|
| ExprKind::If(..)
|
||||||
|
| ExprKind::IncludedBytes(..)
|
||||||
|
| ExprKind::Index(..)
|
||||||
|
| ExprKind::InlineAsm(..)
|
||||||
|
| ExprKind::Lit(_)
|
||||||
|
| ExprKind::Loop(..)
|
||||||
|
| ExprKind::MacCall(..)
|
||||||
|
| ExprKind::Match(..)
|
||||||
|
| ExprKind::MethodCall(..)
|
||||||
|
| ExprKind::OffsetOf(..)
|
||||||
|
| ExprKind::Paren(..)
|
||||||
|
| ExprKind::Path(..)
|
||||||
|
| ExprKind::Repeat(..)
|
||||||
|
| ExprKind::Struct(..)
|
||||||
|
| ExprKind::Try(..)
|
||||||
|
| ExprKind::TryBlock(..)
|
||||||
|
| ExprKind::Tup(_)
|
||||||
|
| ExprKind::Type(..)
|
||||||
|
| ExprKind::Underscore
|
||||||
|
| ExprKind::While(..)
|
||||||
|
| ExprKind::Err(_)
|
||||||
|
| ExprKind::Dummy => PREC_UNAMBIGUOUS,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3030,6 +3078,7 @@ pub struct FieldDef {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub vis: Visibility,
|
pub vis: Visibility,
|
||||||
|
pub safety: Safety,
|
||||||
pub ident: Option<Ident>,
|
pub ident: Option<Ident>,
|
||||||
|
|
||||||
pub ty: P<Ty>,
|
pub ty: P<Ty>,
|
||||||
|
|
|
@ -136,6 +136,13 @@ impl Attribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a list of meta items if the attribute is delimited with parenthesis:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// #[attr(a, b = "c")] // Returns `Some()`.
|
||||||
|
/// #[attr = ""] // Returns `None`.
|
||||||
|
/// #[attr] // Returns `None`.
|
||||||
|
/// ```
|
||||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
AttrKind::Normal(normal) => normal.item.meta_item_list(),
|
AttrKind::Normal(normal) => normal.item.meta_item_list(),
|
||||||
|
@ -143,6 +150,21 @@ impl Attribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the string value in:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// #[attribute = "value"]
|
||||||
|
/// ^^^^^^^
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// It returns `None` in any other cases, including doc comments if they
|
||||||
|
/// are not under the form `#[doc = "..."]`.
|
||||||
|
///
|
||||||
|
/// It also returns `None` for:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// #[attr("value")]
|
||||||
|
/// ```
|
||||||
pub fn value_str(&self) -> Option<Symbol> {
|
pub fn value_str(&self) -> Option<Symbol> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
AttrKind::Normal(normal) => normal.item.value_str(),
|
AttrKind::Normal(normal) => normal.item.value_str(),
|
||||||
|
@ -232,6 +254,18 @@ impl AttrItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the string value in:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// #[attribute = "value"]
|
||||||
|
/// ^^^^^^^
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// It returns `None` in any other cases like:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// #[attr("value")]
|
||||||
|
/// ```
|
||||||
fn value_str(&self) -> Option<Symbol> {
|
fn value_str(&self) -> Option<Symbol> {
|
||||||
match &self.args {
|
match &self.args {
|
||||||
AttrArgs::Eq(_, args) => args.value_str(),
|
AttrArgs::Eq(_, args) => args.value_str(),
|
||||||
|
@ -315,6 +349,18 @@ impl MetaItem {
|
||||||
Some(self.name_value_literal()?.span)
|
Some(self.name_value_literal()?.span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the string value in:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// #[attribute = "value"]
|
||||||
|
/// ^^^^^^^
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// It returns `None` in any other cases like:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// #[attr("value")]
|
||||||
|
/// ```
|
||||||
pub fn value_str(&self) -> Option<Symbol> {
|
pub fn value_str(&self) -> Option<Symbol> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
MetaItemKind::NameValue(v) => v.kind.str(),
|
MetaItemKind::NameValue(v) => v.kind.str(),
|
||||||
|
@ -411,7 +457,7 @@ impl MetaItemKind {
|
||||||
tokens: &mut impl Iterator<Item = &'a TokenTree>,
|
tokens: &mut impl Iterator<Item = &'a TokenTree>,
|
||||||
) -> Option<MetaItemKind> {
|
) -> Option<MetaItemKind> {
|
||||||
match tokens.next() {
|
match tokens.next() {
|
||||||
Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
|
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
|
||||||
MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
|
MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
|
||||||
}
|
}
|
||||||
Some(TokenTree::Token(token, _)) => {
|
Some(TokenTree::Token(token, _)) => {
|
||||||
|
@ -559,7 +605,7 @@ impl MetaItemInner {
|
||||||
tokens.next();
|
tokens.next();
|
||||||
return Some(MetaItemInner::Lit(lit));
|
return Some(MetaItemInner::Lit(lit));
|
||||||
}
|
}
|
||||||
Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
|
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
|
||||||
tokens.next();
|
tokens.next();
|
||||||
return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable());
|
return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable());
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use crate::ast::*;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::token::{self, Token};
|
use crate::token::{self, Token};
|
||||||
use crate::tokenstream::*;
|
use crate::tokenstream::*;
|
||||||
use crate::visit::{AssocCtxt, BoundKind};
|
use crate::visit::{AssocCtxt, BoundKind, FnCtxt};
|
||||||
|
|
||||||
pub trait ExpectOne<A: Array> {
|
pub trait ExpectOne<A: Array> {
|
||||||
fn expect_one(self, err: &'static str) -> A::Item;
|
fn expect_one(self, err: &'static str) -> A::Item;
|
||||||
|
@ -37,7 +37,16 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WalkItemKind {
|
pub trait WalkItemKind {
|
||||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor);
|
type Ctxt;
|
||||||
|
fn walk(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
ctxt: Self::Ctxt,
|
||||||
|
visitor: &mut impl MutVisitor,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MutVisitor: Sized {
|
pub trait MutVisitor: Sized {
|
||||||
|
@ -95,8 +104,16 @@ pub trait MutVisitor: Sized {
|
||||||
walk_use_tree(self, use_tree);
|
walk_use_tree(self, use_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_foreign_item(&mut self, ni: &mut P<ForeignItem>) {
|
||||||
|
walk_item(self, ni);
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
|
fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
|
||||||
walk_flat_map_item(self, ni)
|
walk_flat_map_foreign_item(self, ni)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_item(&mut self, i: &mut P<Item>) {
|
||||||
|
walk_item(self, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
|
fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
|
||||||
|
@ -107,16 +124,24 @@ pub trait MutVisitor: Sized {
|
||||||
walk_fn_header(self, header);
|
walk_fn_header(self, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_field_def(&mut self, fd: &mut FieldDef) {
|
||||||
|
walk_field_def(self, fd);
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> {
|
fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> {
|
||||||
walk_flat_map_field_def(self, fd)
|
walk_flat_map_field_def(self, fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_assoc_item(&mut self, i: &mut P<AssocItem>, ctxt: AssocCtxt) {
|
||||||
|
walk_assoc_item(self, i, ctxt)
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_assoc_item(
|
fn flat_map_assoc_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
i: P<AssocItem>,
|
i: P<AssocItem>,
|
||||||
_ctxt: AssocCtxt,
|
ctxt: AssocCtxt,
|
||||||
) -> SmallVec<[P<AssocItem>; 1]> {
|
) -> SmallVec<[P<AssocItem>; 1]> {
|
||||||
walk_flat_map_item(self, i)
|
walk_flat_map_assoc_item(self, i, ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
|
fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
|
||||||
|
@ -144,6 +169,10 @@ pub trait MutVisitor: Sized {
|
||||||
walk_flat_map_stmt(self, s)
|
walk_flat_map_stmt(self, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_arm(&mut self, arm: &mut Arm) {
|
||||||
|
walk_arm(self, arm);
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
|
fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
|
||||||
walk_flat_map_arm(self, arm)
|
walk_flat_map_arm(self, arm)
|
||||||
}
|
}
|
||||||
|
@ -190,6 +219,10 @@ pub trait MutVisitor: Sized {
|
||||||
walk_foreign_mod(self, nm);
|
walk_foreign_mod(self, nm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_variant(&mut self, v: &mut Variant) {
|
||||||
|
walk_variant(self, v);
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
|
fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
|
||||||
walk_flat_map_variant(self, v)
|
walk_flat_map_variant(self, v)
|
||||||
}
|
}
|
||||||
|
@ -242,6 +275,10 @@ pub trait MutVisitor: Sized {
|
||||||
walk_attribute(self, at);
|
walk_attribute(self, at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_param(&mut self, param: &mut Param) {
|
||||||
|
walk_param(self, param);
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
|
fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
|
||||||
walk_flat_map_param(self, param)
|
walk_flat_map_param(self, param)
|
||||||
}
|
}
|
||||||
|
@ -262,6 +299,10 @@ pub trait MutVisitor: Sized {
|
||||||
walk_variant_data(self, vdata);
|
walk_variant_data(self, vdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_generic_param(&mut self, param: &mut GenericParam) {
|
||||||
|
walk_generic_param(self, param)
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
|
fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
|
||||||
walk_flat_map_generic_param(self, param)
|
walk_flat_map_generic_param(self, param)
|
||||||
}
|
}
|
||||||
|
@ -278,6 +319,10 @@ pub trait MutVisitor: Sized {
|
||||||
walk_mt(self, mt);
|
walk_mt(self, mt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_expr_field(&mut self, f: &mut ExprField) {
|
||||||
|
walk_expr_field(self, f);
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> {
|
fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> {
|
||||||
walk_flat_map_expr_field(self, f)
|
walk_flat_map_expr_field(self, f)
|
||||||
}
|
}
|
||||||
|
@ -287,7 +332,11 @@ pub trait MutVisitor: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) {
|
fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) {
|
||||||
walk_where_predicate(self, where_predicate);
|
walk_where_predicate(self, where_predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_where_predicate_kind(&mut self, kind: &mut WherePredicateKind) {
|
||||||
|
walk_where_predicate_kind(self, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_vis(&mut self, vis: &mut Visibility) {
|
fn visit_vis(&mut self, vis: &mut Visibility) {
|
||||||
|
@ -302,6 +351,10 @@ pub trait MutVisitor: Sized {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_pat_field(&mut self, fp: &mut PatField) {
|
||||||
|
walk_pat_field(self, fp)
|
||||||
|
}
|
||||||
|
|
||||||
fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
|
fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
|
||||||
walk_flat_map_pat_field(self, fp)
|
walk_flat_map_pat_field(self, fp)
|
||||||
}
|
}
|
||||||
|
@ -321,6 +374,10 @@ pub trait MutVisitor: Sized {
|
||||||
fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) {
|
fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) {
|
||||||
walk_capture_by(self, capture_by)
|
walk_capture_by(self, capture_by)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_fn_ret_ty(&mut self, fn_ret_ty: &mut FnRetTy) {
|
||||||
|
walk_fn_ret_ty(self, fn_ret_ty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
|
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
|
||||||
|
@ -416,16 +473,20 @@ pub fn visit_delim_span<T: MutVisitor>(vis: &mut T, DelimSpan { open, close }: &
|
||||||
vis.visit_span(close);
|
vis.visit_span(close);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_flat_map_pat_field<T: MutVisitor>(
|
pub fn walk_pat_field<T: MutVisitor>(vis: &mut T, fp: &mut PatField) {
|
||||||
vis: &mut T,
|
let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = fp;
|
||||||
mut fp: PatField,
|
|
||||||
) -> SmallVec<[PatField; 1]> {
|
|
||||||
let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp;
|
|
||||||
vis.visit_id(id);
|
vis.visit_id(id);
|
||||||
visit_attrs(vis, attrs);
|
visit_attrs(vis, attrs);
|
||||||
vis.visit_ident(ident);
|
vis.visit_ident(ident);
|
||||||
vis.visit_pat(pat);
|
vis.visit_pat(pat);
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_pat_field<T: MutVisitor>(
|
||||||
|
vis: &mut T,
|
||||||
|
mut fp: PatField,
|
||||||
|
) -> SmallVec<[PatField; 1]> {
|
||||||
|
vis.visit_pat_field(&mut fp);
|
||||||
smallvec![fp]
|
smallvec![fp]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,14 +507,18 @@ fn walk_use_tree<T: MutVisitor>(vis: &mut T, use_tree: &mut UseTree) {
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
|
pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) {
|
||||||
let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
|
let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm;
|
||||||
vis.visit_id(id);
|
vis.visit_id(id);
|
||||||
visit_attrs(vis, attrs);
|
visit_attrs(vis, attrs);
|
||||||
vis.visit_pat(pat);
|
vis.visit_pat(pat);
|
||||||
visit_opt(guard, |guard| vis.visit_expr(guard));
|
visit_opt(guard, |guard| vis.visit_expr(guard));
|
||||||
visit_opt(body, |body| vis.visit_expr(body));
|
visit_opt(body, |body| vis.visit_expr(body));
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
|
||||||
|
vis.visit_arm(&mut arm);
|
||||||
smallvec![arm]
|
smallvec![arm]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,11 +595,8 @@ fn walk_foreign_mod<T: MutVisitor>(vis: &mut T, foreign_mod: &mut ForeignMod) {
|
||||||
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
|
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_flat_map_variant<T: MutVisitor>(
|
pub fn walk_variant<T: MutVisitor>(visitor: &mut T, variant: &mut Variant) {
|
||||||
visitor: &mut T,
|
let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant;
|
||||||
mut variant: Variant,
|
|
||||||
) -> SmallVec<[Variant; 1]> {
|
|
||||||
let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
|
|
||||||
visitor.visit_id(id);
|
visitor.visit_id(id);
|
||||||
visit_attrs(visitor, attrs);
|
visit_attrs(visitor, attrs);
|
||||||
visitor.visit_vis(vis);
|
visitor.visit_vis(vis);
|
||||||
|
@ -542,6 +604,13 @@ pub fn walk_flat_map_variant<T: MutVisitor>(
|
||||||
visitor.visit_variant_data(data);
|
visitor.visit_variant_data(data);
|
||||||
visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
|
visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
|
||||||
visitor.visit_span(span);
|
visitor.visit_span(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_variant<T: MutVisitor>(
|
||||||
|
vis: &mut T,
|
||||||
|
mut variant: Variant,
|
||||||
|
) -> SmallVec<[Variant; 1]> {
|
||||||
|
vis.visit_variant(&mut variant);
|
||||||
smallvec![variant]
|
smallvec![variant]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,7 +669,7 @@ fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut An
|
||||||
fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
|
fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
|
||||||
let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
|
let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
|
||||||
visit_thin_vec(inputs, |input| vis.visit_ty(input));
|
visit_thin_vec(inputs, |input| vis.visit_ty(input));
|
||||||
walk_fn_ret_ty(vis, output);
|
vis.visit_fn_ret_ty(output);
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
vis.visit_span(inputs_span);
|
vis.visit_span(inputs_span);
|
||||||
}
|
}
|
||||||
|
@ -672,13 +741,17 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) {
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
|
pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) {
|
||||||
let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param;
|
let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param;
|
||||||
vis.visit_id(id);
|
vis.visit_id(id);
|
||||||
visit_attrs(vis, attrs);
|
visit_attrs(vis, attrs);
|
||||||
vis.visit_pat(pat);
|
vis.visit_pat(pat);
|
||||||
vis.visit_ty(ty);
|
vis.visit_ty(ty);
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
|
||||||
|
vis.visit_param(&mut param);
|
||||||
smallvec![param]
|
smallvec![param]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,7 +953,7 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin
|
||||||
|
|
||||||
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||||
match kind {
|
match kind {
|
||||||
FnKind::Fn(FnSig { header, decl, span }, generics, body) => {
|
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => {
|
||||||
// Identifier and visibility are visited as a part of the item.
|
// Identifier and visibility are visited as a part of the item.
|
||||||
vis.visit_fn_header(header);
|
vis.visit_fn_header(header);
|
||||||
vis.visit_generics(generics);
|
vis.visit_generics(generics);
|
||||||
|
@ -890,8 +963,9 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||||
}
|
}
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
FnKind::Closure(binder, decl, body) => {
|
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
||||||
vis.visit_closure_binder(binder);
|
vis.visit_closure_binder(binder);
|
||||||
|
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
||||||
vis.visit_fn_decl(decl);
|
vis.visit_fn_decl(decl);
|
||||||
vis.visit_expr(body);
|
vis.visit_expr(body);
|
||||||
}
|
}
|
||||||
|
@ -901,7 +975,7 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||||
fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
|
fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
|
||||||
let FnDecl { inputs, output } = decl.deref_mut();
|
let FnDecl { inputs, output } = decl.deref_mut();
|
||||||
inputs.flat_map_in_place(|param| vis.flat_map_param(param));
|
inputs.flat_map_in_place(|param| vis.flat_map_param(param));
|
||||||
walk_fn_ret_ty(vis, output);
|
vis.visit_fn_ret_ty(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
|
fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
|
||||||
|
@ -936,11 +1010,8 @@ fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCaptu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_flat_map_generic_param<T: MutVisitor>(
|
pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) {
|
||||||
vis: &mut T,
|
let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param;
|
||||||
mut param: GenericParam,
|
|
||||||
) -> SmallVec<[GenericParam; 1]> {
|
|
||||||
let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
|
|
||||||
vis.visit_id(id);
|
vis.visit_id(id);
|
||||||
visit_attrs(vis, attrs);
|
visit_attrs(vis, attrs);
|
||||||
vis.visit_ident(ident);
|
vis.visit_ident(ident);
|
||||||
|
@ -958,6 +1029,13 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>(
|
||||||
if let Some(colon_span) = colon_span {
|
if let Some(colon_span) = colon_span {
|
||||||
vis.visit_span(colon_span);
|
vis.visit_span(colon_span);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_generic_param<T: MutVisitor>(
|
||||||
|
vis: &mut T,
|
||||||
|
mut param: GenericParam,
|
||||||
|
) -> SmallVec<[GenericParam; 1]> {
|
||||||
|
vis.visit_generic_param(&mut param);
|
||||||
smallvec![param]
|
smallvec![param]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -991,26 +1069,30 @@ fn walk_where_clause<T: MutVisitor>(vis: &mut T, wc: &mut WhereClause) {
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_where_predicate<T: MutVisitor>(vis: &mut T, pred: &mut WherePredicate) {
|
pub fn walk_where_predicate<T: MutVisitor>(vis: &mut T, pred: &mut WherePredicate) {
|
||||||
match pred {
|
let WherePredicate { kind, id, span } = pred;
|
||||||
WherePredicate::BoundPredicate(bp) => {
|
vis.visit_id(id);
|
||||||
let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp;
|
vis.visit_where_predicate_kind(kind);
|
||||||
|
vis.visit_span(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_where_predicate_kind<T: MutVisitor>(vis: &mut T, kind: &mut WherePredicateKind) {
|
||||||
|
match kind {
|
||||||
|
WherePredicateKind::BoundPredicate(bp) => {
|
||||||
|
let WhereBoundPredicate { bound_generic_params, bounded_ty, bounds } = bp;
|
||||||
bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||||
vis.visit_ty(bounded_ty);
|
vis.visit_ty(bounded_ty);
|
||||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||||
vis.visit_span(span);
|
|
||||||
}
|
}
|
||||||
WherePredicate::RegionPredicate(rp) => {
|
WherePredicateKind::RegionPredicate(rp) => {
|
||||||
let WhereRegionPredicate { span, lifetime, bounds } = rp;
|
let WhereRegionPredicate { lifetime, bounds } = rp;
|
||||||
vis.visit_lifetime(lifetime);
|
vis.visit_lifetime(lifetime);
|
||||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||||
vis.visit_span(span);
|
|
||||||
}
|
}
|
||||||
WherePredicate::EqPredicate(ep) => {
|
WherePredicateKind::EqPredicate(ep) => {
|
||||||
let WhereEqPredicate { span, lhs_ty, rhs_ty } = ep;
|
let WhereEqPredicate { lhs_ty, rhs_ty } = ep;
|
||||||
vis.visit_ty(lhs_ty);
|
vis.visit_ty(lhs_ty);
|
||||||
vis.visit_ty(rhs_ty);
|
vis.visit_ty(rhs_ty);
|
||||||
vis.visit_span(span);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1040,30 +1122,39 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_flat_map_field_def<T: MutVisitor>(
|
pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
|
||||||
visitor: &mut T,
|
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety } = fd;
|
||||||
mut fd: FieldDef,
|
|
||||||
) -> SmallVec<[FieldDef; 1]> {
|
|
||||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd;
|
|
||||||
visitor.visit_id(id);
|
visitor.visit_id(id);
|
||||||
visit_attrs(visitor, attrs);
|
visit_attrs(visitor, attrs);
|
||||||
visitor.visit_vis(vis);
|
visitor.visit_vis(vis);
|
||||||
|
visit_safety(visitor, safety);
|
||||||
visit_opt(ident, |ident| visitor.visit_ident(ident));
|
visit_opt(ident, |ident| visitor.visit_ident(ident));
|
||||||
visitor.visit_ty(ty);
|
visitor.visit_ty(ty);
|
||||||
visitor.visit_span(span);
|
visitor.visit_span(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_field_def<T: MutVisitor>(
|
||||||
|
vis: &mut T,
|
||||||
|
mut fd: FieldDef,
|
||||||
|
) -> SmallVec<[FieldDef; 1]> {
|
||||||
|
vis.visit_field_def(&mut fd);
|
||||||
smallvec![fd]
|
smallvec![fd]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_expr_field<T: MutVisitor>(vis: &mut T, f: &mut ExprField) {
|
||||||
|
let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = f;
|
||||||
|
vis.visit_id(id);
|
||||||
|
visit_attrs(vis, attrs);
|
||||||
|
vis.visit_ident(ident);
|
||||||
|
vis.visit_expr(expr);
|
||||||
|
vis.visit_span(span);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_flat_map_expr_field<T: MutVisitor>(
|
pub fn walk_flat_map_expr_field<T: MutVisitor>(
|
||||||
vis: &mut T,
|
vis: &mut T,
|
||||||
mut f: ExprField,
|
mut f: ExprField,
|
||||||
) -> SmallVec<[ExprField; 1]> {
|
) -> SmallVec<[ExprField; 1]> {
|
||||||
let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f;
|
vis.visit_expr_field(&mut f);
|
||||||
vis.visit_id(id);
|
|
||||||
visit_attrs(vis, attrs);
|
|
||||||
vis.visit_ident(ident);
|
|
||||||
vis.visit_expr(expr);
|
|
||||||
vis.visit_span(span);
|
|
||||||
smallvec![f]
|
smallvec![f]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,17 +1170,29 @@ pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_item_kind(
|
pub fn walk_item_kind<K: WalkItemKind>(
|
||||||
kind: &mut impl WalkItemKind,
|
kind: &mut K,
|
||||||
span: Span,
|
span: Span,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
ctxt: K::Ctxt,
|
||||||
vis: &mut impl MutVisitor,
|
vis: &mut impl MutVisitor,
|
||||||
) {
|
) {
|
||||||
kind.walk(span, id, vis)
|
kind.walk(span, id, ident, visibility, ctxt, vis)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for ItemKind {
|
impl WalkItemKind for ItemKind {
|
||||||
fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) {
|
type Ctxt = ();
|
||||||
|
fn walk(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
_ctxt: Self::Ctxt,
|
||||||
|
vis: &mut impl MutVisitor,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
ItemKind::ExternCrate(_orig_name) => {}
|
ItemKind::ExternCrate(_orig_name) => {}
|
||||||
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
|
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
|
||||||
|
@ -1102,7 +1205,11 @@ impl WalkItemKind for ItemKind {
|
||||||
}
|
}
|
||||||
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||||
visit_defaultness(vis, defaultness);
|
visit_defaultness(vis, defaultness);
|
||||||
vis.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
vis.visit_fn(
|
||||||
|
FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body),
|
||||||
|
span,
|
||||||
|
id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ItemKind::Mod(safety, mod_kind) => {
|
ItemKind::Mod(safety, mod_kind) => {
|
||||||
visit_safety(vis, safety);
|
visit_safety(vis, safety);
|
||||||
|
@ -1201,14 +1308,27 @@ impl WalkItemKind for ItemKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for AssocItemKind {
|
impl WalkItemKind for AssocItemKind {
|
||||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
|
type Ctxt = AssocCtxt;
|
||||||
|
fn walk(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
ctxt: Self::Ctxt,
|
||||||
|
visitor: &mut impl MutVisitor,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
AssocItemKind::Const(item) => {
|
AssocItemKind::Const(item) => {
|
||||||
visit_const_item(item, visitor);
|
visit_const_item(item, visitor);
|
||||||
}
|
}
|
||||||
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||||
visit_defaultness(visitor, defaultness);
|
visit_defaultness(visitor, defaultness);
|
||||||
visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
visitor.visit_fn(
|
||||||
|
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body),
|
||||||
|
span,
|
||||||
|
id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
AssocItemKind::Type(box TyAlias {
|
AssocItemKind::Type(box TyAlias {
|
||||||
defaultness,
|
defaultness,
|
||||||
|
@ -1288,24 +1408,62 @@ pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
|
||||||
vis.visit_span(inject_use_span);
|
vis.visit_span(inject_use_span);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutates one item, returning the item again.
|
pub fn walk_item(visitor: &mut impl MutVisitor, item: &mut P<Item<impl WalkItemKind<Ctxt = ()>>>) {
|
||||||
pub fn walk_flat_map_item<K: WalkItemKind>(
|
walk_item_ctxt(visitor, item, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_assoc_item(visitor: &mut impl MutVisitor, item: &mut P<AssocItem>, ctxt: AssocCtxt) {
|
||||||
|
walk_item_ctxt(visitor, item, ctxt)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_item_ctxt<K: WalkItemKind>(
|
||||||
visitor: &mut impl MutVisitor,
|
visitor: &mut impl MutVisitor,
|
||||||
mut item: P<Item<K>>,
|
item: &mut P<Item<K>>,
|
||||||
) -> SmallVec<[P<Item<K>>; 1]> {
|
ctxt: K::Ctxt,
|
||||||
|
) {
|
||||||
let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
|
let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
|
||||||
visitor.visit_id(id);
|
visitor.visit_id(id);
|
||||||
visit_attrs(visitor, attrs);
|
visit_attrs(visitor, attrs);
|
||||||
visitor.visit_vis(vis);
|
visitor.visit_vis(vis);
|
||||||
visitor.visit_ident(ident);
|
visitor.visit_ident(ident);
|
||||||
kind.walk(*span, *id, visitor);
|
kind.walk(*span, *id, ident, vis, ctxt, visitor);
|
||||||
visit_lazy_tts(visitor, tokens);
|
visit_lazy_tts(visitor, tokens);
|
||||||
visitor.visit_span(span);
|
visitor.visit_span(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P<Item>) -> SmallVec<[P<Item>; 1]> {
|
||||||
|
vis.visit_item(&mut item);
|
||||||
|
smallvec![item]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_foreign_item(
|
||||||
|
vis: &mut impl MutVisitor,
|
||||||
|
mut item: P<ForeignItem>,
|
||||||
|
) -> SmallVec<[P<ForeignItem>; 1]> {
|
||||||
|
vis.visit_foreign_item(&mut item);
|
||||||
|
smallvec![item]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_assoc_item(
|
||||||
|
vis: &mut impl MutVisitor,
|
||||||
|
mut item: P<AssocItem>,
|
||||||
|
ctxt: AssocCtxt,
|
||||||
|
) -> SmallVec<[P<AssocItem>; 1]> {
|
||||||
|
vis.visit_assoc_item(&mut item, ctxt);
|
||||||
smallvec![item]
|
smallvec![item]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for ForeignItemKind {
|
impl WalkItemKind for ForeignItemKind {
|
||||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
|
type Ctxt = ();
|
||||||
|
fn walk(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
_ctxt: Self::Ctxt,
|
||||||
|
visitor: &mut impl MutVisitor,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
||||||
visitor.visit_ty(ty);
|
visitor.visit_ty(ty);
|
||||||
|
@ -1313,7 +1471,11 @@ impl WalkItemKind for ForeignItemKind {
|
||||||
}
|
}
|
||||||
ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||||
visit_defaultness(visitor, defaultness);
|
visit_defaultness(visitor, defaultness);
|
||||||
visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
visitor.visit_fn(
|
||||||
|
FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body),
|
||||||
|
span,
|
||||||
|
id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ForeignItemKind::TyAlias(box TyAlias {
|
ForeignItemKind::TyAlias(box TyAlias {
|
||||||
defaultness,
|
defaultness,
|
||||||
|
@ -1522,9 +1684,8 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
||||||
fn_arg_span,
|
fn_arg_span,
|
||||||
}) => {
|
}) => {
|
||||||
visit_constness(vis, constness);
|
visit_constness(vis, constness);
|
||||||
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
|
||||||
vis.visit_capture_by(capture_clause);
|
vis.visit_capture_by(capture_clause);
|
||||||
vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id);
|
vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id);
|
||||||
vis.visit_span(fn_decl_span);
|
vis.visit_span(fn_decl_span);
|
||||||
vis.visit_span(fn_arg_span);
|
vis.visit_span(fn_arg_span);
|
||||||
}
|
}
|
||||||
|
@ -1785,8 +1946,20 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FnKind<'a> {
|
pub enum FnKind<'a> {
|
||||||
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
||||||
Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option<P<Block>>),
|
Fn(
|
||||||
|
FnCtxt,
|
||||||
|
&'a mut Ident,
|
||||||
|
&'a mut FnSig,
|
||||||
|
&'a mut Visibility,
|
||||||
|
&'a mut Generics,
|
||||||
|
&'a mut Option<P<Block>>,
|
||||||
|
),
|
||||||
|
|
||||||
/// E.g., `|x, y| body`.
|
/// E.g., `|x, y| body`.
|
||||||
Closure(&'a mut ClosureBinder, &'a mut P<FnDecl>, &'a mut P<Expr>),
|
Closure(
|
||||||
|
&'a mut ClosureBinder,
|
||||||
|
&'a mut Option<CoroutineKind>,
|
||||||
|
&'a mut P<FnDecl>,
|
||||||
|
&'a mut P<Expr>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,86 @@ pub enum BinOpToken {
|
||||||
Shr,
|
Shr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This type must not implement `Hash` due to the unusual `PartialEq` impl below.
|
||||||
|
#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||||
|
pub enum InvisibleOrigin {
|
||||||
|
// From the expansion of a metavariable in a declarative macro.
|
||||||
|
MetaVar(MetaVarKind),
|
||||||
|
|
||||||
|
// Converted from `proc_macro::Delimiter` in
|
||||||
|
// `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro.
|
||||||
|
ProcMacro,
|
||||||
|
|
||||||
|
// Converted from `TokenKind::Interpolated` in
|
||||||
|
// `TokenStream::flatten_token`. Treated similarly to `ProcMacro`.
|
||||||
|
FlattenToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for InvisibleOrigin {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, _other: &InvisibleOrigin) -> bool {
|
||||||
|
// When we had AST-based nonterminals we couldn't compare them, and the
|
||||||
|
// old `Nonterminal` type had an `eq` that always returned false,
|
||||||
|
// resulting in this restriction:
|
||||||
|
// https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment
|
||||||
|
// This `eq` emulates that behaviour. We could consider lifting this
|
||||||
|
// restriction now but there are still cases involving invisible
|
||||||
|
// delimiters that make it harder than it first appears.
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Annoyingly similar to `NonterminalKind`, but the slight differences are important.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
|
||||||
|
pub enum MetaVarKind {
|
||||||
|
Item,
|
||||||
|
Block,
|
||||||
|
Stmt,
|
||||||
|
Pat(NtPatKind),
|
||||||
|
Expr {
|
||||||
|
kind: NtExprKind,
|
||||||
|
// This field is needed for `Token::can_begin_literal_maybe_minus`.
|
||||||
|
can_begin_literal_maybe_minus: bool,
|
||||||
|
// This field is needed for `Token::can_begin_string_literal`.
|
||||||
|
can_begin_string_literal: bool,
|
||||||
|
},
|
||||||
|
Ty,
|
||||||
|
Ident,
|
||||||
|
Lifetime,
|
||||||
|
Literal,
|
||||||
|
Meta,
|
||||||
|
Path,
|
||||||
|
Vis,
|
||||||
|
TT,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for MetaVarKind {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let sym = match self {
|
||||||
|
MetaVarKind::Item => sym::item,
|
||||||
|
MetaVarKind::Block => sym::block,
|
||||||
|
MetaVarKind::Stmt => sym::stmt,
|
||||||
|
MetaVarKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
|
||||||
|
MetaVarKind::Pat(PatParam { inferred: false }) => sym::pat_param,
|
||||||
|
MetaVarKind::Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr,
|
||||||
|
MetaVarKind::Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021,
|
||||||
|
MetaVarKind::Ty => sym::ty,
|
||||||
|
MetaVarKind::Ident => sym::ident,
|
||||||
|
MetaVarKind::Lifetime => sym::lifetime,
|
||||||
|
MetaVarKind::Literal => sym::literal,
|
||||||
|
MetaVarKind::Meta => sym::meta,
|
||||||
|
MetaVarKind::Path => sym::path,
|
||||||
|
MetaVarKind::Vis => sym::vis,
|
||||||
|
MetaVarKind::TT => sym::tt,
|
||||||
|
};
|
||||||
|
write!(f, "{sym}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Describes how a sequence of token trees is delimited.
|
/// Describes how a sequence of token trees is delimited.
|
||||||
/// Cannot use `proc_macro::Delimiter` directly because this
|
/// Cannot use `proc_macro::Delimiter` directly because this
|
||||||
/// structure should implement some additional traits.
|
/// structure should implement some additional traits.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||||
#[derive(Encodable, Decodable, Hash, HashStable_Generic)]
|
|
||||||
pub enum Delimiter {
|
pub enum Delimiter {
|
||||||
/// `( ... )`
|
/// `( ... )`
|
||||||
Parenthesis,
|
Parenthesis,
|
||||||
|
@ -59,7 +134,34 @@ pub enum Delimiter {
|
||||||
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
|
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
|
||||||
/// `$var * 3` where `$var` is `1 + 2`.
|
/// `$var * 3` where `$var` is `1 + 2`.
|
||||||
/// Invisible delimiters might not survive roundtrip of a token stream through a string.
|
/// Invisible delimiters might not survive roundtrip of a token stream through a string.
|
||||||
Invisible,
|
Invisible(InvisibleOrigin),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Delimiter {
|
||||||
|
// Should the parser skip these delimiters? Only happens for certain kinds
|
||||||
|
// of invisible delimiters. Ideally this function will eventually disappear
|
||||||
|
// and no invisible delimiters will be skipped.
|
||||||
|
#[inline]
|
||||||
|
pub fn skip(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
|
||||||
|
Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
|
||||||
|
Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This exists because `InvisibleOrigin`s should be compared. It is only used for assertions.
|
||||||
|
pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
|
||||||
|
(Delimiter::Brace, Delimiter::Brace) => true,
|
||||||
|
(Delimiter::Bracket, Delimiter::Bracket) => true,
|
||||||
|
(Delimiter::Invisible(_), Delimiter::Invisible(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that the suffix is *not* considered when deciding the `LitKind` in this
|
// Note that the suffix is *not* considered when deciding the `LitKind` in this
|
||||||
|
@ -496,10 +598,11 @@ impl Token {
|
||||||
/// **NB**: Take care when modifying this function, since it will change
|
/// **NB**: Take care when modifying this function, since it will change
|
||||||
/// the stable set of tokens that are allowed to match an expr nonterminal.
|
/// the stable set of tokens that are allowed to match an expr nonterminal.
|
||||||
pub fn can_begin_expr(&self) -> bool {
|
pub fn can_begin_expr(&self) -> bool {
|
||||||
|
use Delimiter::*;
|
||||||
match self.uninterpolate().kind {
|
match self.uninterpolate().kind {
|
||||||
Ident(name, is_raw) =>
|
Ident(name, is_raw) =>
|
||||||
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
|
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
|
||||||
OpenDelim(..) | // tuple, array or block
|
OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block
|
||||||
Literal(..) | // literal
|
Literal(..) | // literal
|
||||||
Not | // operator not
|
Not | // operator not
|
||||||
BinOp(Minus) | // unary minus
|
BinOp(Minus) | // unary minus
|
||||||
|
@ -520,6 +623,12 @@ impl Token {
|
||||||
NtLiteral(..) |
|
NtLiteral(..) |
|
||||||
NtPath(..)
|
NtPath(..)
|
||||||
),
|
),
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||||
|
MetaVarKind::Block |
|
||||||
|
MetaVarKind::Expr { .. } |
|
||||||
|
MetaVarKind::Literal |
|
||||||
|
MetaVarKind::Path
|
||||||
|
))) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,6 +662,14 @@ impl Token {
|
||||||
| NtPath(..)
|
| NtPath(..)
|
||||||
| NtTy(..)
|
| NtTy(..)
|
||||||
),
|
),
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||||
|
MetaVarKind::Expr { .. } |
|
||||||
|
MetaVarKind::Literal |
|
||||||
|
MetaVarKind::Meta |
|
||||||
|
MetaVarKind::Pat(_) |
|
||||||
|
MetaVarKind::Path |
|
||||||
|
MetaVarKind::Ty
|
||||||
|
))) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,6 +690,10 @@ impl Token {
|
||||||
Lt | BinOp(Shl) | // associated path
|
Lt | BinOp(Shl) | // associated path
|
||||||
PathSep => true, // global path
|
PathSep => true, // global path
|
||||||
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
|
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||||
|
MetaVarKind::Ty |
|
||||||
|
MetaVarKind::Path
|
||||||
|
))) => true,
|
||||||
// For anonymous structs or unions, which only appear in specific positions
|
// For anonymous structs or unions, which only appear in specific positions
|
||||||
// (type of struct fields or union fields), we don't consider them as regular types
|
// (type of struct fields or union fields), we don't consider them as regular types
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -585,6 +706,9 @@ impl Token {
|
||||||
OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true,
|
OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true,
|
||||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
||||||
Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||||
|
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
|
||||||
|
))) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,6 +765,13 @@ impl Token {
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
|
||||||
|
MetaVarKind::Literal => true,
|
||||||
|
MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => {
|
||||||
|
can_begin_literal_maybe_minus
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -656,6 +787,11 @@ impl Token {
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
|
||||||
|
MetaVarKind::Literal => true,
|
||||||
|
MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -896,7 +1032,7 @@ impl PartialEq<TokenKind> for Token {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
|
||||||
pub enum NtPatKind {
|
pub enum NtPatKind {
|
||||||
// Matches or-patterns. Was written using `pat` in edition 2021 or later.
|
// Matches or-patterns. Was written using `pat` in edition 2021 or later.
|
||||||
PatWithOr,
|
PatWithOr,
|
||||||
|
@ -906,7 +1042,7 @@ pub enum NtPatKind {
|
||||||
PatParam { inferred: bool },
|
PatParam { inferred: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
|
||||||
pub enum NtExprKind {
|
pub enum NtExprKind {
|
||||||
// Matches expressions using the post-edition 2024. Was written using
|
// Matches expressions using the post-edition 2024. Was written using
|
||||||
// `expr` in edition 2024 or later.
|
// `expr` in edition 2024 or later.
|
||||||
|
@ -933,7 +1069,7 @@ pub enum Nonterminal {
|
||||||
NtVis(P<ast::Visibility>),
|
NtVis(P<ast::Visibility>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
|
||||||
pub enum NonterminalKind {
|
pub enum NonterminalKind {
|
||||||
Item,
|
Item,
|
||||||
Block,
|
Block,
|
||||||
|
|
|
@ -24,7 +24,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
|
||||||
|
|
||||||
use crate::ast::{AttrStyle, StmtKind};
|
use crate::ast::{AttrStyle, StmtKind};
|
||||||
use crate::ast_traits::{HasAttrs, HasTokens};
|
use crate::ast_traits::{HasAttrs, HasTokens};
|
||||||
use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
|
use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
|
||||||
use crate::{AttrVec, Attribute};
|
use crate::{AttrVec, Attribute};
|
||||||
|
|
||||||
/// Part of a `TokenStream`.
|
/// Part of a `TokenStream`.
|
||||||
|
@ -38,7 +38,6 @@ pub enum TokenTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure all fields of `TokenTree` are `DynSend` and `DynSync`.
|
// Ensure all fields of `TokenTree` are `DynSend` and `DynSync`.
|
||||||
#[cfg(parallel_compiler)]
|
|
||||||
fn _dummy()
|
fn _dummy()
|
||||||
where
|
where
|
||||||
Token: sync::DynSend + sync::DynSync,
|
Token: sync::DynSend + sync::DynSync,
|
||||||
|
@ -485,13 +484,13 @@ impl TokenStream {
|
||||||
token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
|
token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
|
||||||
DelimSpan::from_single(token.span),
|
DelimSpan::from_single(token.span),
|
||||||
DelimSpacing::new(Spacing::JointHidden, spacing),
|
DelimSpacing::new(Spacing::JointHidden, spacing),
|
||||||
Delimiter::Invisible,
|
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
|
||||||
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
|
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
|
||||||
),
|
),
|
||||||
token::Interpolated(ref nt) => TokenTree::Delimited(
|
token::Interpolated(ref nt) => TokenTree::Delimited(
|
||||||
DelimSpan::from_single(token.span),
|
DelimSpan::from_single(token.span),
|
||||||
DelimSpacing::new(Spacing::JointHidden, spacing),
|
DelimSpacing::new(Spacing::JointHidden, spacing),
|
||||||
Delimiter::Invisible,
|
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
|
||||||
TokenStream::from_nonterminal_ast(&nt).flattened(),
|
TokenStream::from_nonterminal_ast(&nt).flattened(),
|
||||||
),
|
),
|
||||||
_ => TokenTree::Token(token.clone(), spacing),
|
_ => TokenTree::Token(token.clone(), spacing),
|
||||||
|
|
|
@ -237,121 +237,6 @@ pub const PREC_PREFIX: i8 = 50;
|
||||||
pub const PREC_UNAMBIGUOUS: i8 = 60;
|
pub const PREC_UNAMBIGUOUS: i8 = 60;
|
||||||
pub const PREC_FORCE_PAREN: i8 = 100;
|
pub const PREC_FORCE_PAREN: i8 = 100;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum ExprPrecedence {
|
|
||||||
Closure,
|
|
||||||
Break,
|
|
||||||
Continue,
|
|
||||||
Ret,
|
|
||||||
Yield,
|
|
||||||
Yeet,
|
|
||||||
Become,
|
|
||||||
|
|
||||||
Range,
|
|
||||||
|
|
||||||
Binary(BinOpKind),
|
|
||||||
|
|
||||||
Cast,
|
|
||||||
|
|
||||||
Assign,
|
|
||||||
AssignOp,
|
|
||||||
|
|
||||||
AddrOf,
|
|
||||||
Let,
|
|
||||||
Unary,
|
|
||||||
|
|
||||||
Call,
|
|
||||||
MethodCall,
|
|
||||||
Field,
|
|
||||||
Index,
|
|
||||||
Try,
|
|
||||||
Mac,
|
|
||||||
|
|
||||||
Array,
|
|
||||||
Repeat,
|
|
||||||
Tup,
|
|
||||||
Lit,
|
|
||||||
Path,
|
|
||||||
Paren,
|
|
||||||
If,
|
|
||||||
While,
|
|
||||||
ForLoop,
|
|
||||||
Loop,
|
|
||||||
Match,
|
|
||||||
PostfixMatch,
|
|
||||||
ConstBlock,
|
|
||||||
Block,
|
|
||||||
TryBlock,
|
|
||||||
Struct,
|
|
||||||
Gen,
|
|
||||||
Await,
|
|
||||||
Err,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprPrecedence {
|
|
||||||
pub fn order(self) -> i8 {
|
|
||||||
match self {
|
|
||||||
ExprPrecedence::Closure => PREC_CLOSURE,
|
|
||||||
|
|
||||||
ExprPrecedence::Break
|
|
||||||
| ExprPrecedence::Continue
|
|
||||||
| ExprPrecedence::Ret
|
|
||||||
| ExprPrecedence::Yield
|
|
||||||
| ExprPrecedence::Yeet
|
|
||||||
| ExprPrecedence::Become => PREC_JUMP,
|
|
||||||
|
|
||||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
|
||||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
|
||||||
// ensures that `pprust` will add parentheses in the right places to get the desired
|
|
||||||
// parse.
|
|
||||||
ExprPrecedence::Range => PREC_RANGE,
|
|
||||||
|
|
||||||
// Binop-like expr kinds, handled by `AssocOp`.
|
|
||||||
ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
|
|
||||||
ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
|
|
||||||
|
|
||||||
ExprPrecedence::Assign |
|
|
||||||
ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
|
|
||||||
|
|
||||||
// Unary, prefix
|
|
||||||
ExprPrecedence::AddrOf
|
|
||||||
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
|
|
||||||
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
|
|
||||||
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
|
|
||||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
|
||||||
| ExprPrecedence::Let
|
|
||||||
| ExprPrecedence::Unary => PREC_PREFIX,
|
|
||||||
|
|
||||||
// Never need parens
|
|
||||||
ExprPrecedence::Array
|
|
||||||
| ExprPrecedence::Await
|
|
||||||
| ExprPrecedence::Block
|
|
||||||
| ExprPrecedence::Call
|
|
||||||
| ExprPrecedence::ConstBlock
|
|
||||||
| ExprPrecedence::Field
|
|
||||||
| ExprPrecedence::ForLoop
|
|
||||||
| ExprPrecedence::Gen
|
|
||||||
| ExprPrecedence::If
|
|
||||||
| ExprPrecedence::Index
|
|
||||||
| ExprPrecedence::Lit
|
|
||||||
| ExprPrecedence::Loop
|
|
||||||
| ExprPrecedence::Mac
|
|
||||||
| ExprPrecedence::Match
|
|
||||||
| ExprPrecedence::MethodCall
|
|
||||||
| ExprPrecedence::Paren
|
|
||||||
| ExprPrecedence::Path
|
|
||||||
| ExprPrecedence::PostfixMatch
|
|
||||||
| ExprPrecedence::Repeat
|
|
||||||
| ExprPrecedence::Struct
|
|
||||||
| ExprPrecedence::Try
|
|
||||||
| ExprPrecedence::TryBlock
|
|
||||||
| ExprPrecedence::Tup
|
|
||||||
| ExprPrecedence::While
|
|
||||||
| ExprPrecedence::Err => PREC_UNAMBIGUOUS,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
|
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
|
||||||
pub fn prec_let_scrutinee_needs_par() -> usize {
|
pub fn prec_let_scrutinee_needs_par() -> usize {
|
||||||
AssocOp::LAnd.precedence()
|
AssocOp::LAnd.precedence()
|
||||||
|
|
|
@ -66,7 +66,7 @@ impl BoundKind {
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum FnKind<'a> {
|
pub enum FnKind<'a> {
|
||||||
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
||||||
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
|
Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>),
|
||||||
|
|
||||||
/// E.g., `|x, y| body`.
|
/// E.g., `|x, y| body`.
|
||||||
Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
|
Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
|
||||||
|
@ -112,11 +112,15 @@ pub enum LifetimeCtxt {
|
||||||
GenericArg,
|
GenericArg,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WalkItemKind: Sized {
|
pub trait WalkItemKind {
|
||||||
|
type Ctxt;
|
||||||
fn walk<'a, V: Visitor<'a>>(
|
fn walk<'a, V: Visitor<'a>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item: &'a Item<Self>,
|
span: Span,
|
||||||
ctxt: AssocCtxt,
|
id: NodeId,
|
||||||
|
ident: &'a Ident,
|
||||||
|
visibility: &'a Visibility,
|
||||||
|
ctxt: Self::Ctxt,
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
) -> V::Result;
|
) -> V::Result;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +192,9 @@ pub trait Visitor<'ast>: Sized {
|
||||||
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result {
|
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result {
|
||||||
walk_where_predicate(self, p)
|
walk_where_predicate(self, p)
|
||||||
}
|
}
|
||||||
|
fn visit_where_predicate_kind(&mut self, k: &'ast WherePredicateKind) -> Self::Result {
|
||||||
|
walk_where_predicate_kind(self, k)
|
||||||
|
}
|
||||||
fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) -> Self::Result {
|
fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) -> Self::Result {
|
||||||
walk_fn(self, fk)
|
walk_fn(self, fk)
|
||||||
}
|
}
|
||||||
|
@ -200,8 +207,8 @@ pub trait Visitor<'ast>: Sized {
|
||||||
fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result {
|
fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result {
|
||||||
walk_param_bound(self, bounds)
|
walk_param_bound(self, bounds)
|
||||||
}
|
}
|
||||||
fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) {
|
fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) -> Self::Result {
|
||||||
walk_precise_capturing_arg(self, arg);
|
walk_precise_capturing_arg(self, arg)
|
||||||
}
|
}
|
||||||
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result {
|
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result {
|
||||||
walk_poly_trait_ref(self, t)
|
walk_poly_trait_ref(self, t)
|
||||||
|
@ -268,8 +275,8 @@ pub trait Visitor<'ast>: Sized {
|
||||||
fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result {
|
fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result {
|
||||||
walk_fn_ret_ty(self, ret_ty)
|
walk_fn_ret_ty(self, ret_ty)
|
||||||
}
|
}
|
||||||
fn visit_fn_header(&mut self, _header: &'ast FnHeader) -> Self::Result {
|
fn visit_fn_header(&mut self, header: &'ast FnHeader) -> Self::Result {
|
||||||
Self::Result::output()
|
walk_fn_header(self, header)
|
||||||
}
|
}
|
||||||
fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result {
|
fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result {
|
||||||
walk_expr_field(self, f)
|
walk_expr_field(self, f)
|
||||||
|
@ -292,6 +299,15 @@ pub trait Visitor<'ast>: Sized {
|
||||||
fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result {
|
fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result {
|
||||||
Self::Result::output()
|
Self::Result::output()
|
||||||
}
|
}
|
||||||
|
fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result {
|
||||||
|
Self::Result::output()
|
||||||
|
}
|
||||||
|
fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result {
|
||||||
|
walk_fn_decl(self, fn_decl)
|
||||||
|
}
|
||||||
|
fn visit_qself(&mut self, qs: &'ast Option<P<QSelf>>) -> Self::Result {
|
||||||
|
walk_qself(self, qs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result {
|
pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result {
|
||||||
|
@ -337,16 +353,19 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for ItemKind {
|
impl WalkItemKind for ItemKind {
|
||||||
|
type Ctxt = ();
|
||||||
fn walk<'a, V: Visitor<'a>>(
|
fn walk<'a, V: Visitor<'a>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item: &'a Item<Self>,
|
span: Span,
|
||||||
_ctxt: AssocCtxt,
|
id: NodeId,
|
||||||
|
ident: &'a Ident,
|
||||||
|
vis: &'a Visibility,
|
||||||
|
_ctxt: Self::Ctxt,
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
let Item { id, span, vis, ident, .. } = item;
|
|
||||||
match self {
|
match self {
|
||||||
ItemKind::ExternCrate(_rename) => {}
|
ItemKind::ExternCrate(_rename) => {}
|
||||||
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, *id, false)),
|
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)),
|
||||||
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
||||||
try_visit!(visitor.visit_ty(ty));
|
try_visit!(visitor.visit_ty(ty));
|
||||||
visit_opt!(visitor, visit_expr, expr);
|
visit_opt!(visitor, visit_expr, expr);
|
||||||
|
@ -357,8 +376,8 @@ impl WalkItemKind for ItemKind {
|
||||||
visit_opt!(visitor, visit_expr, expr);
|
visit_opt!(visitor, visit_expr, expr);
|
||||||
}
|
}
|
||||||
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||||
let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref());
|
let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body);
|
||||||
try_visit!(visitor.visit_fn(kind, *span, *id));
|
try_visit!(visitor.visit_fn(kind, span, id));
|
||||||
}
|
}
|
||||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
||||||
ModKind::Loaded(items, _inline, _inner_span) => {
|
ModKind::Loaded(items, _inline, _inner_span) => {
|
||||||
|
@ -415,7 +434,7 @@ impl WalkItemKind for ItemKind {
|
||||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||||
}
|
}
|
||||||
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
||||||
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, *id)),
|
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, id)),
|
||||||
ItemKind::Delegation(box Delegation {
|
ItemKind::Delegation(box Delegation {
|
||||||
id,
|
id,
|
||||||
qself,
|
qself,
|
||||||
|
@ -424,14 +443,14 @@ impl WalkItemKind for ItemKind {
|
||||||
body,
|
body,
|
||||||
from_glob: _,
|
from_glob: _,
|
||||||
}) => {
|
}) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
visit_opt!(visitor, visit_ident, rename);
|
visit_opt!(visitor, visit_ident, rename);
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
}
|
}
|
||||||
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(prefix, *id));
|
try_visit!(visitor.visit_path(prefix, id));
|
||||||
if let Some(suffixes) = suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
for (ident, rename) in suffixes {
|
for (ident, rename) in suffixes {
|
||||||
visitor.visit_ident(ident);
|
visitor.visit_ident(ident);
|
||||||
|
@ -447,13 +466,6 @@ impl WalkItemKind for ItemKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_item<'a, V: Visitor<'a>>(
|
|
||||||
visitor: &mut V,
|
|
||||||
item: &'a Item<impl WalkItemKind>,
|
|
||||||
) -> V::Result {
|
|
||||||
walk_assoc_item(visitor, item, AssocCtxt::Trait /*ignored*/)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn walk_enum_def<'a, V: Visitor<'a>>(
|
pub fn walk_enum_def<'a, V: Visitor<'a>>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
EnumDef { variants }: &'a EnumDef,
|
EnumDef { variants }: &'a EnumDef,
|
||||||
|
@ -508,10 +520,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
|
||||||
let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } =
|
let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } =
|
||||||
&**function_declaration;
|
&**function_declaration;
|
||||||
walk_list!(visitor, visit_generic_param, generic_params);
|
walk_list!(visitor, visit_generic_param, generic_params);
|
||||||
try_visit!(walk_fn_decl(visitor, decl));
|
try_visit!(visitor.visit_fn_decl(decl));
|
||||||
}
|
}
|
||||||
TyKind::Path(maybe_qself, path) => {
|
TyKind::Path(maybe_qself, path) => {
|
||||||
try_visit!(walk_qself(visitor, maybe_qself));
|
try_visit!(visitor.visit_qself(maybe_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
}
|
}
|
||||||
TyKind::Pat(ty, pat) => {
|
TyKind::Pat(ty, pat) => {
|
||||||
|
@ -642,16 +654,16 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
||||||
let Pat { id, kind, span: _, tokens: _ } = pattern;
|
let Pat { id, kind, span: _, tokens: _ } = pattern;
|
||||||
match kind {
|
match kind {
|
||||||
PatKind::TupleStruct(opt_qself, path, elems) => {
|
PatKind::TupleStruct(opt_qself, path, elems) => {
|
||||||
try_visit!(walk_qself(visitor, opt_qself));
|
try_visit!(visitor.visit_qself(opt_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
walk_list!(visitor, visit_pat, elems);
|
walk_list!(visitor, visit_pat, elems);
|
||||||
}
|
}
|
||||||
PatKind::Path(opt_qself, path) => {
|
PatKind::Path(opt_qself, path) => {
|
||||||
try_visit!(walk_qself(visitor, opt_qself));
|
try_visit!(visitor.visit_qself(opt_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id))
|
try_visit!(visitor.visit_path(path, *id))
|
||||||
}
|
}
|
||||||
PatKind::Struct(opt_qself, path, fields, _rest) => {
|
PatKind::Struct(opt_qself, path, fields, _rest) => {
|
||||||
try_visit!(walk_qself(visitor, opt_qself));
|
try_visit!(visitor.visit_qself(opt_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
walk_list!(visitor, visit_pat_field, fields);
|
walk_list!(visitor, visit_pat_field, fields);
|
||||||
}
|
}
|
||||||
|
@ -681,20 +693,23 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for ForeignItemKind {
|
impl WalkItemKind for ForeignItemKind {
|
||||||
|
type Ctxt = ();
|
||||||
fn walk<'a, V: Visitor<'a>>(
|
fn walk<'a, V: Visitor<'a>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item: &'a Item<Self>,
|
span: Span,
|
||||||
_ctxt: AssocCtxt,
|
id: NodeId,
|
||||||
|
ident: &'a Ident,
|
||||||
|
vis: &'a Visibility,
|
||||||
|
_ctxt: Self::Ctxt,
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
let &Item { id, span, ident, ref vis, .. } = item;
|
|
||||||
match self {
|
match self {
|
||||||
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
||||||
try_visit!(visitor.visit_ty(ty));
|
try_visit!(visitor.visit_ty(ty));
|
||||||
visit_opt!(visitor, visit_expr, expr);
|
visit_opt!(visitor, visit_expr, expr);
|
||||||
}
|
}
|
||||||
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||||
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
|
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body);
|
||||||
try_visit!(visitor.visit_fn(kind, span, id));
|
try_visit!(visitor.visit_fn(kind, span, id));
|
||||||
}
|
}
|
||||||
ForeignItemKind::TyAlias(box TyAlias {
|
ForeignItemKind::TyAlias(box TyAlias {
|
||||||
|
@ -730,14 +745,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
|
||||||
pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>(
|
pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
arg: &'a PreciseCapturingArg,
|
arg: &'a PreciseCapturingArg,
|
||||||
) {
|
) -> V::Result {
|
||||||
match arg {
|
match arg {
|
||||||
PreciseCapturingArg::Lifetime(lt) => {
|
PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg),
|
||||||
visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg);
|
PreciseCapturingArg::Arg(path, id) => visitor.visit_path(path, *id),
|
||||||
}
|
|
||||||
PreciseCapturingArg::Arg(path, id) => {
|
|
||||||
visitor.visit_path(path, *id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,22 +797,29 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
predicate: &'a WherePredicate,
|
predicate: &'a WherePredicate,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
match predicate {
|
let WherePredicate { kind, id: _, span: _ } = predicate;
|
||||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
visitor.visit_where_predicate_kind(kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_where_predicate_kind<'a, V: Visitor<'a>>(
|
||||||
|
visitor: &mut V,
|
||||||
|
kind: &'a WherePredicateKind,
|
||||||
|
) -> V::Result {
|
||||||
|
match kind {
|
||||||
|
WherePredicateKind::BoundPredicate(WhereBoundPredicate {
|
||||||
bounded_ty,
|
bounded_ty,
|
||||||
bounds,
|
bounds,
|
||||||
bound_generic_params,
|
bound_generic_params,
|
||||||
span: _,
|
|
||||||
}) => {
|
}) => {
|
||||||
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
||||||
try_visit!(visitor.visit_ty(bounded_ty));
|
try_visit!(visitor.visit_ty(bounded_ty));
|
||||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||||
}
|
}
|
||||||
WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span: _ }) => {
|
WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
|
||||||
try_visit!(visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound));
|
try_visit!(visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound));
|
||||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||||
}
|
}
|
||||||
WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span: _ }) => {
|
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
|
||||||
try_visit!(visitor.visit_ty(lhs_ty));
|
try_visit!(visitor.visit_ty(lhs_ty));
|
||||||
try_visit!(visitor.visit_ty(rhs_ty));
|
try_visit!(visitor.visit_ty(rhs_ty));
|
||||||
}
|
}
|
||||||
|
@ -817,6 +835,12 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy)
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_fn_header<'a, V: Visitor<'a>>(visitor: &mut V, fn_header: &'a FnHeader) -> V::Result {
|
||||||
|
let FnHeader { safety: _, coroutine_kind, constness: _, ext: _ } = fn_header;
|
||||||
|
visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
|
||||||
|
V::Result::output()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_fn_decl<'a, V: Visitor<'a>>(
|
pub fn walk_fn_decl<'a, V: Visitor<'a>>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
FnDecl { inputs, output }: &'a FnDecl,
|
FnDecl { inputs, output }: &'a FnDecl,
|
||||||
|
@ -831,12 +855,13 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
|
||||||
// Identifier and visibility are visited as a part of the item.
|
// Identifier and visibility are visited as a part of the item.
|
||||||
try_visit!(visitor.visit_fn_header(header));
|
try_visit!(visitor.visit_fn_header(header));
|
||||||
try_visit!(visitor.visit_generics(generics));
|
try_visit!(visitor.visit_generics(generics));
|
||||||
try_visit!(walk_fn_decl(visitor, decl));
|
try_visit!(visitor.visit_fn_decl(decl));
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
}
|
}
|
||||||
FnKind::Closure(binder, _coroutine_kind, decl, body) => {
|
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
||||||
try_visit!(visitor.visit_closure_binder(binder));
|
try_visit!(visitor.visit_closure_binder(binder));
|
||||||
try_visit!(walk_fn_decl(visitor, decl));
|
visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
|
||||||
|
try_visit!(visitor.visit_fn_decl(decl));
|
||||||
try_visit!(visitor.visit_expr(body));
|
try_visit!(visitor.visit_expr(body));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -844,13 +869,16 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for AssocItemKind {
|
impl WalkItemKind for AssocItemKind {
|
||||||
|
type Ctxt = AssocCtxt;
|
||||||
fn walk<'a, V: Visitor<'a>>(
|
fn walk<'a, V: Visitor<'a>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item: &'a Item<Self>,
|
span: Span,
|
||||||
ctxt: AssocCtxt,
|
id: NodeId,
|
||||||
|
ident: &'a Ident,
|
||||||
|
vis: &'a Visibility,
|
||||||
|
ctxt: Self::Ctxt,
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
let &Item { id, span, ident, ref vis, .. } = item;
|
|
||||||
match self {
|
match self {
|
||||||
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
|
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
|
||||||
try_visit!(visitor.visit_generics(generics));
|
try_visit!(visitor.visit_generics(generics));
|
||||||
|
@ -858,8 +886,7 @@ impl WalkItemKind for AssocItemKind {
|
||||||
visit_opt!(visitor, visit_expr, expr);
|
visit_opt!(visitor, visit_expr, expr);
|
||||||
}
|
}
|
||||||
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||||
let kind =
|
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body);
|
||||||
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
|
|
||||||
try_visit!(visitor.visit_fn(kind, span, id));
|
try_visit!(visitor.visit_fn(kind, span, id));
|
||||||
}
|
}
|
||||||
AssocItemKind::Type(box TyAlias {
|
AssocItemKind::Type(box TyAlias {
|
||||||
|
@ -884,13 +911,13 @@ impl WalkItemKind for AssocItemKind {
|
||||||
body,
|
body,
|
||||||
from_glob: _,
|
from_glob: _,
|
||||||
}) => {
|
}) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
visit_opt!(visitor, visit_ident, rename);
|
visit_opt!(visitor, visit_ident, rename);
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
}
|
}
|
||||||
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(prefix, id));
|
try_visit!(visitor.visit_path(prefix, id));
|
||||||
if let Some(suffixes) = suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
for (ident, rename) in suffixes {
|
for (ident, rename) in suffixes {
|
||||||
|
@ -907,16 +934,31 @@ impl WalkItemKind for AssocItemKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_item<'a, V: Visitor<'a>>(
|
||||||
|
visitor: &mut V,
|
||||||
|
item: &'a Item<impl WalkItemKind<Ctxt = ()>>,
|
||||||
|
) -> V::Result {
|
||||||
|
walk_item_ctxt(visitor, item, ())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_assoc_item<'a, V: Visitor<'a>>(
|
pub fn walk_assoc_item<'a, V: Visitor<'a>>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
item: &'a Item<impl WalkItemKind>,
|
item: &'a AssocItem,
|
||||||
ctxt: AssocCtxt,
|
ctxt: AssocCtxt,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item;
|
walk_item_ctxt(visitor, item, ctxt)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_item_ctxt<'a, V: Visitor<'a>, K: WalkItemKind>(
|
||||||
|
visitor: &mut V,
|
||||||
|
item: &'a Item<K>,
|
||||||
|
ctxt: K::Ctxt,
|
||||||
|
) -> V::Result {
|
||||||
|
let Item { id, span, ident, vis, attrs, kind, tokens: _ } = item;
|
||||||
walk_list!(visitor, visit_attribute, attrs);
|
walk_list!(visitor, visit_attribute, attrs);
|
||||||
try_visit!(visitor.visit_vis(vis));
|
try_visit!(visitor.visit_vis(vis));
|
||||||
try_visit!(visitor.visit_ident(ident));
|
try_visit!(visitor.visit_ident(ident));
|
||||||
try_visit!(kind.walk(item, ctxt, visitor));
|
try_visit!(kind.walk(*span, *id, ident, vis, ctxt, visitor));
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,7 +971,7 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result {
|
pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result {
|
||||||
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field;
|
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _ } = field;
|
||||||
walk_list!(visitor, visit_attribute, attrs);
|
walk_list!(visitor, visit_attribute, attrs);
|
||||||
try_visit!(visitor.visit_vis(vis));
|
try_visit!(visitor.visit_vis(vis));
|
||||||
visit_opt!(visitor, visit_ident, ident);
|
visit_opt!(visitor, visit_ident, ident);
|
||||||
|
@ -1005,7 +1047,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
InlineAsmSym { id, qself, path }: &'a InlineAsmSym,
|
InlineAsmSym { id, qself, path }: &'a InlineAsmSym,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
visitor.visit_path(path, *id)
|
visitor.visit_path(path, *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1037,7 +1079,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
||||||
}
|
}
|
||||||
ExprKind::Struct(se) => {
|
ExprKind::Struct(se) => {
|
||||||
let StructExpr { qself, path, fields, rest } = &**se;
|
let StructExpr { qself, path, fields, rest } = &**se;
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
walk_list!(visitor, visit_expr_field, fields);
|
walk_list!(visitor, visit_expr_field, fields);
|
||||||
match rest {
|
match rest {
|
||||||
|
@ -1146,7 +1188,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
||||||
}
|
}
|
||||||
ExprKind::Underscore => {}
|
ExprKind::Underscore => {}
|
||||||
ExprKind::Path(maybe_qself, path) => {
|
ExprKind::Path(maybe_qself, path) => {
|
||||||
try_visit!(walk_qself(visitor, maybe_qself));
|
try_visit!(visitor.visit_qself(maybe_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
}
|
}
|
||||||
ExprKind::Break(opt_label, opt_expr) => {
|
ExprKind::Break(opt_label, opt_expr) => {
|
||||||
|
|
|
@ -103,6 +103,12 @@ ast_lowering_invalid_asm_template_modifier_reg_class =
|
||||||
ast_lowering_invalid_asm_template_modifier_sym =
|
ast_lowering_invalid_asm_template_modifier_sym =
|
||||||
asm template modifiers are not allowed for `sym` arguments
|
asm template modifiers are not allowed for `sym` arguments
|
||||||
|
|
||||||
|
ast_lowering_invalid_legacy_const_generic_arg =
|
||||||
|
invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
|
||||||
|
|
||||||
|
ast_lowering_invalid_legacy_const_generic_arg_suggestion =
|
||||||
|
try using a const generic argument instead
|
||||||
|
|
||||||
ast_lowering_invalid_register =
|
ast_lowering_invalid_register =
|
||||||
invalid register `{$reg}`: {$error}
|
invalid register `{$reg}`: {$error}
|
||||||
|
|
||||||
|
@ -146,6 +152,8 @@ ast_lowering_register2 = register `{$reg2_name}`
|
||||||
|
|
||||||
ast_lowering_register_class_only_clobber =
|
ast_lowering_register_class_only_clobber =
|
||||||
register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
|
register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
|
||||||
|
ast_lowering_register_class_only_clobber_stable =
|
||||||
|
register class `{$reg_class_name}` can only be used as a clobber in stable
|
||||||
|
|
||||||
ast_lowering_register_conflict =
|
ast_lowering_register_conflict =
|
||||||
register `{$reg1_name}` conflicts with register `{$reg2_name}`
|
register `{$reg1_name}` conflicts with register `{$reg2_name}`
|
||||||
|
@ -175,6 +183,8 @@ ast_lowering_underscore_expr_lhs_assign =
|
||||||
.label = `_` not allowed here
|
.label = `_` not allowed here
|
||||||
|
|
||||||
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
|
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
|
||||||
|
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
|
||||||
|
using both label and output operands for inline assembly is unstable
|
||||||
ast_lowering_unstable_inline_assembly_label_operands =
|
ast_lowering_unstable_inline_assembly_label_operands =
|
||||||
label operands for inline assembly are unstable
|
label operands for inline assembly are unstable
|
||||||
ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable
|
ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable
|
||||||
|
|
|
@ -17,7 +17,8 @@ use super::errors::{
|
||||||
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
|
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
|
||||||
InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
|
InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
|
||||||
InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
|
InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
|
||||||
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
|
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable,
|
||||||
|
RegisterConflict,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
|
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
|
||||||
|
@ -45,9 +46,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
| asm::InlineAsmArch::X86_64
|
| asm::InlineAsmArch::X86_64
|
||||||
| asm::InlineAsmArch::Arm
|
| asm::InlineAsmArch::Arm
|
||||||
| asm::InlineAsmArch::AArch64
|
| asm::InlineAsmArch::AArch64
|
||||||
|
| asm::InlineAsmArch::Arm64EC
|
||||||
| asm::InlineAsmArch::RiscV32
|
| asm::InlineAsmArch::RiscV32
|
||||||
| asm::InlineAsmArch::RiscV64
|
| asm::InlineAsmArch::RiscV64
|
||||||
| asm::InlineAsmArch::LoongArch64
|
| asm::InlineAsmArch::LoongArch64
|
||||||
|
| asm::InlineAsmArch::S390x
|
||||||
);
|
);
|
||||||
if !is_stable && !self.tcx.features().asm_experimental_arch() {
|
if !is_stable && !self.tcx.features().asm_experimental_arch() {
|
||||||
feature_err(
|
feature_err(
|
||||||
|
@ -59,6 +62,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
|
||||||
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
|
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
|
||||||
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
|
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
|
||||||
&& !self.tcx.sess.opts.actually_rustdoc
|
&& !self.tcx.sess.opts.actually_rustdoc
|
||||||
|
@ -237,15 +241,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InlineAsmOperand::Label { block } => {
|
InlineAsmOperand::Label { block } => {
|
||||||
if !self.tcx.features().asm_goto() {
|
|
||||||
feature_err(
|
|
||||||
sess,
|
|
||||||
sym::asm_goto,
|
|
||||||
*op_sp,
|
|
||||||
fluent::ast_lowering_unstable_inline_assembly_label_operands,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
hir::InlineAsmOperand::Label { block: self.lower_block(block, false) }
|
hir::InlineAsmOperand::Label { block: self.lower_block(block, false) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -331,11 +326,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// means that we disallow passing a value in/out of the asm and
|
// means that we disallow passing a value in/out of the asm and
|
||||||
// require that the operand name an explicit register, not a
|
// require that the operand name an explicit register, not a
|
||||||
// register class.
|
// register class.
|
||||||
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
|
if reg_class.is_clobber_only(asm_arch.unwrap(), allow_experimental_reg)
|
||||||
|
&& !op.is_clobber()
|
||||||
|
{
|
||||||
|
if allow_experimental_reg || reg_class.is_clobber_only(asm_arch.unwrap(), true)
|
||||||
|
{
|
||||||
|
// always clobber-only
|
||||||
self.dcx().emit_err(RegisterClassOnlyClobber {
|
self.dcx().emit_err(RegisterClassOnlyClobber {
|
||||||
op_span: op_sp,
|
op_span: op_sp,
|
||||||
reg_class_name: reg_class.name(),
|
reg_class_name: reg_class.name(),
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// clobber-only in stable
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.create_feature_err(
|
||||||
|
RegisterClassOnlyClobberStable {
|
||||||
|
op_span: op_sp,
|
||||||
|
reg_class_name: reg_class.name(),
|
||||||
|
},
|
||||||
|
sym::asm_experimental_reg,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,6 +477,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Feature gate checking for asm goto.
|
||||||
|
if let Some((_, op_sp)) =
|
||||||
|
operands.iter().find(|(op, _)| matches!(op, hir::InlineAsmOperand::Label { .. }))
|
||||||
|
{
|
||||||
|
if !self.tcx.features().asm_goto() {
|
||||||
|
feature_err(
|
||||||
|
sess,
|
||||||
|
sym::asm_goto,
|
||||||
|
*op_sp,
|
||||||
|
fluent::ast_lowering_unstable_inline_assembly_label_operands,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// In addition, check if an output operand is used.
|
||||||
|
// This is gated behind an additional feature.
|
||||||
|
let output_operand_used = operands.iter().any(|(op, _)| {
|
||||||
|
matches!(
|
||||||
|
op,
|
||||||
|
hir::InlineAsmOperand::Out { expr: Some(_), .. }
|
||||||
|
| hir::InlineAsmOperand::InOut { .. }
|
||||||
|
| hir::InlineAsmOperand::SplitInOut { out_expr: Some(_), .. }
|
||||||
|
)
|
||||||
|
});
|
||||||
|
if output_operand_used && !self.tcx.features().asm_goto_with_outputs() {
|
||||||
|
feature_err(
|
||||||
|
sess,
|
||||||
|
sym::asm_goto_with_outputs,
|
||||||
|
*op_sp,
|
||||||
|
fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let operands = self.arena.alloc_from_iter(operands);
|
let operands = self.arena.alloc_from_iter(operands);
|
||||||
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
|
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
|
||||||
let template_strs = self.arena.alloc_from_iter(
|
let template_strs = self.arena.alloc_from_iter(
|
||||||
|
|
|
@ -279,6 +279,14 @@ pub(crate) struct RegisterClassOnlyClobber {
|
||||||
pub reg_class_name: Symbol,
|
pub reg_class_name: Symbol,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(ast_lowering_register_class_only_clobber_stable)]
|
||||||
|
pub(crate) struct RegisterClassOnlyClobberStable {
|
||||||
|
#[primary_span]
|
||||||
|
pub op_span: Span,
|
||||||
|
pub reg_class_name: Symbol,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(ast_lowering_register_conflict)]
|
#[diag(ast_lowering_register_conflict)]
|
||||||
pub(crate) struct RegisterConflict<'a> {
|
pub(crate) struct RegisterConflict<'a> {
|
||||||
|
@ -451,3 +459,26 @@ pub(crate) struct YieldInClosure {
|
||||||
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
|
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
|
||||||
pub suggestion: Option<Span>,
|
pub suggestion: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(ast_lowering_invalid_legacy_const_generic_arg)]
|
||||||
|
pub(crate) struct InvalidLegacyConstGenericArg {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub suggestion: UseConstGenericArg,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(
|
||||||
|
ast_lowering_invalid_legacy_const_generic_arg_suggestion,
|
||||||
|
applicability = "maybe-incorrect"
|
||||||
|
)]
|
||||||
|
pub(crate) struct UseConstGenericArg {
|
||||||
|
#[suggestion_part(code = "::<{const_args}>")]
|
||||||
|
pub end_of_fn: Span,
|
||||||
|
pub const_args: String,
|
||||||
|
pub other_args: String,
|
||||||
|
#[suggestion_part(code = "{other_args}")]
|
||||||
|
pub call_args: Span,
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use rustc_ast::ptr::P as AstP;
|
use rustc_ast::ptr::P as AstP;
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
|
use rustc_ast_pretty::pprust::expr_to_string;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::HirId;
|
use rustc_hir::HirId;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::errors::report_lit_error;
|
use rustc_session::errors::report_lit_error;
|
||||||
use rustc_span::source_map::{Spanned, respan};
|
use rustc_span::source_map::{Spanned, respan};
|
||||||
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
||||||
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
|
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
|
||||||
use thin_vec::{ThinVec, thin_vec};
|
use thin_vec::{ThinVec, thin_vec};
|
||||||
|
use visit::{Visitor, walk_expr};
|
||||||
|
|
||||||
use super::errors::{
|
use super::errors::{
|
||||||
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
|
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
|
||||||
|
@ -23,9 +27,32 @@ use super::errors::{
|
||||||
use super::{
|
use super::{
|
||||||
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||||
};
|
};
|
||||||
use crate::errors::YieldInClosure;
|
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
||||||
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated};
|
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated};
|
||||||
|
|
||||||
|
struct WillCreateDefIdsVisitor {}
|
||||||
|
|
||||||
|
impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
|
||||||
|
type Result = ControlFlow<Span>;
|
||||||
|
|
||||||
|
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
|
||||||
|
ControlFlow::Break(c.value.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_item(&mut self, item: &'v Item) -> Self::Result {
|
||||||
|
ControlFlow::Break(item.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {
|
||||||
|
match ex.kind {
|
||||||
|
ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => {
|
||||||
|
ControlFlow::Break(ex.span)
|
||||||
|
}
|
||||||
|
_ => walk_expr(self, ex),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'hir> LoweringContext<'_, 'hir> {
|
impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||||
self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
|
self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
|
||||||
|
@ -396,10 +423,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut error = None;
|
||||||
|
let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| {
|
||||||
|
// Avoid emitting the error multiple times.
|
||||||
|
if error.is_none() {
|
||||||
|
let mut const_args = vec![];
|
||||||
|
let mut other_args = vec![];
|
||||||
|
for (idx, arg) in args.iter().enumerate() {
|
||||||
|
if legacy_args_idx.contains(&idx) {
|
||||||
|
const_args.push(format!("{{ {} }}", expr_to_string(arg)));
|
||||||
|
} else {
|
||||||
|
other_args.push(expr_to_string(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let suggestion = UseConstGenericArg {
|
||||||
|
end_of_fn: f.span.shrink_to_hi(),
|
||||||
|
const_args: const_args.join(", "),
|
||||||
|
other_args: other_args.join(", "),
|
||||||
|
call_args: args[0].span.to(args.last().unwrap().span),
|
||||||
|
};
|
||||||
|
error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion }));
|
||||||
|
}
|
||||||
|
error.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
// Split the arguments into const generics and normal arguments
|
// Split the arguments into const generics and normal arguments
|
||||||
let mut real_args = vec![];
|
let mut real_args = vec![];
|
||||||
let mut generic_args = ThinVec::new();
|
let mut generic_args = ThinVec::new();
|
||||||
for (idx, arg) in args.into_iter().enumerate() {
|
for (idx, arg) in args.iter().cloned().enumerate() {
|
||||||
if legacy_args_idx.contains(&idx) {
|
if legacy_args_idx.contains(&idx) {
|
||||||
let parent_def_id = self.current_def_id_parent;
|
let parent_def_id = self.current_def_id_parent;
|
||||||
let node_id = self.next_node_id();
|
let node_id = self.next_node_id();
|
||||||
|
@ -410,7 +461,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
|
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
let anon_const = AnonConst { id: node_id, value: arg };
|
let mut visitor = WillCreateDefIdsVisitor {};
|
||||||
|
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
|
||||||
|
AstP(Expr {
|
||||||
|
id: self.next_node_id(),
|
||||||
|
kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
|
||||||
|
span: f.span,
|
||||||
|
attrs: [].into(),
|
||||||
|
tokens: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
arg
|
||||||
|
};
|
||||||
|
|
||||||
|
let anon_const = AnonConst { id: node_id, value: const_value };
|
||||||
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
|
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
|
||||||
} else {
|
} else {
|
||||||
real_args.push(arg);
|
real_args.push(arg);
|
||||||
|
|
|
@ -381,15 +381,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_where_predicate(&mut self, predicate: &'hir WherePredicate<'hir>) {
|
fn visit_where_predicate(&mut self, predicate: &'hir WherePredicate<'hir>) {
|
||||||
match predicate {
|
self.insert(predicate.span, predicate.hir_id, Node::WherePredicate(predicate));
|
||||||
WherePredicate::BoundPredicate(pred) => {
|
self.with_parent(predicate.hir_id, |this| {
|
||||||
self.insert(pred.span, pred.hir_id, Node::WhereBoundPredicate(pred));
|
|
||||||
self.with_parent(pred.hir_id, |this| {
|
|
||||||
intravisit::walk_where_predicate(this, predicate)
|
intravisit::walk_where_predicate(this, predicate)
|
||||||
})
|
});
|
||||||
}
|
|
||||||
_ => intravisit::walk_where_predicate(self, predicate),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_array_length(&mut self, len: &'hir ArrayLen<'hir>) {
|
fn visit_array_length(&mut self, len: &'hir ArrayLen<'hir>) {
|
||||||
|
|
|
@ -724,6 +724,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
},
|
},
|
||||||
vis_span: self.lower_span(f.vis.span),
|
vis_span: self.lower_span(f.vis.span),
|
||||||
ty,
|
ty,
|
||||||
|
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1400,7 +1401,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// keep track of the Span info. Now, `<dyn HirTyLowerer>::add_implicit_sized_bound`
|
// keep track of the Span info. Now, `<dyn HirTyLowerer>::add_implicit_sized_bound`
|
||||||
// checks both param bounds and where clauses for `?Sized`.
|
// checks both param bounds and where clauses for `?Sized`.
|
||||||
for pred in &generics.where_clause.predicates {
|
for pred in &generics.where_clause.predicates {
|
||||||
let WherePredicate::BoundPredicate(bound_pred) = pred else {
|
let WherePredicateKind::BoundPredicate(bound_pred) = &pred.kind else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let compute_is_param = || {
|
let compute_is_param = || {
|
||||||
|
@ -1537,9 +1538,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let span = self.lower_span(span);
|
let span = self.lower_span(span);
|
||||||
|
let hir_id = self.next_id();
|
||||||
match kind {
|
let kind = self.arena.alloc(match kind {
|
||||||
GenericParamKind::Const { .. } => None,
|
GenericParamKind::Const { .. } => return None,
|
||||||
GenericParamKind::Type { .. } => {
|
GenericParamKind::Type { .. } => {
|
||||||
let def_id = self.local_def_id(id).to_def_id();
|
let def_id = self.local_def_id(id).to_def_id();
|
||||||
let hir_id = self.next_id();
|
let hir_id = self.next_id();
|
||||||
|
@ -1554,38 +1555,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let ty_id = self.next_id();
|
let ty_id = self.next_id();
|
||||||
let bounded_ty =
|
let bounded_ty =
|
||||||
self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path));
|
self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path));
|
||||||
Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
|
||||||
hir_id: self.next_id(),
|
|
||||||
bounded_ty: self.arena.alloc(bounded_ty),
|
bounded_ty: self.arena.alloc(bounded_ty),
|
||||||
bounds,
|
bounds,
|
||||||
span,
|
|
||||||
bound_generic_params: &[],
|
bound_generic_params: &[],
|
||||||
origin,
|
origin,
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
GenericParamKind::Lifetime => {
|
GenericParamKind::Lifetime => {
|
||||||
let ident = self.lower_ident(ident);
|
let ident = self.lower_ident(ident);
|
||||||
let lt_id = self.next_node_id();
|
let lt_id = self.next_node_id();
|
||||||
let lifetime = self.new_named_lifetime(id, lt_id, ident);
|
let lifetime = self.new_named_lifetime(id, lt_id, ident);
|
||||||
Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||||
lifetime,
|
lifetime,
|
||||||
span,
|
|
||||||
bounds,
|
bounds,
|
||||||
in_where_clause: false,
|
in_where_clause: false,
|
||||||
}))
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
Some(hir::WherePredicate { hir_id, span, kind })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
|
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
|
||||||
match pred {
|
let hir_id = self.lower_node_id(pred.id);
|
||||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
let span = self.lower_span(pred.span);
|
||||||
|
let kind = self.arena.alloc(match &pred.kind {
|
||||||
|
WherePredicateKind::BoundPredicate(WhereBoundPredicate {
|
||||||
bound_generic_params,
|
bound_generic_params,
|
||||||
bounded_ty,
|
bounded_ty,
|
||||||
bounds,
|
bounds,
|
||||||
span,
|
}) => hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
|
||||||
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
|
||||||
hir_id: self.next_id(),
|
|
||||||
bound_generic_params: self
|
bound_generic_params: self
|
||||||
.lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
|
.lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
|
||||||
bounded_ty: self
|
bounded_ty: self
|
||||||
|
@ -1594,12 +1593,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
bounds,
|
bounds,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||||
),
|
),
|
||||||
span: self.lower_span(*span),
|
|
||||||
origin: PredicateOrigin::WhereClause,
|
origin: PredicateOrigin::WhereClause,
|
||||||
}),
|
}),
|
||||||
WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span }) => {
|
WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
|
||||||
hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||||
span: self.lower_span(*span),
|
|
||||||
lifetime: self.lower_lifetime(lifetime),
|
lifetime: self.lower_lifetime(lifetime),
|
||||||
bounds: self.lower_param_bounds(
|
bounds: self.lower_param_bounds(
|
||||||
bounds,
|
bounds,
|
||||||
|
@ -1608,15 +1605,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
in_where_clause: true,
|
in_where_clause: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span }) => {
|
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
|
||||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
||||||
lhs_ty: self
|
lhs_ty: self
|
||||||
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||||
rhs_ty: self
|
rhs_ty: self
|
||||||
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||||
span: self.lower_span(*span),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
hir::WherePredicate { hir_id, span, kind }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -738,7 +738,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||||
) -> Span {
|
) -> Span {
|
||||||
self.tcx.with_stable_hashing_context(|hcx| {
|
self.tcx.with_stable_hashing_context(|hcx| {
|
||||||
span.mark_with_reason(allow_internal_unstable, reason, self.tcx.sess.edition(), hcx)
|
span.mark_with_reason(allow_internal_unstable, reason, span.edition(), hcx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2052,6 +2052,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used when lowering a type argument that turned out to actually be a const argument.
|
||||||
|
///
|
||||||
|
/// Only use for that purpose since otherwise it will create a duplicate def.
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn lower_const_path_to_const_arg(
|
fn lower_const_path_to_const_arg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -2060,20 +2063,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
ty_id: NodeId,
|
ty_id: NodeId,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> &'hir hir::ConstArg<'hir> {
|
) -> &'hir hir::ConstArg<'hir> {
|
||||||
let ct_kind = match res {
|
let tcx = self.tcx;
|
||||||
Res::Def(DefKind::ConstParam, _) => {
|
|
||||||
|
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
|
||||||
|
let ct_kind = if path.is_potential_trivial_const_arg()
|
||||||
|
&& (tcx.features().min_generic_const_args()
|
||||||
|
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
|
||||||
|
{
|
||||||
let qpath = self.lower_qpath(
|
let qpath = self.lower_qpath(
|
||||||
ty_id,
|
ty_id,
|
||||||
&None,
|
&None,
|
||||||
path,
|
path,
|
||||||
ParamMode::Optional,
|
ParamMode::Optional,
|
||||||
AllowReturnTypeNotation::No,
|
AllowReturnTypeNotation::No,
|
||||||
|
// FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
hir::ConstArgKind::Path(qpath)
|
hir::ConstArgKind::Path(qpath)
|
||||||
}
|
} else {
|
||||||
_ => {
|
|
||||||
// Construct an AnonConst where the expr is the "ty"'s path.
|
// Construct an AnonConst where the expr is the "ty"'s path.
|
||||||
|
|
||||||
let parent_def_id = self.current_def_id_parent;
|
let parent_def_id = self.current_def_id_parent;
|
||||||
|
@ -2081,6 +2089,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let span = self.lower_span(span);
|
let span = self.lower_span(span);
|
||||||
|
|
||||||
// Add a definition for the in-band const def.
|
// Add a definition for the in-band const def.
|
||||||
|
// We're lowering a const argument that was originally thought to be a type argument,
|
||||||
|
// so the def collector didn't create the def ahead of time. That's why we have to do
|
||||||
|
// it here.
|
||||||
let def_id =
|
let def_id =
|
||||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
|
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
|
||||||
let hir_id = self.lower_node_id(node_id);
|
let hir_id = self.lower_node_id(node_id);
|
||||||
|
@ -2104,14 +2115,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
hir::ConstArgKind::Anon(ct)
|
hir::ConstArgKind::Anon(ct)
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.arena.alloc(hir::ConstArg {
|
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: ct_kind,
|
|
||||||
is_desugared_from_effects: false,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`hir::ConstArg`] for when to use this function vs
|
/// See [`hir::ConstArg`] for when to use this function vs
|
||||||
|
@ -2122,6 +2128,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||||
|
let tcx = self.tcx;
|
||||||
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
|
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
|
||||||
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
|
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
|
||||||
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
|
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
|
||||||
|
@ -2135,35 +2142,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
};
|
};
|
||||||
let maybe_res =
|
let maybe_res =
|
||||||
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
||||||
debug!("res={:?}", maybe_res);
|
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
|
||||||
// FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path
|
if let ExprKind::Path(None, path) = &expr.kind
|
||||||
if let Some(res) = maybe_res
|
&& path.is_potential_trivial_const_arg()
|
||||||
&& let Res::Def(DefKind::ConstParam, _) = res
|
&& (tcx.features().min_generic_const_args()
|
||||||
&& let ExprKind::Path(qself, path) = &expr.kind
|
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
|
||||||
{
|
{
|
||||||
let qpath = self.lower_qpath(
|
let qpath = self.lower_qpath(
|
||||||
expr.id,
|
expr.id,
|
||||||
qself,
|
&None,
|
||||||
path,
|
path,
|
||||||
ParamMode::Optional,
|
ParamMode::Optional,
|
||||||
AllowReturnTypeNotation::No,
|
AllowReturnTypeNotation::No,
|
||||||
|
// FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
return ConstArg {
|
return ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) };
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: hir::ConstArgKind::Path(qpath),
|
|
||||||
is_desugared_from_effects: false,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||||
ConstArg {
|
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
|
||||||
is_desugared_from_effects: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`hir::ConstArg`] for when to use this function vs
|
/// See [`hir::ConstArg`] for when to use this function vs
|
||||||
|
|
|
@ -946,8 +946,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
|
|
||||||
self.visit_vis(&item.vis);
|
self.visit_vis(&item.vis);
|
||||||
self.visit_ident(&item.ident);
|
self.visit_ident(&item.ident);
|
||||||
let kind =
|
let kind = FnKind::Fn(FnCtxt::Free, &item.ident, sig, &item.vis, generics, body);
|
||||||
FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
|
|
||||||
self.visit_fn(kind, item.span, item.id);
|
self.visit_fn(kind, item.span, item.id);
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
walk_list!(self, visit_attribute, &item.attrs);
|
||||||
return; // Avoid visiting again.
|
return; // Avoid visiting again.
|
||||||
|
@ -1201,14 +1200,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
validate_generic_param_order(self.dcx(), &generics.params, generics.span);
|
validate_generic_param_order(self.dcx(), &generics.params, generics.span);
|
||||||
|
|
||||||
for predicate in &generics.where_clause.predicates {
|
for predicate in &generics.where_clause.predicates {
|
||||||
if let WherePredicate::EqPredicate(predicate) = predicate {
|
let span = predicate.span;
|
||||||
deny_equality_constraints(self, predicate, generics);
|
if let WherePredicateKind::EqPredicate(predicate) = &predicate.kind {
|
||||||
|
deny_equality_constraints(self, predicate, span, generics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
walk_list!(self, visit_generic_param, &generics.params);
|
walk_list!(self, visit_generic_param, &generics.params);
|
||||||
for predicate in &generics.where_clause.predicates {
|
for predicate in &generics.where_clause.predicates {
|
||||||
match predicate {
|
match &predicate.kind {
|
||||||
WherePredicate::BoundPredicate(bound_pred) => {
|
WherePredicateKind::BoundPredicate(bound_pred) => {
|
||||||
// This is slightly complicated. Our representation for poly-trait-refs contains a single
|
// This is slightly complicated. Our representation for poly-trait-refs contains a single
|
||||||
// binder and thus we only allow a single level of quantification. However,
|
// binder and thus we only allow a single level of quantification. However,
|
||||||
// the syntax of Rust permits quantification in two places in where clauses,
|
// the syntax of Rust permits quantification in two places in where clauses,
|
||||||
|
@ -1476,14 +1476,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
{
|
{
|
||||||
self.visit_vis(&item.vis);
|
self.visit_vis(&item.vis);
|
||||||
self.visit_ident(&item.ident);
|
self.visit_ident(&item.ident);
|
||||||
let kind = FnKind::Fn(
|
let kind =
|
||||||
FnCtxt::Assoc(ctxt),
|
FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, sig, &item.vis, generics, body);
|
||||||
item.ident,
|
|
||||||
sig,
|
|
||||||
&item.vis,
|
|
||||||
generics,
|
|
||||||
body.as_deref(),
|
|
||||||
);
|
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
walk_list!(self, visit_attribute, &item.attrs);
|
||||||
self.visit_fn(kind, item.span, item.id);
|
self.visit_fn(kind, item.span, item.id);
|
||||||
}
|
}
|
||||||
|
@ -1511,9 +1505,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
fn deny_equality_constraints(
|
fn deny_equality_constraints(
|
||||||
this: &AstValidator<'_>,
|
this: &AstValidator<'_>,
|
||||||
predicate: &WhereEqPredicate,
|
predicate: &WhereEqPredicate,
|
||||||
|
predicate_span: Span,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
) {
|
) {
|
||||||
let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None };
|
let mut err = errors::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None };
|
||||||
|
|
||||||
// Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
// Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||||
if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind
|
if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind
|
||||||
|
@ -1557,7 +1552,7 @@ fn deny_equality_constraints(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err.assoc = Some(errors::AssociatedSuggestion {
|
err.assoc = Some(errors::AssociatedSuggestion {
|
||||||
span: predicate.span,
|
span: predicate_span,
|
||||||
ident: *ident,
|
ident: *ident,
|
||||||
param: param.ident,
|
param: param.ident,
|
||||||
path: pprust::path_to_string(&assoc_path),
|
path: pprust::path_to_string(&assoc_path),
|
||||||
|
@ -1587,23 +1582,23 @@ fn deny_equality_constraints(
|
||||||
// We're removing th eonly where bound left, remove the whole thing.
|
// We're removing th eonly where bound left, remove the whole thing.
|
||||||
generics.where_clause.span
|
generics.where_clause.span
|
||||||
} else {
|
} else {
|
||||||
let mut span = predicate.span;
|
let mut span = predicate_span;
|
||||||
let mut prev: Option<Span> = None;
|
let mut prev: Option<Span> = None;
|
||||||
let mut preds = generics.where_clause.predicates.iter().peekable();
|
let mut preds = generics.where_clause.predicates.iter().peekable();
|
||||||
// Find the predicate that shouldn't have been in the where bound list.
|
// Find the predicate that shouldn't have been in the where bound list.
|
||||||
while let Some(pred) = preds.next() {
|
while let Some(pred) = preds.next() {
|
||||||
if let WherePredicate::EqPredicate(pred) = pred
|
if let WherePredicateKind::EqPredicate(_) = pred.kind
|
||||||
&& pred.span == predicate.span
|
&& pred.span == predicate_span
|
||||||
{
|
{
|
||||||
if let Some(next) = preds.peek() {
|
if let Some(next) = preds.peek() {
|
||||||
// This is the first predicate, remove the trailing comma as well.
|
// This is the first predicate, remove the trailing comma as well.
|
||||||
span = span.with_hi(next.span().lo());
|
span = span.with_hi(next.span.lo());
|
||||||
} else if let Some(prev) = prev {
|
} else if let Some(prev) = prev {
|
||||||
// Remove the previous comma as well.
|
// Remove the previous comma as well.
|
||||||
span = span.with_lo(prev.hi());
|
span = span.with_lo(prev.hi());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prev = Some(pred.span());
|
prev = Some(pred.span);
|
||||||
}
|
}
|
||||||
span
|
span
|
||||||
};
|
};
|
||||||
|
@ -1620,8 +1615,8 @@ fn deny_equality_constraints(
|
||||||
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
|
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
|
||||||
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||||
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
|
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
|
||||||
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
|
generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
|
||||||
WherePredicate::BoundPredicate(p) => Some(&p.bounds),
|
WherePredicateKind::BoundPredicate(p) => Some(&p.bounds),
|
||||||
_ => None,
|
_ => None,
|
||||||
}),
|
}),
|
||||||
) {
|
) {
|
||||||
|
@ -1644,8 +1639,8 @@ fn deny_equality_constraints(
|
||||||
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||||
if let [potential_param, potential_assoc] = &full_path.segments[..] {
|
if let [potential_param, potential_assoc] = &full_path.segments[..] {
|
||||||
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
|
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
|
||||||
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
|
generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
|
||||||
WherePredicate::BoundPredicate(p)
|
WherePredicateKind::BoundPredicate(p)
|
||||||
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
|
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
|
||||||
&& let [segment] = &path.segments[..] =>
|
&& let [segment] = &path.segments[..] =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -594,8 +594,8 @@ pub(crate) struct ConstBoundTraitObject {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(effects): Consider making the note/reason the message of the diagnostic.
|
// FIXME(const_trait_impl): Consider making the note/reason the message of the diagnostic.
|
||||||
// FIXME(effects): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here).
|
// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here).
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(ast_passes_tilde_const_disallowed)]
|
#[diag(ast_passes_tilde_const_disallowed)]
|
||||||
pub(crate) struct TildeConstDisallowed {
|
pub(crate) struct TildeConstDisallowed {
|
||||||
|
|
|
@ -204,6 +204,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
"meant for internal use only" {
|
"meant for internal use only" {
|
||||||
keyword => rustdoc_internals
|
keyword => rustdoc_internals
|
||||||
fake_variadic => rustdoc_internals
|
fake_variadic => rustdoc_internals
|
||||||
|
search_unbox => rustdoc_internals
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -344,8 +345,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
|
|
||||||
fn visit_generics(&mut self, g: &'a ast::Generics) {
|
fn visit_generics(&mut self, g: &'a ast::Generics) {
|
||||||
for predicate in &g.where_clause.predicates {
|
for predicate in &g.where_clause.predicates {
|
||||||
match predicate {
|
match &predicate.kind {
|
||||||
ast::WherePredicate::BoundPredicate(bound_pred) => {
|
ast::WherePredicateKind::BoundPredicate(bound_pred) => {
|
||||||
// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||||
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
|
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
|
||||||
}
|
}
|
||||||
|
@ -522,9 +523,18 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
"consider removing `for<...>`"
|
"consider removing `for<...>`"
|
||||||
);
|
);
|
||||||
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
|
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
|
||||||
for &span in spans.get(&sym::yield_expr).iter().copied().flatten() {
|
// yield can be enabled either by `coroutines` or `gen_blocks`
|
||||||
if !span.at_least_rust_2024() {
|
if let Some(spans) = spans.get(&sym::yield_expr) {
|
||||||
gate!(&visitor, coroutines, span, "yield syntax is experimental");
|
for span in spans {
|
||||||
|
if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines))
|
||||||
|
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
|
||||||
|
{
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
// Don't know which of the two features to include in the
|
||||||
|
// error message, so I am arbitrarily picking one.
|
||||||
|
feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gate_all!(gen_blocks, "gen blocks are experimental");
|
gate_all!(gen_blocks, "gen blocks are experimental");
|
||||||
|
@ -547,6 +557,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
gate_all!(global_registration, "global registration is experimental");
|
gate_all!(global_registration, "global registration is experimental");
|
||||||
gate_all!(return_type_notation, "return type notation is experimental");
|
gate_all!(return_type_notation, "return type notation is experimental");
|
||||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||||
|
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
|
||||||
|
|
||||||
if !visitor.features.never_patterns() {
|
if !visitor.features.never_patterns() {
|
||||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
pub mod ast_validation;
|
pub mod ast_validation;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub mod feature_gate;
|
pub mod feature_gate;
|
||||||
pub mod node_count;
|
|
||||||
pub mod show_span;
|
pub mod show_span;
|
||||||
|
|
||||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
// Simply gives a rough count of the number of nodes in an AST.
|
|
||||||
|
|
||||||
use rustc_ast::visit::*;
|
|
||||||
use rustc_ast::*;
|
|
||||||
use rustc_span::Span;
|
|
||||||
use rustc_span::symbol::Ident;
|
|
||||||
|
|
||||||
pub struct NodeCounter {
|
|
||||||
pub count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeCounter {
|
|
||||||
pub fn new() -> NodeCounter {
|
|
||||||
NodeCounter { count: 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast> Visitor<'ast> for NodeCounter {
|
|
||||||
fn visit_ident(&mut self, _ident: &Ident) {
|
|
||||||
self.count += 1;
|
|
||||||
}
|
|
||||||
fn visit_foreign_item(&mut self, i: &ForeignItem) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_item(self, i)
|
|
||||||
}
|
|
||||||
fn visit_item(&mut self, i: &Item) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_item(self, i)
|
|
||||||
}
|
|
||||||
fn visit_local(&mut self, l: &Local) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_local(self, l)
|
|
||||||
}
|
|
||||||
fn visit_block(&mut self, b: &Block) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_block(self, b)
|
|
||||||
}
|
|
||||||
fn visit_stmt(&mut self, s: &Stmt) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_stmt(self, s)
|
|
||||||
}
|
|
||||||
fn visit_arm(&mut self, a: &Arm) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_arm(self, a)
|
|
||||||
}
|
|
||||||
fn visit_pat(&mut self, p: &Pat) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_pat(self, p)
|
|
||||||
}
|
|
||||||
fn visit_expr(&mut self, ex: &Expr) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_expr(self, ex)
|
|
||||||
}
|
|
||||||
fn visit_ty(&mut self, t: &Ty) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_ty(self, t)
|
|
||||||
}
|
|
||||||
fn visit_generic_param(&mut self, param: &GenericParam) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_generic_param(self, param)
|
|
||||||
}
|
|
||||||
fn visit_generics(&mut self, g: &Generics) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_generics(self, g)
|
|
||||||
}
|
|
||||||
fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: Span, _: NodeId) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_fn(self, fk)
|
|
||||||
}
|
|
||||||
fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_assoc_item(self, ti, ctxt);
|
|
||||||
}
|
|
||||||
fn visit_trait_ref(&mut self, t: &TraitRef) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_trait_ref(self, t)
|
|
||||||
}
|
|
||||||
fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_param_bound(self, bounds)
|
|
||||||
}
|
|
||||||
fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_poly_trait_ref(self, t)
|
|
||||||
}
|
|
||||||
fn visit_variant_data(&mut self, s: &VariantData) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_struct_def(self, s)
|
|
||||||
}
|
|
||||||
fn visit_field_def(&mut self, s: &FieldDef) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_field_def(self, s)
|
|
||||||
}
|
|
||||||
fn visit_enum_def(&mut self, enum_definition: &EnumDef) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_enum_def(self, enum_definition)
|
|
||||||
}
|
|
||||||
fn visit_variant(&mut self, v: &Variant) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_variant(self, v)
|
|
||||||
}
|
|
||||||
fn visit_lifetime(&mut self, lifetime: &Lifetime, _: visit::LifetimeCtxt) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_lifetime(self, lifetime)
|
|
||||||
}
|
|
||||||
fn visit_mac_call(&mut self, mac: &MacCall) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_mac(self, mac)
|
|
||||||
}
|
|
||||||
fn visit_path(&mut self, path: &Path, _id: NodeId) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_path(self, path)
|
|
||||||
}
|
|
||||||
fn visit_use_tree(&mut self, use_tree: &UseTree, id: NodeId, _nested: bool) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_use_tree(self, use_tree, id)
|
|
||||||
}
|
|
||||||
fn visit_generic_args(&mut self, generic_args: &GenericArgs) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_generic_args(self, generic_args)
|
|
||||||
}
|
|
||||||
fn visit_assoc_item_constraint(&mut self, constraint: &AssocItemConstraint) {
|
|
||||||
self.count += 1;
|
|
||||||
walk_assoc_item_constraint(self, constraint)
|
|
||||||
}
|
|
||||||
fn visit_attribute(&mut self, _attr: &Attribute) {
|
|
||||||
self.count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -942,9 +942,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
token::CloseDelim(Delimiter::Bracket) => "]".into(),
|
token::CloseDelim(Delimiter::Bracket) => "]".into(),
|
||||||
token::OpenDelim(Delimiter::Brace) => "{".into(),
|
token::OpenDelim(Delimiter::Brace) => "{".into(),
|
||||||
token::CloseDelim(Delimiter::Brace) => "}".into(),
|
token::CloseDelim(Delimiter::Brace) => "}".into(),
|
||||||
token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
|
token::OpenDelim(Delimiter::Invisible(_))
|
||||||
"".into()
|
| token::CloseDelim(Delimiter::Invisible(_)) => "".into(),
|
||||||
}
|
|
||||||
token::Pound => "#".into(),
|
token::Pound => "#".into(),
|
||||||
token::Dollar => "$".into(),
|
token::Dollar => "$".into(),
|
||||||
token::Question => "?".into(),
|
token::Question => "?".into(),
|
||||||
|
|
|
@ -59,7 +59,7 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
|
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
|
||||||
self.print_expr_cond_paren(expr, expr.precedence().order() < prec, fixup);
|
self.print_expr_cond_paren(expr, expr.precedence() < prec, fixup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||||
|
@ -615,7 +615,7 @@ impl<'a> State<'a> {
|
||||||
expr,
|
expr,
|
||||||
// Parenthesize if required by precedence, or in the
|
// Parenthesize if required by precedence, or in the
|
||||||
// case of `break 'inner: loop { break 'inner 1 } + 1`
|
// case of `break 'inner: loop { break 'inner 1 } + 1`
|
||||||
expr.precedence().order() < parser::PREC_JUMP
|
expr.precedence() < parser::PREC_JUMP
|
||||||
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
||||||
fixup.subsequent_subexpression(),
|
fixup.subsequent_subexpression(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -191,6 +191,6 @@ impl FixupContext {
|
||||||
/// "let chain".
|
/// "let chain".
|
||||||
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
|
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
|
||||||
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|
||||||
|| parser::needs_par_as_let_scrutinee(expr.precedence().order())
|
|| parser::needs_par_as_let_scrutinee(expr.precedence())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -726,11 +726,12 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
|
pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
|
||||||
match predicate {
|
let ast::WherePredicate { kind, id: _, span: _ } = predicate;
|
||||||
ast::WherePredicate::BoundPredicate(where_bound_predicate) => {
|
match kind {
|
||||||
|
ast::WherePredicateKind::BoundPredicate(where_bound_predicate) => {
|
||||||
self.print_where_bound_predicate(where_bound_predicate);
|
self.print_where_bound_predicate(where_bound_predicate);
|
||||||
}
|
}
|
||||||
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate {
|
||||||
lifetime,
|
lifetime,
|
||||||
bounds,
|
bounds,
|
||||||
..
|
..
|
||||||
|
@ -742,7 +743,9 @@ impl<'a> State<'a> {
|
||||||
self.print_lifetime_bounds(bounds);
|
self.print_lifetime_bounds(bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
|
ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate {
|
||||||
|
lhs_ty, rhs_ty, ..
|
||||||
|
}) => {
|
||||||
self.print_type(lhs_ty);
|
self.print_type(lhs_ty);
|
||||||
self.space();
|
self.space();
|
||||||
self.word_space("=");
|
self.word_space("=");
|
||||||
|
|
|
@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag;
|
||||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_session::{RustcVersion, Session};
|
use rustc_session::{RustcVersion, Session};
|
||||||
|
use rustc_span::Span;
|
||||||
use rustc_span::hygiene::Transparency;
|
use rustc_span::hygiene::Transparency;
|
||||||
use rustc_span::symbol::{Symbol, kw, sym};
|
use rustc_span::symbol::{Symbol, kw, sym};
|
||||||
use rustc_span::{DUMMY_SP, Span};
|
|
||||||
|
|
||||||
use crate::fluent_generated;
|
use crate::fluent_generated;
|
||||||
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||||
|
@ -92,9 +92,7 @@ impl Stability {
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic)]
|
||||||
pub struct ConstStability {
|
pub struct ConstStability {
|
||||||
pub level: StabilityLevel,
|
pub level: StabilityLevel,
|
||||||
/// This can be `None` for functions that do not have an explicit const feature.
|
pub feature: Symbol,
|
||||||
/// We still track them for recursive const stability checks.
|
|
||||||
pub feature: Option<Symbol>,
|
|
||||||
/// This is true iff the `const_stable_indirect` attribute is present.
|
/// This is true iff the `const_stable_indirect` attribute is present.
|
||||||
pub const_stable_indirect: bool,
|
pub const_stable_indirect: bool,
|
||||||
/// whether the function has a `#[rustc_promotable]` attribute
|
/// whether the function has a `#[rustc_promotable]` attribute
|
||||||
|
@ -272,23 +270,19 @@ pub fn find_stability(
|
||||||
|
|
||||||
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
|
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
|
||||||
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
|
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
|
||||||
///
|
|
||||||
/// `is_const_fn` indicates whether this is a function marked as `const`. It will always
|
|
||||||
/// be false for intrinsics in an `extern` block!
|
|
||||||
pub fn find_const_stability(
|
pub fn find_const_stability(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
attrs: &[Attribute],
|
attrs: &[Attribute],
|
||||||
item_sp: Span,
|
item_sp: Span,
|
||||||
is_const_fn: bool,
|
|
||||||
) -> Option<(ConstStability, Span)> {
|
) -> Option<(ConstStability, Span)> {
|
||||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||||
let mut promotable = false;
|
let mut promotable = false;
|
||||||
let mut const_stable_indirect = None;
|
let mut const_stable_indirect = false;
|
||||||
|
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
match attr.name_or_empty() {
|
match attr.name_or_empty() {
|
||||||
sym::rustc_promotable => promotable = true,
|
sym::rustc_promotable => promotable = true,
|
||||||
sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
|
sym::rustc_const_stable_indirect => const_stable_indirect = true,
|
||||||
sym::rustc_const_unstable => {
|
sym::rustc_const_unstable => {
|
||||||
if const_stab.is_some() {
|
if const_stab.is_some() {
|
||||||
sess.dcx()
|
sess.dcx()
|
||||||
|
@ -300,7 +294,7 @@ pub fn find_const_stability(
|
||||||
const_stab = Some((
|
const_stab = Some((
|
||||||
ConstStability {
|
ConstStability {
|
||||||
level,
|
level,
|
||||||
feature: Some(feature),
|
feature,
|
||||||
const_stable_indirect: false,
|
const_stable_indirect: false,
|
||||||
promotable: false,
|
promotable: false,
|
||||||
},
|
},
|
||||||
|
@ -318,7 +312,7 @@ pub fn find_const_stability(
|
||||||
const_stab = Some((
|
const_stab = Some((
|
||||||
ConstStability {
|
ConstStability {
|
||||||
level,
|
level,
|
||||||
feature: Some(feature),
|
feature,
|
||||||
const_stable_indirect: false,
|
const_stable_indirect: false,
|
||||||
promotable: false,
|
promotable: false,
|
||||||
},
|
},
|
||||||
|
@ -330,7 +324,7 @@ pub fn find_const_stability(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge promotable and not_exposed_on_stable into stability info
|
// Merge promotable and const_stable_indirect into stability info
|
||||||
if promotable {
|
if promotable {
|
||||||
match &mut const_stab {
|
match &mut const_stab {
|
||||||
Some((stab, _)) => stab.promotable = promotable,
|
Some((stab, _)) => stab.promotable = promotable,
|
||||||
|
@ -341,7 +335,7 @@ pub fn find_const_stability(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if const_stable_indirect.is_some() {
|
if const_stable_indirect {
|
||||||
match &mut const_stab {
|
match &mut const_stab {
|
||||||
Some((stab, _)) => {
|
Some((stab, _)) => {
|
||||||
if stab.is_const_unstable() {
|
if stab.is_const_unstable() {
|
||||||
|
@ -353,38 +347,36 @@ pub fn find_const_stability(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
|
// This function has no const stability attribute, but has `const_stable_indirect`.
|
||||||
// the `default_const_unstable` logic.
|
// We ignore that; unmarked functions are subject to recursive const stability
|
||||||
|
// checks by default so we do carry out the user's intent.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
|
|
||||||
// fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
|
|
||||||
// stability checks for them. We need to do this because the default for whether an unmarked
|
|
||||||
// function enforces recursive stability differs between staged-api crates and force-unmarked
|
|
||||||
// crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
|
|
||||||
// enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
|
|
||||||
// assume the function does not have recursive stability. All functions that *do* have recursive
|
|
||||||
// stability must explicitly record this, and so that's what we do for all `const fn` in a
|
|
||||||
// staged_api crate.
|
|
||||||
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
|
|
||||||
let c = ConstStability {
|
|
||||||
feature: None,
|
|
||||||
const_stable_indirect: const_stable_indirect.is_some(),
|
|
||||||
promotable: false,
|
|
||||||
level: StabilityLevel::Unstable {
|
|
||||||
reason: UnstableReason::Default,
|
|
||||||
issue: None,
|
|
||||||
is_soft: false,
|
|
||||||
implied_by: None,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
|
|
||||||
}
|
|
||||||
|
|
||||||
const_stab
|
const_stab
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate
|
||||||
|
/// without the `staged_api` feature.
|
||||||
|
pub fn unmarked_crate_const_stab(
|
||||||
|
_sess: &Session,
|
||||||
|
attrs: &[Attribute],
|
||||||
|
regular_stab: Stability,
|
||||||
|
) -> ConstStability {
|
||||||
|
assert!(regular_stab.level.is_unstable());
|
||||||
|
// The only attribute that matters here is `rustc_const_stable_indirect`.
|
||||||
|
// We enforce recursive const stability rules for those functions.
|
||||||
|
let const_stable_indirect =
|
||||||
|
attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect);
|
||||||
|
ConstStability {
|
||||||
|
feature: regular_stab.feature,
|
||||||
|
const_stable_indirect,
|
||||||
|
promotable: false,
|
||||||
|
level: regular_stab.level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
|
/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
|
||||||
/// Returns `None` if no stability attributes are found.
|
/// Returns `None` if no stability attributes are found.
|
||||||
pub fn find_body_stability(
|
pub fn find_body_stability(
|
||||||
|
|
|
@ -8,11 +8,6 @@ edition = "2021"
|
||||||
icu_list = "1.2"
|
icu_list = "1.2"
|
||||||
icu_locid = "1.2"
|
icu_locid = "1.2"
|
||||||
icu_locid_transform = "1.3.2"
|
icu_locid_transform = "1.3.2"
|
||||||
icu_provider = "1.2"
|
icu_provider = { version = "1.2", features = ["sync"] }
|
||||||
zerovec = "0.10.0"
|
zerovec = "0.10.0"
|
||||||
# tidy-alphabetical-end
|
# tidy-alphabetical-end
|
||||||
|
|
||||||
[features]
|
|
||||||
# tidy-alphabetical-start
|
|
||||||
rustc_use_parallel_compiler = ['icu_provider/sync']
|
|
||||||
# tidy-alphabetical-end
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
either = "1.5.0"
|
either = "1.5.0"
|
||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
polonius-engine = "0.13.0"
|
polonius-engine = "0.13.0"
|
||||||
|
rustc_abi = { path = "../rustc_abi" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
|
@ -21,7 +22,6 @@ rustc_middle = { path = "../rustc_middle" }
|
||||||
rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
|
rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
|
||||||
rustc_session = { path = "../rustc_session" }
|
rustc_session = { path = "../rustc_session" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
rustc_target = { path = "../rustc_target" }
|
|
||||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||||
rustc_traits = { path = "../rustc_traits" }
|
rustc_traits = { path = "../rustc_traits" }
|
||||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||||
|
|
|
@ -20,18 +20,18 @@ pub struct BorrowSet<'tcx> {
|
||||||
/// by the `Location` of the assignment statement in which it
|
/// by the `Location` of the assignment statement in which it
|
||||||
/// appears on the right hand side. Thus the location is the map
|
/// appears on the right hand side. Thus the location is the map
|
||||||
/// key, and its position in the map corresponds to `BorrowIndex`.
|
/// key, and its position in the map corresponds to `BorrowIndex`.
|
||||||
pub location_map: FxIndexMap<Location, BorrowData<'tcx>>,
|
pub(crate) location_map: FxIndexMap<Location, BorrowData<'tcx>>,
|
||||||
|
|
||||||
/// Locations which activate borrows.
|
/// Locations which activate borrows.
|
||||||
/// NOTE: a given location may activate more than one borrow in the future
|
/// NOTE: a given location may activate more than one borrow in the future
|
||||||
/// when more general two-phase borrow support is introduced, but for now we
|
/// when more general two-phase borrow support is introduced, but for now we
|
||||||
/// only need to store one borrow index.
|
/// only need to store one borrow index.
|
||||||
pub activation_map: FxIndexMap<Location, Vec<BorrowIndex>>,
|
pub(crate) activation_map: FxIndexMap<Location, Vec<BorrowIndex>>,
|
||||||
|
|
||||||
/// Map from local to all the borrows on that local.
|
/// Map from local to all the borrows on that local.
|
||||||
pub local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
|
pub(crate) local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
|
||||||
|
|
||||||
pub locals_state_at_exit: LocalsStateAtExit,
|
pub(crate) locals_state_at_exit: LocalsStateAtExit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
|
impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
|
||||||
|
@ -45,7 +45,7 @@ impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
|
||||||
/// Location where a two-phase borrow is activated, if a borrow
|
/// Location where a two-phase borrow is activated, if a borrow
|
||||||
/// is in fact a two-phase borrow.
|
/// is in fact a two-phase borrow.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum TwoPhaseActivation {
|
pub(crate) enum TwoPhaseActivation {
|
||||||
NotTwoPhase,
|
NotTwoPhase,
|
||||||
NotActivated,
|
NotActivated,
|
||||||
ActivatedAt(Location),
|
ActivatedAt(Location),
|
||||||
|
@ -55,17 +55,17 @@ pub enum TwoPhaseActivation {
|
||||||
pub struct BorrowData<'tcx> {
|
pub struct BorrowData<'tcx> {
|
||||||
/// Location where the borrow reservation starts.
|
/// Location where the borrow reservation starts.
|
||||||
/// In many cases, this will be equal to the activation location but not always.
|
/// In many cases, this will be equal to the activation location but not always.
|
||||||
pub reserve_location: Location,
|
pub(crate) reserve_location: Location,
|
||||||
/// Location where the borrow is activated.
|
/// Location where the borrow is activated.
|
||||||
pub activation_location: TwoPhaseActivation,
|
pub(crate) activation_location: TwoPhaseActivation,
|
||||||
/// What kind of borrow this is
|
/// What kind of borrow this is
|
||||||
pub kind: mir::BorrowKind,
|
pub(crate) kind: mir::BorrowKind,
|
||||||
/// The region for which this borrow is live
|
/// The region for which this borrow is live
|
||||||
pub region: RegionVid,
|
pub(crate) region: RegionVid,
|
||||||
/// Place from which we are borrowing
|
/// Place from which we are borrowing
|
||||||
pub borrowed_place: mir::Place<'tcx>,
|
pub(crate) borrowed_place: mir::Place<'tcx>,
|
||||||
/// Place to which the borrow was stored
|
/// Place to which the borrow was stored
|
||||||
pub assigned_place: mir::Place<'tcx>,
|
pub(crate) assigned_place: mir::Place<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
||||||
|
@ -120,7 +120,7 @@ impl LocalsStateAtExit {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> BorrowSet<'tcx> {
|
impl<'tcx> BorrowSet<'tcx> {
|
||||||
pub fn build(
|
pub(crate) fn build(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
locals_are_invalidated_at_exit: bool,
|
locals_are_invalidated_at_exit: bool,
|
||||||
|
@ -156,7 +156,7 @@ impl<'tcx> BorrowSet<'tcx> {
|
||||||
self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
|
self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub(crate) fn len(&self) -> usize {
|
||||||
self.location_map.len()
|
self.location_map.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,7 +210,7 @@ impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
#[debug_format = "OutlivesConstraintIndex({})"]
|
#[debug_format = "OutlivesConstraintIndex({})"]
|
||||||
pub struct OutlivesConstraintIndex {}
|
pub(crate) struct OutlivesConstraintIndex {}
|
||||||
}
|
}
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
|
|
|
@ -1,93 +1,171 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_data_structures::graph;
|
use rustc_data_structures::graph;
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges};
|
use rustc_middle::mir::{
|
||||||
|
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
|
||||||
|
};
|
||||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||||
use rustc_mir_dataflow::fmt::DebugWithContext;
|
use rustc_mir_dataflow::fmt::DebugWithContext;
|
||||||
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
||||||
use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable};
|
use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
|
use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
|
||||||
|
|
||||||
/// The results of the dataflow analyses used by the borrow checker.
|
// This analysis is different to most others. Its results aren't computed with
|
||||||
pub(crate) struct BorrowckResults<'a, 'tcx> {
|
// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are
|
||||||
pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>,
|
// computed individually with `iterate_to_fixpoint`.
|
||||||
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>,
|
pub(crate) struct Borrowck<'a, 'tcx> {
|
||||||
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>,
|
pub(crate) borrows: Borrows<'a, 'tcx>,
|
||||||
|
pub(crate) uninits: MaybeUninitializedPlaces<'a, 'tcx>,
|
||||||
|
pub(crate) ever_inits: EverInitializedPlaces<'a, 'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
||||||
|
type Domain = BorrowckDomain<'a, 'tcx>;
|
||||||
|
|
||||||
|
const NAME: &'static str = "borrowck";
|
||||||
|
|
||||||
|
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
||||||
|
BorrowckDomain {
|
||||||
|
borrows: self.borrows.bottom_value(body),
|
||||||
|
uninits: self.uninits.bottom_value(body),
|
||||||
|
ever_inits: self.ever_inits.bottom_value(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) {
|
||||||
|
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_before_statement_effect(
|
||||||
|
&mut self,
|
||||||
|
state: &mut Self::Domain,
|
||||||
|
stmt: &mir::Statement<'tcx>,
|
||||||
|
loc: Location,
|
||||||
|
) {
|
||||||
|
self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc);
|
||||||
|
self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc);
|
||||||
|
self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_statement_effect(
|
||||||
|
&mut self,
|
||||||
|
state: &mut Self::Domain,
|
||||||
|
stmt: &mir::Statement<'tcx>,
|
||||||
|
loc: Location,
|
||||||
|
) {
|
||||||
|
self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc);
|
||||||
|
self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc);
|
||||||
|
self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_before_terminator_effect(
|
||||||
|
&mut self,
|
||||||
|
state: &mut Self::Domain,
|
||||||
|
term: &mir::Terminator<'tcx>,
|
||||||
|
loc: Location,
|
||||||
|
) {
|
||||||
|
self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc);
|
||||||
|
self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc);
|
||||||
|
self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_terminator_effect<'mir>(
|
||||||
|
&mut self,
|
||||||
|
state: &mut Self::Domain,
|
||||||
|
term: &'mir mir::Terminator<'tcx>,
|
||||||
|
loc: Location,
|
||||||
|
) -> TerminatorEdges<'mir, 'tcx> {
|
||||||
|
self.borrows.apply_terminator_effect(&mut state.borrows, term, loc);
|
||||||
|
self.uninits.apply_terminator_effect(&mut state.uninits, term, loc);
|
||||||
|
self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc);
|
||||||
|
|
||||||
|
// This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
|
||||||
|
// analysis doesn't use.
|
||||||
|
TerminatorEdges::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_call_return_effect(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut Self::Domain,
|
||||||
|
_block: BasicBlock,
|
||||||
|
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
) {
|
||||||
|
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_switch_int_edge_effects(
|
||||||
|
&mut self,
|
||||||
|
_block: BasicBlock,
|
||||||
|
_discr: &mir::Operand<'tcx>,
|
||||||
|
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
||||||
|
) {
|
||||||
|
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JoinSemiLattice for BorrowckDomain<'_, '_> {
|
||||||
|
fn join(&mut self, _other: &Self) -> bool {
|
||||||
|
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx>
|
||||||
|
where
|
||||||
|
C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
|
||||||
|
{
|
||||||
|
fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("borrows: ")?;
|
||||||
|
self.borrows.fmt_with(ctxt, f)?;
|
||||||
|
f.write_str(" uninits: ")?;
|
||||||
|
self.uninits.fmt_with(ctxt, f)?;
|
||||||
|
f.write_str(" ever_inits: ")?;
|
||||||
|
self.ever_inits.fmt_with(ctxt, f)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if self == old {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.borrows != old.borrows {
|
||||||
|
f.write_str("borrows: ")?;
|
||||||
|
self.borrows.fmt_diff_with(&old.borrows, ctxt, f)?;
|
||||||
|
f.write_str("\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.uninits != old.uninits {
|
||||||
|
f.write_str("uninits: ")?;
|
||||||
|
self.uninits.fmt_diff_with(&old.uninits, ctxt, f)?;
|
||||||
|
f.write_str("\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ever_inits != old.ever_inits {
|
||||||
|
f.write_str("ever_inits: ")?;
|
||||||
|
self.ever_inits.fmt_diff_with(&old.ever_inits, ctxt, f)?;
|
||||||
|
f.write_str("\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The transient state of the dataflow analyses used by the borrow checker.
|
/// The transient state of the dataflow analyses used by the borrow checker.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub(crate) struct BorrowckDomain<'a, 'tcx> {
|
pub(crate) struct BorrowckDomain<'a, 'tcx> {
|
||||||
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||||
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||||
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
|
|
||||||
type Direction = Forward;
|
|
||||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
|
||||||
|
|
||||||
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::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));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_before_statement_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
stmt: &mir::Statement<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
|
|
||||||
self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
|
|
||||||
self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_statement_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
stmt: &mir::Statement<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
|
|
||||||
self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
|
|
||||||
self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_before_terminator_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
term: &mir::Terminator<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
|
|
||||||
self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
|
|
||||||
self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_terminator_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
term: &mir::Terminator<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
|
|
||||||
self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
|
|
||||||
self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
#[orderable]
|
#[orderable]
|
||||||
#[debug_format = "bw{}"]
|
#[debug_format = "bw{}"]
|
||||||
|
@ -254,8 +332,8 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
|
||||||
let sccs = self.regioncx.constraint_sccs();
|
let sccs = self.regioncx.constraint_sccs();
|
||||||
let universal_regions = self.regioncx.universal_regions();
|
let universal_regions = self.regioncx.universal_regions();
|
||||||
|
|
||||||
// We first handle the cases where the loan doesn't go out of scope, depending on the issuing
|
// We first handle the cases where the loan doesn't go out of scope, depending on the
|
||||||
// region's successors.
|
// issuing region's successors.
|
||||||
for successor in graph::depth_first_search(&self.regioncx.region_graph(), issuing_region) {
|
for successor in graph::depth_first_search(&self.regioncx.region_graph(), issuing_region) {
|
||||||
// 1. Via applied member constraints
|
// 1. Via applied member constraints
|
||||||
//
|
//
|
||||||
|
@ -563,6 +641,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
||||||
| mir::StatementKind::Coverage(..)
|
| mir::StatementKind::Coverage(..)
|
||||||
| mir::StatementKind::Intrinsic(..)
|
| mir::StatementKind::Intrinsic(..)
|
||||||
| mir::StatementKind::ConstEvalCounter
|
| mir::StatementKind::ConstEvalCounter
|
||||||
|
| mir::StatementKind::BackwardIncompatibleDropHint { .. }
|
||||||
| mir::StatementKind::Nop => {}
|
| mir::StatementKind::Nop => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use rustc_errors::Diag;
|
use rustc_errors::Diag;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_infer::infer::canonical::CanonicalQueryInput;
|
|
||||||
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
|
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||||
use rustc_infer::infer::{
|
use rustc_infer::infer::{
|
||||||
InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _,
|
InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _,
|
||||||
|
@ -21,7 +20,6 @@ use rustc_span::Span;
|
||||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||||
use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError;
|
use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError;
|
||||||
use rustc_trait_selection::traits::ObligationCtxt;
|
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 rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
@ -31,12 +29,9 @@ use crate::session_diagnostics::{
|
||||||
HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
|
HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(crate) struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
|
|
||||||
|
|
||||||
/// What operation a universe was created for.
|
/// What operation a universe was created for.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum UniverseInfoInner<'tcx> {
|
pub(crate) enum UniverseInfo<'tcx> {
|
||||||
/// Relating two types which have binders.
|
/// Relating two types which have binders.
|
||||||
RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
|
RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
|
||||||
/// Created from performing a `TypeOp`.
|
/// Created from performing a `TypeOp`.
|
||||||
|
@ -47,11 +42,11 @@ enum UniverseInfoInner<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> UniverseInfo<'tcx> {
|
impl<'tcx> UniverseInfo<'tcx> {
|
||||||
pub(crate) fn other() -> UniverseInfo<'tcx> {
|
pub(crate) fn other() -> UniverseInfo<'tcx> {
|
||||||
UniverseInfo(UniverseInfoInner::Other)
|
UniverseInfo::Other
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
|
pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
|
||||||
UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
|
UniverseInfo::RelateTys { expected, found }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn report_error(
|
pub(crate) fn report_error(
|
||||||
|
@ -61,21 +56,21 @@ impl<'tcx> UniverseInfo<'tcx> {
|
||||||
error_element: RegionElement,
|
error_element: RegionElement,
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
) {
|
) {
|
||||||
match self.0 {
|
match *self {
|
||||||
UniverseInfoInner::RelateTys { expected, found } => {
|
UniverseInfo::RelateTys { expected, found } => {
|
||||||
let err = mbcx.infcx.err_ctxt().report_mismatched_types(
|
let err = mbcx.infcx.err_ctxt().report_mismatched_types(
|
||||||
&cause,
|
&cause,
|
||||||
mbcx.param_env,
|
mbcx.infcx.param_env,
|
||||||
expected,
|
expected,
|
||||||
found,
|
found,
|
||||||
TypeError::RegionsPlaceholderMismatch,
|
TypeError::RegionsPlaceholderMismatch,
|
||||||
);
|
);
|
||||||
mbcx.buffer_error(err);
|
mbcx.buffer_error(err);
|
||||||
}
|
}
|
||||||
UniverseInfoInner::TypeOp(ref type_op_info) => {
|
UniverseInfo::TypeOp(ref type_op_info) => {
|
||||||
type_op_info.report_error(mbcx, placeholder, error_element, cause);
|
type_op_info.report_error(mbcx, placeholder, error_element, cause);
|
||||||
}
|
}
|
||||||
UniverseInfoInner::Other => {
|
UniverseInfo::Other => {
|
||||||
// FIXME: This error message isn't great, but it doesn't show
|
// FIXME: This error message isn't great, but it doesn't show
|
||||||
// up in the existing UI tests. Consider investigating this
|
// up in the existing UI tests. Consider investigating this
|
||||||
// some more.
|
// some more.
|
||||||
|
@ -93,19 +88,16 @@ pub(crate) trait ToUniverseInfo<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
||||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
|
UniverseInfo::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
|
||||||
base_universe: Some(base_universe),
|
base_universe: Some(base_universe),
|
||||||
..self
|
..self
|
||||||
})))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpProvePredicateGoal<'tcx> {
|
impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpProvePredicateGoal<'tcx> {
|
||||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
|
UniverseInfo::TypeOp(Rc::new(PredicateQuery { canonical_query: self, base_universe }))
|
||||||
canonical_query: self,
|
|
||||||
base_universe,
|
|
||||||
})))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,26 +105,13 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUnivers
|
||||||
for CanonicalTypeOpNormalizeGoal<'tcx, T>
|
for CanonicalTypeOpNormalizeGoal<'tcx, T>
|
||||||
{
|
{
|
||||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
|
UniverseInfo::TypeOp(Rc::new(NormalizeQuery { canonical_query: self, base_universe }))
|
||||||
canonical_query: self,
|
|
||||||
base_universe,
|
|
||||||
})))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpAscribeUserTypeGoal<'tcx> {
|
impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpAscribeUserTypeGoal<'tcx> {
|
||||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
|
UniverseInfo::TypeOp(Rc::new(AscribeUserTypeQuery { canonical_query: self, base_universe }))
|
||||||
canonical_query: self,
|
|
||||||
base_universe,
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx, F> ToUniverseInfo<'tcx> for CanonicalQueryInput<'tcx, type_op::custom::CustomTypeOp<F>> {
|
|
||||||
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
|
||||||
// We can't rerun custom type ops.
|
|
||||||
UniverseInfo::other()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +122,7 @@ impl<'tcx> ToUniverseInfo<'tcx> for ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_lifetimes)]
|
#[allow(unused_lifetimes)]
|
||||||
trait TypeOpInfo<'tcx> {
|
pub(crate) trait TypeOpInfo<'tcx> {
|
||||||
/// Returns an error to be reported if rerunning the type op fails to
|
/// Returns an error to be reported if rerunning the type op fails to
|
||||||
/// recover the error's cause.
|
/// recover the error's cause.
|
||||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx>;
|
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx>;
|
||||||
|
@ -289,8 +268,8 @@ where
|
||||||
// `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
|
// `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
|
||||||
// `ObligationCause`. The normalization results are currently different between
|
// `ObligationCause`. The normalization results are currently different between
|
||||||
// `QueryNormalizeExt::query_normalize` used in the query and `normalize` called below:
|
// `QueryNormalizeExt::query_normalize` used in the query and `normalize` called below:
|
||||||
// the former fails to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test.
|
// the former fails to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs`
|
||||||
// Check after #85499 lands to see if its fixes have erased this difference.
|
// test. Check after #85499 lands to see if its fixes have erased this difference.
|
||||||
let (param_env, value) = key.into_parts();
|
let (param_env, value) = key.into_parts();
|
||||||
let _ = ocx.normalize(&cause, param_env, value.value);
|
let _ = ocx.normalize(&cause, param_env, value.value);
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ use rustc_span::{BytePos, Span, Symbol};
|
||||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||||
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
@ -201,7 +202,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
|
|
||||||
let mut has_suggest_reborrow = false;
|
let mut has_suggest_reborrow = false;
|
||||||
if !seen_spans.contains(&move_span) {
|
if !seen_spans.contains(&move_span) {
|
||||||
if !closure {
|
|
||||||
self.suggest_ref_or_clone(
|
self.suggest_ref_or_clone(
|
||||||
mpi,
|
mpi,
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -209,8 +209,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
move_spans,
|
move_spans,
|
||||||
moved_place.as_ref(),
|
moved_place.as_ref(),
|
||||||
&mut has_suggest_reborrow,
|
&mut has_suggest_reborrow,
|
||||||
|
closure,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
let msg_opt = CapturedMessageOpt {
|
let msg_opt = CapturedMessageOpt {
|
||||||
is_partial_move,
|
is_partial_move,
|
||||||
|
@ -266,27 +266,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let opt_name = self.describe_place_with_options(place.as_ref(), DescribePlaceOpt {
|
if self.infcx.param_env.caller_bounds().iter().any(|c| {
|
||||||
including_downcast: true,
|
c.as_trait_clause().is_some_and(|pred| {
|
||||||
including_tuple_field: true,
|
pred.skip_binder().self_ty() == ty && self.infcx.tcx.is_fn_trait(pred.def_id())
|
||||||
});
|
})
|
||||||
let note_msg = match opt_name {
|
}) {
|
||||||
Some(name) => format!("`{name}`"),
|
|
||||||
None => "value".to_owned(),
|
|
||||||
};
|
|
||||||
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg)
|
|
||||||
|| if let UseSpans::FnSelfUse { kind, .. } = use_spans
|
|
||||||
&& let CallKind::FnCall { fn_trait_id, self_ty } = kind
|
|
||||||
&& let ty::Param(_) = self_ty.kind()
|
|
||||||
&& ty == self_ty
|
|
||||||
&& self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce)
|
|
||||||
{
|
|
||||||
// this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`.
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Suppress the next suggestion since we don't want to put more bounds onto
|
// Suppress the next suggestion since we don't want to put more bounds onto
|
||||||
// something that already has `Fn`-like bounds (or is a closure), so we can't
|
// something that already has `Fn`-like bounds (or is a closure), so we can't
|
||||||
// restrict anyways.
|
// restrict anyways.
|
||||||
|
@ -295,6 +279,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
self.suggest_adding_bounds(&mut err, ty, copy_did, span);
|
self.suggest_adding_bounds(&mut err, ty, copy_did, span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
};
|
||||||
if needs_note {
|
if needs_note {
|
||||||
if let Some(local) = place.as_local() {
|
if let Some(local) = place.as_local() {
|
||||||
let span = self.body.local_decls[local].source_info.span;
|
let span = self.body.local_decls[local].source_info.span;
|
||||||
|
@ -341,6 +333,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
move_spans: UseSpans<'tcx>,
|
move_spans: UseSpans<'tcx>,
|
||||||
moved_place: PlaceRef<'tcx>,
|
moved_place: PlaceRef<'tcx>,
|
||||||
has_suggest_reborrow: &mut bool,
|
has_suggest_reborrow: &mut bool,
|
||||||
|
moved_or_invoked_closure: bool,
|
||||||
) {
|
) {
|
||||||
let move_span = match move_spans {
|
let move_span = match move_spans {
|
||||||
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
|
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
|
||||||
|
@ -428,17 +421,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}
|
}
|
||||||
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
|
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
|
||||||
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
|
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
|
||||||
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
|
let (def_id, call_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
|
||||||
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
|
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
|
||||||
{
|
{
|
||||||
(typeck.type_dependent_def_id(parent_expr.hir_id), args, 1)
|
let def_id = typeck.type_dependent_def_id(parent_expr.hir_id);
|
||||||
|
(def_id, Some(parent_expr.hir_id), args, 1)
|
||||||
} else if let hir::Node::Expr(parent_expr) = parent
|
} else if let hir::Node::Expr(parent_expr) = parent
|
||||||
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
|
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
|
||||||
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
|
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
|
||||||
{
|
{
|
||||||
(Some(*def_id), args, 0)
|
(Some(*def_id), Some(call.hir_id), args, 0)
|
||||||
} else {
|
} else {
|
||||||
(None, &[][..], 0)
|
(None, None, &[][..], 0)
|
||||||
|
};
|
||||||
|
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||||
|
|
||||||
|
let mut can_suggest_clone = true;
|
||||||
|
if let Some(def_id) = def_id
|
||||||
|
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
||||||
|
{
|
||||||
|
// The move occurred as one of the arguments to a function call. Is that
|
||||||
|
// argument generic? `def_id` can't be a closure here, so using `fn_sig` is fine
|
||||||
|
let arg_param = if self.infcx.tcx.def_kind(def_id).is_fn_like()
|
||||||
|
&& let sig =
|
||||||
|
self.infcx.tcx.fn_sig(def_id).instantiate_identity().skip_binder()
|
||||||
|
&& let Some(arg_ty) = sig.inputs().get(pos + offset)
|
||||||
|
&& let ty::Param(arg_param) = arg_ty.kind()
|
||||||
|
{
|
||||||
|
Some(arg_param)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the moved value is a mut reference, it is used in a
|
// If the moved value is a mut reference, it is used in a
|
||||||
|
@ -447,85 +459,38 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
// for example:
|
// for example:
|
||||||
// struct Y(u32);
|
// struct Y(u32);
|
||||||
// x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
|
// x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
|
||||||
if let Some(def_id) = def_id
|
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind()
|
||||||
&& self.infcx.tcx.def_kind(def_id).is_fn_like()
|
&& arg_param.is_some()
|
||||||
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
|
||||||
&& let Some(arg) = self
|
|
||||||
.infcx
|
|
||||||
.tcx
|
|
||||||
.fn_sig(def_id)
|
|
||||||
.skip_binder()
|
|
||||||
.skip_binder()
|
|
||||||
.inputs()
|
|
||||||
.get(pos + offset)
|
|
||||||
&& let ty::Param(_) = arg.kind()
|
|
||||||
{
|
{
|
||||||
let place = &self.move_data.move_paths[mpi].place;
|
|
||||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
|
||||||
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
|
|
||||||
*has_suggest_reborrow = true;
|
*has_suggest_reborrow = true;
|
||||||
self.suggest_reborrow(err, expr.span, moved_place);
|
self.suggest_reborrow(err, expr.span, moved_place);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut can_suggest_clone = true;
|
// If the moved place is used generically by the callee and a reference to it
|
||||||
if let Some(def_id) = def_id
|
// would still satisfy any bounds on its type, suggest borrowing.
|
||||||
&& let Some(local_def_id) = def_id.as_local()
|
if let Some(¶m) = arg_param
|
||||||
|
&& let Some(generic_args) = call_id.and_then(|id| typeck.node_args_opt(id))
|
||||||
|
&& let Some(ref_mutability) = self.suggest_borrow_generic_arg(
|
||||||
|
err,
|
||||||
|
def_id,
|
||||||
|
generic_args,
|
||||||
|
param,
|
||||||
|
moved_place,
|
||||||
|
pos + offset,
|
||||||
|
ty,
|
||||||
|
expr.span,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
can_suggest_clone = ref_mutability.is_mut();
|
||||||
|
} else if let Some(local_def_id) = def_id.as_local()
|
||||||
&& let node = self.infcx.tcx.hir_node_by_def_id(local_def_id)
|
&& let node = self.infcx.tcx.hir_node_by_def_id(local_def_id)
|
||||||
&& let Some(fn_sig) = node.fn_sig()
|
&& let Some(fn_decl) = node.fn_decl()
|
||||||
&& let Some(ident) = node.ident()
|
&& let Some(ident) = node.ident()
|
||||||
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
&& let Some(arg) = fn_decl.inputs.get(pos + offset)
|
||||||
&& let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
|
|
||||||
{
|
{
|
||||||
let mut is_mut = false;
|
// If we can't suggest borrowing in the call, but the function definition
|
||||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = arg.kind
|
// is local, instead offer changing the function to borrow that argument.
|
||||||
&& let Res::Def(DefKind::TyParam, param_def_id) = path.res
|
|
||||||
&& self
|
|
||||||
.infcx
|
|
||||||
.tcx
|
|
||||||
.predicates_of(def_id)
|
|
||||||
.instantiate_identity(self.infcx.tcx)
|
|
||||||
.predicates
|
|
||||||
.into_iter()
|
|
||||||
.any(|pred| {
|
|
||||||
if let ty::ClauseKind::Trait(predicate) = pred.kind().skip_binder()
|
|
||||||
&& [
|
|
||||||
self.infcx.tcx.get_diagnostic_item(sym::AsRef),
|
|
||||||
self.infcx.tcx.get_diagnostic_item(sym::AsMut),
|
|
||||||
self.infcx.tcx.get_diagnostic_item(sym::Borrow),
|
|
||||||
self.infcx.tcx.get_diagnostic_item(sym::BorrowMut),
|
|
||||||
]
|
|
||||||
.contains(&Some(predicate.def_id()))
|
|
||||||
&& let ty::Param(param) = predicate.self_ty().kind()
|
|
||||||
&& let generics = self.infcx.tcx.generics_of(def_id)
|
|
||||||
&& let param = generics.type_param(*param, self.infcx.tcx)
|
|
||||||
&& param.def_id == param_def_id
|
|
||||||
{
|
|
||||||
if [
|
|
||||||
self.infcx.tcx.get_diagnostic_item(sym::AsMut),
|
|
||||||
self.infcx.tcx.get_diagnostic_item(sym::BorrowMut),
|
|
||||||
]
|
|
||||||
.contains(&Some(predicate.def_id()))
|
|
||||||
{
|
|
||||||
is_mut = true;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
{
|
|
||||||
// The type of the argument corresponding to the expression that got moved
|
|
||||||
// is a type parameter `T`, which is has a `T: AsRef` obligation.
|
|
||||||
err.span_suggestion_verbose(
|
|
||||||
expr.span.shrink_to_lo(),
|
|
||||||
"borrow the value to avoid moving it",
|
|
||||||
format!("&{}", if is_mut { "mut " } else { "" }),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
can_suggest_clone = is_mut;
|
|
||||||
} else {
|
|
||||||
let mut span: MultiSpan = arg.span.into();
|
let mut span: MultiSpan = arg.span.into();
|
||||||
span.push_span_label(
|
span.push_span_label(
|
||||||
arg.span,
|
arg.span,
|
||||||
|
@ -546,8 +511,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let place = &self.move_data.move_paths[mpi].place;
|
|
||||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
|
||||||
if let hir::Node::Expr(parent_expr) = parent
|
if let hir::Node::Expr(parent_expr) = parent
|
||||||
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
|
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
|
||||||
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
|
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
|
||||||
|
@ -557,6 +520,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
} else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans
|
} else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans
|
||||||
{
|
{
|
||||||
// We already suggest cloning for these cases in `explain_captures`.
|
// We already suggest cloning for these cases in `explain_captures`.
|
||||||
|
} else if moved_or_invoked_closure {
|
||||||
|
// Do not suggest `closure.clone()()`.
|
||||||
} else if let UseSpans::ClosureUse {
|
} else if let UseSpans::ClosureUse {
|
||||||
closure_kind:
|
closure_kind:
|
||||||
ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),
|
ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),
|
||||||
|
@ -665,6 +630,114 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If a place is used after being moved as an argument to a function, the function is generic
|
||||||
|
/// in that argument, and a reference to the argument's type would still satisfy the function's
|
||||||
|
/// bounds, suggest borrowing. This covers, e.g., borrowing an `impl Fn()` argument being passed
|
||||||
|
/// in an `impl FnOnce()` position.
|
||||||
|
/// Returns `Some(mutability)` when suggesting to borrow with mutability `mutability`, or `None`
|
||||||
|
/// if no suggestion is made.
|
||||||
|
fn suggest_borrow_generic_arg(
|
||||||
|
&self,
|
||||||
|
err: &mut Diag<'_>,
|
||||||
|
callee_did: DefId,
|
||||||
|
generic_args: ty::GenericArgsRef<'tcx>,
|
||||||
|
param: ty::ParamTy,
|
||||||
|
moved_place: PlaceRef<'tcx>,
|
||||||
|
moved_arg_pos: usize,
|
||||||
|
moved_arg_ty: Ty<'tcx>,
|
||||||
|
place_span: Span,
|
||||||
|
) -> Option<ty::Mutability> {
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
|
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
|
||||||
|
let clauses = tcx.predicates_of(callee_did);
|
||||||
|
|
||||||
|
// First, is there at least one method on one of `param`'s trait bounds?
|
||||||
|
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
|
||||||
|
if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {
|
||||||
|
clause.as_trait_clause().is_some_and(|tc| {
|
||||||
|
tc.self_ty().skip_binder().is_param(param.index)
|
||||||
|
&& tc.polarity() == ty::PredicatePolarity::Positive
|
||||||
|
&& tcx
|
||||||
|
.supertrait_def_ids(tc.def_id())
|
||||||
|
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
|
||||||
|
.any(|item| item.fn_has_self_parameter)
|
||||||
|
})
|
||||||
|
}) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try borrowing a shared reference first, then mutably.
|
||||||
|
if let Some(mutbl) = [ty::Mutability::Not, ty::Mutability::Mut].into_iter().find(|&mutbl| {
|
||||||
|
let re = self.infcx.tcx.lifetimes.re_erased;
|
||||||
|
let ref_ty = Ty::new_ref(self.infcx.tcx, re, moved_arg_ty, mutbl);
|
||||||
|
|
||||||
|
// Ensure that substituting `ref_ty` in the callee's signature doesn't break
|
||||||
|
// other inputs or the return type.
|
||||||
|
let new_args = tcx.mk_args_from_iter(generic_args.iter().enumerate().map(
|
||||||
|
|(i, arg)| {
|
||||||
|
if i == param.index as usize { ref_ty.into() } else { arg }
|
||||||
|
},
|
||||||
|
));
|
||||||
|
let can_subst = |ty: Ty<'tcx>| {
|
||||||
|
// Normalize before comparing to see through type aliases and projections.
|
||||||
|
let old_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, generic_args);
|
||||||
|
let new_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, new_args);
|
||||||
|
if let Ok(old_ty) = tcx.try_normalize_erasing_regions(
|
||||||
|
self.infcx.typing_env(self.infcx.param_env),
|
||||||
|
old_ty,
|
||||||
|
) && let Ok(new_ty) = tcx.try_normalize_erasing_regions(
|
||||||
|
self.infcx.typing_env(self.infcx.param_env),
|
||||||
|
new_ty,
|
||||||
|
) {
|
||||||
|
old_ty == new_ty
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !can_subst(sig.output())
|
||||||
|
|| sig
|
||||||
|
.inputs()
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.any(|(i, &input_ty)| i != moved_arg_pos && !can_subst(input_ty))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the callee's predicates, substituting in `ref_ty` for the moved argument type.
|
||||||
|
clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| {
|
||||||
|
// Normalize before testing to see through type aliases and projections.
|
||||||
|
if let Ok(normalized) = tcx.try_normalize_erasing_regions(
|
||||||
|
self.infcx.typing_env(self.infcx.param_env),
|
||||||
|
clause,
|
||||||
|
) {
|
||||||
|
clause = normalized;
|
||||||
|
}
|
||||||
|
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
|
||||||
|
tcx,
|
||||||
|
ObligationCause::dummy(),
|
||||||
|
self.infcx.param_env,
|
||||||
|
clause,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}) {
|
||||||
|
let place_desc = if let Some(desc) = self.describe_place(moved_place) {
|
||||||
|
format!("`{desc}`")
|
||||||
|
} else {
|
||||||
|
"here".to_owned()
|
||||||
|
};
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
place_span.shrink_to_lo(),
|
||||||
|
format!("consider {}borrowing {place_desc}", mutbl.mutably_str()),
|
||||||
|
mutbl.ref_prefix_str(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
Some(mutbl)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn report_use_of_uninitialized(
|
fn report_use_of_uninitialized(
|
||||||
&self,
|
&self,
|
||||||
mpi: MovePathIndex,
|
mpi: MovePathIndex,
|
||||||
|
@ -832,7 +905,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
||||||
debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
|
debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
|
||||||
|
|
||||||
let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.param_env, ty)
|
let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.infcx.param_env, ty)
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -845,74 +918,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_borrow_fn_like(
|
|
||||||
&self,
|
|
||||||
err: &mut Diag<'_>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
move_sites: &[MoveSite],
|
|
||||||
value_name: &str,
|
|
||||||
) -> bool {
|
|
||||||
let tcx = self.infcx.tcx;
|
|
||||||
|
|
||||||
// Find out if the predicates show that the type is a Fn or FnMut
|
|
||||||
let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| {
|
|
||||||
if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
|
|
||||||
&& pred.self_ty() == ty
|
|
||||||
{
|
|
||||||
if tcx.is_lang_item(pred.def_id(), LangItem::Fn) {
|
|
||||||
return Some(hir::Mutability::Not);
|
|
||||||
} else if tcx.is_lang_item(pred.def_id(), LangItem::FnMut) {
|
|
||||||
return Some(hir::Mutability::Mut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
|
|
||||||
// borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
|
|
||||||
// These types seem reasonably opaque enough that they could be instantiated with their
|
|
||||||
// borrowed variants in a function body when we see a move error.
|
|
||||||
let borrow_level = match *ty.kind() {
|
|
||||||
ty::Param(_) => tcx
|
|
||||||
.explicit_predicates_of(self.mir_def_id().to_def_id())
|
|
||||||
.predicates
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.find_map(find_fn_kind_from_did),
|
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => tcx
|
|
||||||
.explicit_item_super_predicates(def_id)
|
|
||||||
.iter_instantiated_copied(tcx, args)
|
|
||||||
.find_map(|(clause, span)| find_fn_kind_from_did((clause, span))),
|
|
||||||
ty::Closure(_, args) => match args.as_closure().kind() {
|
|
||||||
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
|
|
||||||
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(borrow_level) = borrow_level else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let sugg = move_sites
|
|
||||||
.iter()
|
|
||||||
.map(|move_site| {
|
|
||||||
let move_out = self.move_data.moves[(*move_site).moi];
|
|
||||||
let moved_place = &self.move_data.move_paths[move_out.path].place;
|
|
||||||
let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
|
|
||||||
let move_span = move_spans.args_or_use();
|
|
||||||
let suggestion = borrow_level.ref_prefix_str().to_owned();
|
|
||||||
(move_span.shrink_to_lo(), suggestion)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
err.multipart_suggestion_verbose(
|
|
||||||
format!("consider {}borrowing {value_name}", borrow_level.mutably_str()),
|
|
||||||
sugg,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// In a move error that occurs on a call within a loop, we try to identify cases where cloning
|
/// In a move error that occurs on a call within a loop, we try to identify cases where cloning
|
||||||
/// the value would lead to a logic error. We infer these cases by seeing if the moved value is
|
/// the value would lead to a logic error. We infer these cases by seeing if the moved value is
|
||||||
/// part of the logic to break the loop, either through an explicit `break` or if the expression
|
/// part of the logic to break the loop, either through an explicit `break` or if the expression
|
||||||
|
@ -1300,7 +1305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool {
|
pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool {
|
||||||
let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false };
|
let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false };
|
||||||
self.infcx
|
self.infcx
|
||||||
.type_implements_trait(clone_trait_def, [ty], self.param_env)
|
.type_implements_trait(clone_trait_def, [ty], self.infcx.param_env)
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,11 +1350,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
// See `tests/ui/moves/needs-clone-through-deref.rs`
|
// See `tests/ui/moves/needs-clone-through-deref.rs`
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// We don't want to suggest `.clone()` in a move closure, since the value has already been captured.
|
// We don't want to suggest `.clone()` in a move closure, since the value has already been
|
||||||
|
// captured.
|
||||||
if self.in_move_closure(expr) {
|
if self.in_move_closure(expr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// We also don't want to suggest cloning a closure itself, since the value has already been captured.
|
// We also don't want to suggest cloning a closure itself, since the value has already been
|
||||||
|
// captured.
|
||||||
if let hir::ExprKind::Closure(_) = expr.kind {
|
if let hir::ExprKind::Closure(_) = expr.kind {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1381,7 +1388,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Cloning the raw pointer doesn't make sense in some cases and would cause a type mismatch error. (see #126863)
|
// Cloning the raw pointer doesn't make sense in some cases and would cause a type mismatch
|
||||||
|
// error. (see #126863)
|
||||||
if inner_expr.span.lo() != expr.span.lo() && !is_raw_ptr {
|
if inner_expr.span.lo() != expr.span.lo() && !is_raw_ptr {
|
||||||
// Remove "(*" or "(&"
|
// Remove "(*" or "(&"
|
||||||
sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));
|
sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));
|
||||||
|
@ -1430,7 +1438,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);
|
let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);
|
||||||
let cause = ObligationCause::misc(span, self.mir_def_id());
|
let cause = ObligationCause::misc(span, self.mir_def_id());
|
||||||
|
|
||||||
ocx.register_bound(cause, self.param_env, ty, def_id);
|
ocx.register_bound(cause, self.infcx.param_env, ty, def_id);
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
|
|
||||||
// Only emit suggestion if all required predicates are on generic
|
// Only emit suggestion if all required predicates are on generic
|
||||||
|
@ -1553,8 +1561,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let use_spans = self.move_spans(place.as_ref(), location);
|
let use_spans = self.move_spans(place.as_ref(), location);
|
||||||
let span = use_spans.var_or_use();
|
let span = use_spans.var_or_use();
|
||||||
|
|
||||||
// If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use
|
// If the attempted use is in a closure then we do not care about the path span of the
|
||||||
// we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure
|
// place we are currently trying to use we call `var_span_label` on `borrow_spans` to
|
||||||
|
// annotate if the existing borrow was in a closure.
|
||||||
let mut err = self.cannot_use_when_mutably_borrowed(
|
let mut err = self.cannot_use_when_mutably_borrowed(
|
||||||
span,
|
span,
|
||||||
&self.describe_any_place(place.as_ref()),
|
&self.describe_any_place(place.as_ref()),
|
||||||
|
@ -1949,7 +1958,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
|
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
|
||||||
&& let inner = inner.peel_refs()
|
&& let inner = inner.peel_refs()
|
||||||
&& (Holds { ty: inner }).visit_ty(local_ty).is_break()
|
&& (Holds { ty: inner }).visit_ty(local_ty).is_break()
|
||||||
&& let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
|
&& let None =
|
||||||
|
self.infcx.type_implements_trait_shallow(clone, inner, self.infcx.param_env)
|
||||||
{
|
{
|
||||||
err.span_label(
|
err.span_label(
|
||||||
span,
|
span,
|
||||||
|
@ -1981,7 +1991,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let obligation = Obligation::new(
|
let obligation = Obligation::new(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
ObligationCause::dummy(),
|
ObligationCause::dummy(),
|
||||||
self.param_env,
|
self.infcx.param_env,
|
||||||
trait_ref,
|
trait_ref,
|
||||||
);
|
);
|
||||||
self.infcx.err_ctxt().suggest_derive(
|
self.infcx.err_ctxt().suggest_derive(
|
||||||
|
@ -2480,7 +2490,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
if let hir::ExprKind::Closure(closure) = ex.kind
|
if let hir::ExprKind::Closure(closure) = ex.kind
|
||||||
&& ex.span.contains(self.borrow_span)
|
&& ex.span.contains(self.borrow_span)
|
||||||
// To support cases like `|| { v.call(|this| v.get()) }`
|
// To support cases like `|| { v.call(|this| v.get()) }`
|
||||||
// FIXME: actually support such cases (need to figure out how to move from the capture place to original local)
|
// FIXME: actually support such cases (need to figure out how to move from the
|
||||||
|
// capture place to original local).
|
||||||
&& self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span))
|
&& self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span))
|
||||||
{
|
{
|
||||||
self.res = Some((ex, closure));
|
self.res = Some((ex, closure));
|
||||||
|
@ -2733,7 +2744,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
/// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
|
/// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
|
||||||
/// mutable (via `a.u.s.b`) [E0502]
|
/// mutable (via `a.u.s.b`) [E0502]
|
||||||
/// ```
|
/// ```
|
||||||
pub(crate) fn describe_place_for_conflicting_borrow(
|
fn describe_place_for_conflicting_borrow(
|
||||||
&self,
|
&self,
|
||||||
first_borrowed_place: Place<'tcx>,
|
first_borrowed_place: Place<'tcx>,
|
||||||
second_borrowed_place: Place<'tcx>,
|
second_borrowed_place: Place<'tcx>,
|
||||||
|
@ -3188,8 +3199,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
/// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
|
/// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
|
||||||
/// We could expand the analysis to suggest hoising all of the relevant parts of
|
/// We could expand the analysis to suggest hoising all of the relevant parts of
|
||||||
/// the users' code to make the code compile, but that could be too much.
|
/// the users' code to make the code compile, but that could be too much.
|
||||||
/// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`,
|
/// We found the `prop_expr` by the way to check whether the expression is a
|
||||||
/// which is a special case since it's generated by the compiler.
|
/// `FormatArguments`, which is a special case since it's generated by the
|
||||||
|
/// compiler.
|
||||||
struct NestedStatementVisitor<'tcx> {
|
struct NestedStatementVisitor<'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
current: usize,
|
current: usize,
|
||||||
|
@ -3388,7 +3400,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
|
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
|
||||||
&& self
|
&& self
|
||||||
.infcx
|
.infcx
|
||||||
.type_implements_trait(iter_trait, [return_ty], self.param_env)
|
.type_implements_trait(iter_trait, [return_ty], self.infcx.param_env)
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
{
|
{
|
||||||
err.span_suggestion_hidden(
|
err.span_suggestion_hidden(
|
||||||
|
@ -3420,7 +3432,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
|
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
|
||||||
Ok(string) => {
|
Ok(string) => {
|
||||||
let coro_prefix = if string.starts_with("async") {
|
let coro_prefix = if string.starts_with("async") {
|
||||||
// `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize` to `u32`
|
// `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize`
|
||||||
|
// to `u32`.
|
||||||
Some(5)
|
Some(5)
|
||||||
} else if string.starts_with("gen") {
|
} else if string.starts_with("gen") {
|
||||||
// `gen` is 3 chars long
|
// `gen` is 3 chars long
|
||||||
|
@ -3618,10 +3631,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let stmt_kind =
|
let stmt_kind =
|
||||||
self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind);
|
self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind);
|
||||||
if let Some(StatementKind::StorageDead(..)) = stmt_kind {
|
if let Some(StatementKind::StorageDead(..)) = stmt_kind {
|
||||||
// this analysis only tries to find moves explicitly
|
// This analysis only tries to find moves explicitly written by the user, so we
|
||||||
// written by the user, so we ignore the move-outs
|
// ignore the move-outs created by `StorageDead` and at the beginning of a
|
||||||
// created by `StorageDead` and at the beginning
|
// function.
|
||||||
// of a function.
|
|
||||||
} else {
|
} else {
|
||||||
// If we are found a use of a.b.c which was in error, then we want to look for
|
// If we are found a use of a.b.c which was in error, then we want to look for
|
||||||
// moves not only of a.b.c but also a.b and a.
|
// moves not only of a.b.c but also a.b and a.
|
||||||
|
@ -3706,13 +3718,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_argument || !reached_start) && result.is_empty() {
|
if (is_argument || !reached_start) && result.is_empty() {
|
||||||
/* Process back edges (moves in future loop iterations) only if
|
// Process back edges (moves in future loop iterations) only if
|
||||||
the move path is definitely initialized upon loop entry,
|
// the move path is definitely initialized upon loop entry,
|
||||||
to avoid spurious "in previous iteration" errors.
|
// to avoid spurious "in previous iteration" errors.
|
||||||
During DFS, if there's a path from the error back to the start
|
// During DFS, if there's a path from the error back to the start
|
||||||
of the function with no intervening init or move, then the
|
// of the function with no intervening init or move, then the
|
||||||
move path may be uninitialized at loop entry.
|
// move path may be uninitialized at loop entry.
|
||||||
*/
|
|
||||||
while let Some(location) = back_edge_stack.pop() {
|
while let Some(location) = back_edge_stack.pop() {
|
||||||
if dfs_iter(&mut result, location, true) {
|
if dfs_iter(&mut result, location, true) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -3828,11 +3839,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
|
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
|
||||||
let deref_target =
|
let deref_target =
|
||||||
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||||
Instance::try_resolve(tcx, self.param_env, deref_target, method_args)
|
Instance::try_resolve(
|
||||||
|
tcx,
|
||||||
|
self.infcx.typing_env(self.infcx.param_env),
|
||||||
|
deref_target,
|
||||||
|
method_args,
|
||||||
|
)
|
||||||
.transpose()
|
.transpose()
|
||||||
});
|
});
|
||||||
if let Some(Ok(instance)) = deref_target {
|
if let Some(Ok(instance)) = deref_target {
|
||||||
let deref_target_ty = instance.ty(tcx, self.param_env);
|
let deref_target_ty =
|
||||||
|
instance.ty(tcx, self.infcx.typing_env(self.infcx.param_env));
|
||||||
err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`"));
|
err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`"));
|
||||||
err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
|
err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
{
|
{
|
||||||
suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
|
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) {
|
} 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
|
// 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)) {
|
if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
var_or_use_span,
|
var_or_use_span,
|
||||||
|
@ -165,7 +166,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
LaterUseKind::FakeLetRead => "borrow later stored here",
|
LaterUseKind::FakeLetRead => "borrow later stored here",
|
||||||
LaterUseKind::Other => "borrow used here, in later iteration of loop",
|
LaterUseKind::Other => "borrow used here, in later iteration of loop",
|
||||||
};
|
};
|
||||||
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
|
// 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 path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
|
||||||
err.span_label(var_or_use_span, format!("{borrow_desc}{message}"));
|
err.span_label(var_or_use_span, format!("{borrow_desc}{message}"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -285,7 +287,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
span: _,
|
span: _,
|
||||||
pat,
|
pat,
|
||||||
init,
|
init,
|
||||||
// FIXME(#101728): enable rewrite when type ascription is stabilized again
|
// FIXME(#101728): enable rewrite when type ascription is
|
||||||
|
// stabilized again.
|
||||||
ty: None,
|
ty: None,
|
||||||
recovered: _,
|
recovered: _,
|
||||||
}) = cond.kind
|
}) = cond.kind
|
||||||
|
@ -353,8 +356,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
unsize_ty: Ty<'tcx>,
|
unsize_ty: Ty<'tcx>,
|
||||||
) {
|
) {
|
||||||
if let ty::Adt(def, args) = unsize_ty.kind() {
|
if let ty::Adt(def, args) = unsize_ty.kind() {
|
||||||
// We try to elaborate the object lifetime defaults and present those to the user. This should
|
// We try to elaborate the object lifetime defaults and present those to the user. This
|
||||||
// make it clear where the region constraint is coming from.
|
// should make it clear where the region constraint is coming from.
|
||||||
let generics = tcx.generics_of(def.did());
|
let generics = tcx.generics_of(def.did());
|
||||||
|
|
||||||
let mut has_dyn = false;
|
let mut has_dyn = false;
|
||||||
|
@ -531,9 +534,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||||
let mut use_in_later_iteration_of_loop = false;
|
let mut use_in_later_iteration_of_loop = false;
|
||||||
|
|
||||||
if region_sub == borrow_region_vid {
|
if region_sub == borrow_region_vid {
|
||||||
// When `region_sub` is the same as `borrow_region_vid` (the location where the borrow is
|
// When `region_sub` is the same as `borrow_region_vid` (the location where the borrow
|
||||||
// issued is the same location that invalidates the reference), this is likely a loop iteration
|
// is issued is the same location that invalidates the reference), this is likely a
|
||||||
// - in this case, try using the loop terminator location in `find_sub_region_live_at`.
|
// loop iteration. In this case, try using the loop terminator location in
|
||||||
|
// `find_sub_region_live_at`.
|
||||||
if let Some(loop_terminator_location) =
|
if let Some(loop_terminator_location) =
|
||||||
regioncx.find_loop_terminator_location(borrow.region, body)
|
regioncx.find_loop_terminator_location(borrow.region, body)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Borrow checker diagnostics.
|
//! Borrow checker diagnostics.
|
||||||
|
|
||||||
|
use rustc_abi::{FieldIdx, VariantIdx};
|
||||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
use rustc_errors::{Applicability, Diag, MultiSpan};
|
||||||
use rustc_hir::def::{CtorKind, Namespace};
|
use rustc_hir::def::{CtorKind, Namespace};
|
||||||
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
||||||
|
@ -21,7 +22,6 @@ use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
|
||||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
|
@ -763,7 +763,7 @@ impl<'tcx> BorrowedContentSource<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///helper struct for explain_captures()
|
/// Helper struct for `explain_captures`.
|
||||||
struct CapturedMessageOpt {
|
struct CapturedMessageOpt {
|
||||||
is_partial_move: bool,
|
is_partial_move: bool,
|
||||||
is_loop_message: bool,
|
is_loop_message: bool,
|
||||||
|
@ -864,7 +864,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
|
|
||||||
let kind = call_kind(
|
let kind = call_kind(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
self.param_env,
|
self.infcx.typing_env(self.infcx.param_env),
|
||||||
method_did,
|
method_did,
|
||||||
method_args,
|
method_args,
|
||||||
*fn_span,
|
*fn_span,
|
||||||
|
@ -1062,8 +1062,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
&& let spans = hir_generics
|
&& let spans = hir_generics
|
||||||
.predicates
|
.predicates
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|pred| match pred {
|
.filter_map(|pred| match pred.kind {
|
||||||
hir::WherePredicate::BoundPredicate(pred) => Some(pred),
|
hir::WherePredicateKind::BoundPredicate(pred) => Some(pred),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.filter(|pred| {
|
.filter(|pred| {
|
||||||
|
@ -1160,7 +1160,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
|
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
|
||||||
Some(def_id) => type_known_to_meet_bound_modulo_regions(
|
Some(def_id) => type_known_to_meet_bound_modulo_regions(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
self.param_env,
|
self.infcx.param_env,
|
||||||
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
|
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
|
||||||
def_id,
|
def_id,
|
||||||
),
|
),
|
||||||
|
@ -1224,7 +1224,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
BoundRegionConversionTime::FnCall,
|
BoundRegionConversionTime::FnCall,
|
||||||
tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0),
|
tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0),
|
||||||
)
|
)
|
||||||
&& self.infcx.can_eq(self.param_env, ty, self_ty)
|
&& self.infcx.can_eq(self.infcx.param_env, ty, self_ty)
|
||||||
{
|
{
|
||||||
err.subdiagnostic(CaptureReasonSuggest::FreshReborrow {
|
err.subdiagnostic(CaptureReasonSuggest::FreshReborrow {
|
||||||
span: move_span.shrink_to_hi(),
|
span: move_span.shrink_to_hi(),
|
||||||
|
@ -1258,7 +1258,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
if let Some(errors) = self.infcx.type_implements_trait_shallow(
|
if let Some(errors) = self.infcx.type_implements_trait_shallow(
|
||||||
clone_trait,
|
clone_trait,
|
||||||
ty,
|
ty,
|
||||||
self.param_env,
|
self.infcx.param_env,
|
||||||
) && !has_sugg
|
) && !has_sugg
|
||||||
{
|
{
|
||||||
let msg = match &errors[..] {
|
let msg = match &errors[..] {
|
||||||
|
|
|
@ -10,6 +10,7 @@ use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
||||||
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
|
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
|
||||||
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
||||||
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::MirBorrowckCtxt;
|
use crate::MirBorrowckCtxt;
|
||||||
|
@ -267,6 +268,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
kind,
|
kind,
|
||||||
self.is_upvar_field_projection(original_path.as_ref())
|
self.is_upvar_field_projection(original_path.as_ref())
|
||||||
);
|
);
|
||||||
|
if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) {
|
||||||
|
// If the type may implement Copy, skip the error.
|
||||||
|
// It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
|
||||||
|
self.dcx().span_delayed_bug(
|
||||||
|
span,
|
||||||
|
"Type may implement copy, but there is no other error.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
(
|
(
|
||||||
match kind {
|
match kind {
|
||||||
&IllegalMoveOriginKind::BorrowedContent { target_place } => self
|
&IllegalMoveOriginKind::BorrowedContent { target_place } => self
|
||||||
|
@ -291,6 +301,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
self.buffer_error(err);
|
self.buffer_error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_ambiguous_copy(&mut self, ty: Ty<'tcx>) -> bool {
|
||||||
|
let Some(copy_trait_def) = self.infcx.tcx.lang_items().copy_trait() else { return false };
|
||||||
|
// This is only going to be ambiguous if there are incoherent impls, because otherwise
|
||||||
|
// ambiguity should never happen in MIR.
|
||||||
|
self.infcx.type_implements_trait(copy_trait_def, [ty], self.infcx.param_env).may_apply()
|
||||||
|
}
|
||||||
|
|
||||||
fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> {
|
fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> {
|
||||||
let description = if place.projection.len() == 1 {
|
let description = if place.projection.len() == 1 {
|
||||||
format!("static item {}", self.describe_any_place(place.as_ref()))
|
format!("static item {}", self.describe_any_place(place.as_ref()))
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
use core::ops::ControlFlow;
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
use hir::{ExprKind, Param};
|
use hir::{ExprKind, Param};
|
||||||
|
use rustc_abi::FieldIdx;
|
||||||
use rustc_errors::{Applicability, Diag};
|
use rustc_errors::{Applicability, Diag};
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::{self as hir, BindingMode, ByRef, Node};
|
use rustc_hir::{self as hir, BindingMode, ByRef, Node};
|
||||||
|
@ -16,7 +17,6 @@ use rustc_middle::mir::{
|
||||||
use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
|
use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
|
||||||
use rustc_span::symbol::{Symbol, kw};
|
use rustc_span::symbol::{Symbol, kw};
|
||||||
use rustc_span::{BytePos, DesugaringKind, Span, sym};
|
use rustc_span::{BytePos, DesugaringKind, Span, sym};
|
||||||
use rustc_target::abi::FieldIdx;
|
|
||||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
@ -793,7 +793,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
|
let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
|
||||||
let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
|
let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
|
||||||
let root_hir_id = upvar_id.var_path.hir_id;
|
let root_hir_id = upvar_id.var_path.hir_id;
|
||||||
// we have an origin for this closure kind starting at this root variable so it's safe to unwrap here
|
// We have an origin for this closure kind starting at this root variable so it's
|
||||||
|
// safe to unwrap here.
|
||||||
let captured_places =
|
let captured_places =
|
||||||
tables.closure_min_captures[&closure_local_def_id].get(&root_hir_id).unwrap();
|
tables.closure_min_captures[&closure_local_def_id].get(&root_hir_id).unwrap();
|
||||||
|
|
||||||
|
@ -816,7 +817,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
) {
|
) {
|
||||||
match captured_place.info.capture_kind {
|
match captured_place.info.capture_kind {
|
||||||
ty::UpvarCapture::ByRef(
|
ty::UpvarCapture::ByRef(
|
||||||
ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
|
ty::BorrowKind::Mutable | ty::BorrowKind::UniqueImmutable,
|
||||||
) => {
|
) => {
|
||||||
capture_reason = format!("mutable borrow of `{upvar}`");
|
capture_reason = format!("mutable borrow of `{upvar}`");
|
||||||
}
|
}
|
||||||
|
@ -966,8 +967,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we can detect the expression to be an function or method call where the closure was an argument,
|
// If we can detect the expression to be an function or method call where the closure was
|
||||||
// we point at the function or method definition argument...
|
// an argument, we point at the function or method definition argument...
|
||||||
if let Some((callee_def_id, call_span, call_args)) = get_call_details() {
|
if let Some((callee_def_id, call_span, call_args)) = get_call_details() {
|
||||||
let arg_pos = call_args
|
let arg_pos = call_args
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1241,7 +1242,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
.type_implements_trait_shallow(
|
.type_implements_trait_shallow(
|
||||||
clone_trait,
|
clone_trait,
|
||||||
ty.peel_refs(),
|
ty.peel_refs(),
|
||||||
self.param_env,
|
self.infcx.param_env,
|
||||||
)
|
)
|
||||||
.as_deref()
|
.as_deref()
|
||||||
{
|
{
|
||||||
|
@ -1278,7 +1279,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let obligation = traits::Obligation::new(
|
let obligation = traits::Obligation::new(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
traits::ObligationCause::dummy(),
|
traits::ObligationCause::dummy(),
|
||||||
self.param_env,
|
self.infcx.param_env,
|
||||||
trait_ref,
|
trait_ref,
|
||||||
);
|
);
|
||||||
self.infcx.err_ctxt().suggest_derive(
|
self.infcx.err_ctxt().suggest_derive(
|
||||||
|
|
|
@ -4,15 +4,16 @@
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use itertools::Itertools as _;
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::{Applicability, Diag};
|
use rustc_errors::{Diag, Subdiagnostic};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::mir::{self, ConstraintCategory, Location};
|
use rustc_middle::mir::{self, ConstraintCategory, Location};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||||
};
|
};
|
||||||
use rustc_span::Symbol;
|
use rustc_trait_selection::errors::impl_trait_overcapture_suggestion;
|
||||||
|
|
||||||
use crate::MirBorrowckCtxt;
|
use crate::MirBorrowckCtxt;
|
||||||
use crate::borrow_set::BorrowData;
|
use crate::borrow_set::BorrowData;
|
||||||
|
@ -61,6 +62,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
// *does* mention. We'll use that for the `+ use<'a>` suggestion below.
|
// *does* mention. We'll use that for the `+ use<'a>` suggestion below.
|
||||||
let mut visitor = CheckExplicitRegionMentionAndCollectGenerics {
|
let mut visitor = CheckExplicitRegionMentionAndCollectGenerics {
|
||||||
tcx,
|
tcx,
|
||||||
|
generics: tcx.generics_of(opaque_def_id),
|
||||||
offending_region_idx,
|
offending_region_idx,
|
||||||
seen_opaques: [opaque_def_id].into_iter().collect(),
|
seen_opaques: [opaque_def_id].into_iter().collect(),
|
||||||
seen_lifetimes: Default::default(),
|
seen_lifetimes: Default::default(),
|
||||||
|
@ -83,34 +85,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
"this call may capture more lifetimes than intended, \
|
"this call may capture more lifetimes than intended, \
|
||||||
because Rust 2024 has adjusted the `impl Trait` lifetime capture rules",
|
because Rust 2024 has adjusted the `impl Trait` lifetime capture rules",
|
||||||
);
|
);
|
||||||
let mut seen_generics: Vec<_> =
|
let mut captured_args = visitor.seen_lifetimes;
|
||||||
visitor.seen_lifetimes.iter().map(ToString::to_string).collect();
|
// Add in all of the type and const params, too.
|
||||||
// Capture all in-scope ty/const params.
|
// Ordering here is kinda strange b/c we're walking backwards,
|
||||||
seen_generics.extend(
|
// but we're trying to provide *a* suggestion, not a nice one.
|
||||||
ty::GenericArgs::identity_for_item(tcx, opaque_def_id)
|
let mut next_generics = Some(visitor.generics);
|
||||||
.iter()
|
let mut any_synthetic = false;
|
||||||
.filter(|arg| {
|
while let Some(generics) = next_generics {
|
||||||
matches!(
|
for param in &generics.own_params {
|
||||||
arg.unpack(),
|
if param.kind.is_ty_or_const() {
|
||||||
ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_)
|
captured_args.insert(param.def_id);
|
||||||
)
|
}
|
||||||
})
|
if param.kind.is_synthetic() {
|
||||||
.map(|arg| arg.to_string()),
|
any_synthetic = true;
|
||||||
);
|
}
|
||||||
if opaque_def_id.is_local() {
|
}
|
||||||
diag.span_suggestion_verbose(
|
next_generics = generics.parent.map(|def_id| tcx.generics_of(def_id));
|
||||||
tcx.def_span(opaque_def_id).shrink_to_hi(),
|
}
|
||||||
"add a precise capturing bound to avoid overcapturing",
|
|
||||||
format!(" + use<{}>", seen_generics.join(", ")),
|
if let Some(opaque_def_id) = opaque_def_id.as_local()
|
||||||
Applicability::MaybeIncorrect,
|
&& let hir::OpaqueTyOrigin::FnReturn { parent, .. } =
|
||||||
);
|
tcx.hir().expect_opaque_ty(opaque_def_id).origin
|
||||||
|
{
|
||||||
|
if let Some(sugg) = impl_trait_overcapture_suggestion(
|
||||||
|
tcx,
|
||||||
|
opaque_def_id,
|
||||||
|
parent,
|
||||||
|
captured_args,
|
||||||
|
) {
|
||||||
|
sugg.add_to_diag(diag);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
diag.span_help(
|
diag.span_help(
|
||||||
tcx.def_span(opaque_def_id),
|
tcx.def_span(opaque_def_id),
|
||||||
format!(
|
format!(
|
||||||
"if you can modify this crate, add a precise \
|
"if you can modify this crate, add a precise \
|
||||||
capturing bound to avoid overcapturing: `+ use<{}>`",
|
capturing bound to avoid overcapturing: `+ use<{}>`",
|
||||||
seen_generics.join(", ")
|
if any_synthetic {
|
||||||
|
"/* Args */".to_string()
|
||||||
|
} else {
|
||||||
|
captured_args
|
||||||
|
.into_iter()
|
||||||
|
.map(|def_id| tcx.item_name(def_id))
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -182,9 +200,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
|
||||||
|
|
||||||
struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
|
struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
generics: &'tcx ty::Generics,
|
||||||
offending_region_idx: usize,
|
offending_region_idx: usize,
|
||||||
seen_opaques: FxIndexSet<DefId>,
|
seen_opaques: FxIndexSet<DefId>,
|
||||||
seen_lifetimes: FxIndexSet<Symbol>,
|
seen_lifetimes: FxIndexSet<DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
|
||||||
|
@ -214,7 +233,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGen
|
||||||
if param.index as usize == self.offending_region_idx {
|
if param.index as usize == self.offending_region_idx {
|
||||||
ControlFlow::Break(())
|
ControlFlow::Break(())
|
||||||
} else {
|
} else {
|
||||||
self.seen_lifetimes.insert(param.name);
|
self.seen_lifetimes.insert(self.generics.region_param(param, self.tcx).def_id);
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::GenericBound::Trait;
|
use rustc_hir::GenericBound::Trait;
|
||||||
use rustc_hir::QPath::Resolved;
|
use rustc_hir::QPath::Resolved;
|
||||||
use rustc_hir::WherePredicate::BoundPredicate;
|
use rustc_hir::WherePredicateKind::BoundPredicate;
|
||||||
use rustc_hir::def::Res::Def;
|
use rustc_hir::def::Res::Def;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
|
@ -189,7 +189,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
/// Returns `true` if a closure is inferred to be an `FnMut` closure.
|
/// Returns `true` if a closure is inferred to be an `FnMut` closure.
|
||||||
fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
|
fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
|
||||||
if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref()
|
if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref()
|
||||||
&& let ty::BoundRegionKind::BrEnv = late_param.bound_region
|
&& let ty::BoundRegionKind::ClosureEnv = late_param.bound_region
|
||||||
&& let DefiningTy::Closure(_, args) = self.regioncx.universal_regions().defining_ty
|
&& let DefiningTy::Closure(_, args) = self.regioncx.universal_regions().defining_ty
|
||||||
{
|
{
|
||||||
return args.as_closure().kind() == ty::ClosureKind::FnMut;
|
return args.as_closure().kind() == ty::ClosureKind::FnMut;
|
||||||
|
@ -236,7 +236,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let mut hrtb_bounds = vec![];
|
let mut hrtb_bounds = vec![];
|
||||||
gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| {
|
gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| {
|
||||||
for pred in generics.predicates {
|
for pred in generics.predicates {
|
||||||
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) = pred
|
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
|
||||||
|
pred.kind
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
@ -267,12 +268,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
};
|
};
|
||||||
debug!(?generics_fn);
|
debug!(?generics_fn);
|
||||||
generics_fn.predicates.iter().for_each(|predicate| {
|
generics_fn.predicates.iter().for_each(|predicate| {
|
||||||
let BoundPredicate(WhereBoundPredicate {
|
let BoundPredicate(WhereBoundPredicate { bounded_ty, bounds, .. }) = predicate.kind
|
||||||
span: bounded_span,
|
|
||||||
bounded_ty,
|
|
||||||
bounds,
|
|
||||||
..
|
|
||||||
}) = predicate
|
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -287,7 +283,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
.rfind(|param| param.def_id.to_def_id() == defid)
|
.rfind(|param| param.def_id.to_def_id() == defid)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
suggestions.push((bounded_span.shrink_to_hi(), " + 'static".to_string()));
|
suggestions.push((predicate.span.shrink_to_hi(), " + 'static".to_string()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -952,7 +948,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
|
|
||||||
if let Ok(Some(instance)) = ty::Instance::try_resolve(
|
if let Ok(Some(instance)) = ty::Instance::try_resolve(
|
||||||
tcx,
|
tcx,
|
||||||
self.param_env,
|
self.infcx.typing_env(self.infcx.param_env),
|
||||||
*fn_did,
|
*fn_did,
|
||||||
self.infcx.resolve_vars_if_possible(args),
|
self.infcx.resolve_vars_if_possible(args),
|
||||||
) {
|
) {
|
||||||
|
@ -1091,7 +1087,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
peeled_ty = ref_ty;
|
peeled_ty = ref_ty;
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
if !self.infcx.type_is_copy_modulo_regions(self.param_env, peeled_ty) {
|
if !self.infcx.type_is_copy_modulo_regions(self.infcx.param_env, peeled_ty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1103,7 +1099,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
peeled_ty,
|
peeled_ty,
|
||||||
liberated_sig.c_variadic,
|
liberated_sig.c_variadic,
|
||||||
hir::Safety::Safe,
|
hir::Safety::Safe,
|
||||||
rustc_target::spec::abi::Abi::Rust,
|
rustc_abi::ExternAbi::Rust,
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
let closure_ty = Ty::new_closure(
|
let closure_ty = Ty::new_closure(
|
||||||
|
@ -1160,7 +1156,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let ocx = ObligationCtxt::new(&self.infcx);
|
let ocx = ObligationCtxt::new(&self.infcx);
|
||||||
ocx.register_obligations(preds.iter().map(|(pred, span)| {
|
ocx.register_obligations(preds.iter().map(|(pred, span)| {
|
||||||
trace!(?pred);
|
trace!(?pred);
|
||||||
Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred)
|
Obligation::misc(tcx, span, self.mir_def_id(), self.infcx.param_env, pred)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if ocx.select_all_or_error().is_empty() && count > 0 {
|
if ocx.select_all_or_error().is_empty() && count > 0 {
|
||||||
|
|
|
@ -30,8 +30,8 @@ pub(crate) struct RegionName {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
|
/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
|
||||||
/// was named by the user would get `NamedLateParamRegion` and `'static` lifetime would get `Static`.
|
/// was named by the user would get `NamedLateParamRegion` and `'static` lifetime would get
|
||||||
/// This helps to print the right kinds of diagnostics.
|
/// `Static`. This helps to print the right kinds of diagnostics.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) enum RegionNameSource {
|
pub(crate) enum RegionNameSource {
|
||||||
/// A bound (not free) region that was instantiated at the def site (not an HRTB).
|
/// A bound (not free) region that was instantiated at the def site (not an HRTB).
|
||||||
|
@ -301,7 +301,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ReLateParam(late_param) => match late_param.bound_region {
|
ty::ReLateParam(late_param) => match late_param.bound_region {
|
||||||
ty::BoundRegionKind::BrNamed(region_def_id, name) => {
|
ty::BoundRegionKind::Named(region_def_id, name) => {
|
||||||
// Get the span to point to, even if we don't use the name.
|
// Get the span to point to, even if we don't use the name.
|
||||||
let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP);
|
let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP);
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -332,7 +332,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::BoundRegionKind::BrEnv => {
|
ty::BoundRegionKind::ClosureEnv => {
|
||||||
let def_ty = self.regioncx.universal_regions().defining_ty;
|
let def_ty = self.regioncx.universal_regions().defining_ty;
|
||||||
|
|
||||||
let closure_kind = match def_ty {
|
let closure_kind = match def_ty {
|
||||||
|
@ -369,7 +369,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::BoundRegionKind::BrAnon => None,
|
ty::BoundRegionKind::Anon => None,
|
||||||
},
|
},
|
||||||
|
|
||||||
ty::ReBound(..)
|
ty::ReBound(..)
|
||||||
|
@ -825,8 +825,8 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||||
/// async fn foo() -> i32 { 2 }
|
/// async fn foo() -> i32 { 2 }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// this function, given the lowered return type of `foo`, an [`OpaqueDef`] that implements `Future<Output=i32>`,
|
/// this function, given the lowered return type of `foo`, an [`OpaqueDef`] that implements
|
||||||
/// returns the `i32`.
|
/// `Future<Output=i32>`, returns the `i32`.
|
||||||
///
|
///
|
||||||
/// [`OpaqueDef`]: hir::TyKind::OpaqueDef
|
/// [`OpaqueDef`]: hir::TyKind::OpaqueDef
|
||||||
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
|
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use std::collections::BTreeMap;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
use rustc_abi::FieldIdx;
|
||||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||||
use rustc_data_structures::graph::dominators::Dominators;
|
use rustc_data_structures::graph::dominators::Dominators;
|
||||||
use rustc_errors::Diag;
|
use rustc_errors::Diag;
|
||||||
|
@ -36,26 +36,33 @@ use rustc_middle::mir::*;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
|
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_mir_dataflow::Analysis;
|
|
||||||
use rustc_mir_dataflow::impls::{
|
use rustc_mir_dataflow::impls::{
|
||||||
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
||||||
};
|
};
|
||||||
use rustc_mir_dataflow::move_paths::{
|
use rustc_mir_dataflow::move_paths::{
|
||||||
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
|
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
|
||||||
};
|
};
|
||||||
|
use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
|
||||||
use rustc_session::lint::builtin::UNUSED_MUT;
|
use rustc_session::lint::builtin::UNUSED_MUT;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::abi::FieldIdx;
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use self::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
|
use crate::borrow_set::{BorrowData, BorrowSet};
|
||||||
use self::location::LocationTable;
|
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
||||||
use self::path_utils::*;
|
use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
|
||||||
use self::prefixes::PrefixSet;
|
use crate::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
|
||||||
|
use crate::location::LocationTable;
|
||||||
|
use crate::nll::PoloniusOutput;
|
||||||
|
use crate::path_utils::*;
|
||||||
|
use crate::place_ext::PlaceExt;
|
||||||
|
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
||||||
|
use crate::prefixes::PrefixSet;
|
||||||
|
use crate::region_infer::RegionInferenceContext;
|
||||||
|
use crate::renumber::RegionCtxt;
|
||||||
use crate::session_diagnostics::VarNeedNotMut;
|
use crate::session_diagnostics::VarNeedNotMut;
|
||||||
|
|
||||||
pub mod borrow_set;
|
mod borrow_set;
|
||||||
mod borrowck_errors;
|
mod borrowck_errors;
|
||||||
mod constraints;
|
mod constraints;
|
||||||
mod dataflow;
|
mod dataflow;
|
||||||
|
@ -81,18 +88,11 @@ mod util;
|
||||||
/// A public API provided for the Rust compiler consumers.
|
/// A public API provided for the Rust compiler consumers.
|
||||||
pub mod consumers;
|
pub mod consumers;
|
||||||
|
|
||||||
use borrow_set::{BorrowData, BorrowSet};
|
|
||||||
use dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows};
|
|
||||||
use nll::PoloniusOutput;
|
|
||||||
use place_ext::PlaceExt;
|
|
||||||
use places_conflict::{PlaceConflictBias, places_conflict};
|
|
||||||
use region_infer::RegionInferenceContext;
|
|
||||||
use renumber::RegionCtxt;
|
|
||||||
|
|
||||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
||||||
/// Associate some local constants with the `'tcx` lifetime
|
/// Associate some local constants with the `'tcx` lifetime
|
||||||
struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
|
struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
|
||||||
|
|
||||||
impl<'tcx> TyCtxtConsts<'tcx> {
|
impl<'tcx> TyCtxtConsts<'tcx> {
|
||||||
const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
|
const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,6 @@ fn do_mir_borrowck<'tcx>(
|
||||||
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
|
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
|
||||||
let def = input_body.source.def_id().expect_local();
|
let def = input_body.source.def_id().expect_local();
|
||||||
let infcx = BorrowckInferCtxt::new(tcx, def);
|
let infcx = BorrowckInferCtxt::new(tcx, def);
|
||||||
let param_env = tcx.param_env(def);
|
|
||||||
|
|
||||||
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
|
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
|
||||||
for var_debug_info in &input_body.var_debug_info {
|
for var_debug_info in &input_body.var_debug_info {
|
||||||
|
@ -162,7 +161,7 @@ fn do_mir_borrowck<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diags = diags::BorrowckDiags::new();
|
let diags = &mut diags::BorrowckDiags::new();
|
||||||
|
|
||||||
// Gather the upvars of a closure, if any.
|
// Gather the upvars of a closure, if any.
|
||||||
if let Some(e) = input_body.tainted_by_errors {
|
if let Some(e) = input_body.tainted_by_errors {
|
||||||
|
@ -175,8 +174,7 @@ fn do_mir_borrowck<'tcx>(
|
||||||
// will have a lifetime tied to the inference context.
|
// will have a lifetime tied to the inference context.
|
||||||
let mut body_owned = input_body.clone();
|
let mut body_owned = input_body.clone();
|
||||||
let mut promoted = input_promoted.to_owned();
|
let mut promoted = input_promoted.to_owned();
|
||||||
let free_regions =
|
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
|
||||||
nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted);
|
|
||||||
let body = &body_owned; // no further changes
|
let body = &body_owned; // no further changes
|
||||||
|
|
||||||
// FIXME(-Znext-solver): A bit dubious that we're only registering
|
// FIXME(-Znext-solver): A bit dubious that we're only registering
|
||||||
|
@ -192,7 +190,7 @@ fn do_mir_borrowck<'tcx>(
|
||||||
.iter_enumerated()
|
.iter_enumerated()
|
||||||
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
|
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
|
||||||
|
|
||||||
let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
||||||
.iterate_to_fixpoint(tcx, body, Some("borrowck"))
|
.iterate_to_fixpoint(tcx, body, Some("borrowck"))
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
|
|
||||||
|
@ -213,11 +211,9 @@ fn do_mir_borrowck<'tcx>(
|
||||||
body,
|
body,
|
||||||
&promoted,
|
&promoted,
|
||||||
&location_table,
|
&location_table,
|
||||||
param_env,
|
flow_inits,
|
||||||
&mut flow_inits,
|
|
||||||
&move_data,
|
&move_data,
|
||||||
&borrow_set,
|
&borrow_set,
|
||||||
tcx.closure_captures(def),
|
|
||||||
consumer_options,
|
consumer_options,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -227,35 +223,7 @@ fn do_mir_borrowck<'tcx>(
|
||||||
|
|
||||||
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
||||||
// information.
|
// information.
|
||||||
nll::dump_annotation(
|
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, &opaque_type_values, diags);
|
||||||
&infcx,
|
|
||||||
body,
|
|
||||||
®ioncx,
|
|
||||||
&opt_closure_req,
|
|
||||||
&opaque_type_values,
|
|
||||||
&mut diags,
|
|
||||||
);
|
|
||||||
|
|
||||||
// The various `flow_*` structures can be large. We drop `flow_inits` here
|
|
||||||
// so it doesn't overlap with the others below. This reduces peak memory
|
|
||||||
// usage significantly on some benchmarks.
|
|
||||||
drop(flow_inits);
|
|
||||||
|
|
||||||
let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set).iterate_to_fixpoint(
|
|
||||||
tcx,
|
|
||||||
body,
|
|
||||||
Some("borrowck"),
|
|
||||||
);
|
|
||||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
|
|
||||||
tcx,
|
|
||||||
body,
|
|
||||||
Some("borrowck"),
|
|
||||||
);
|
|
||||||
let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
|
|
||||||
tcx,
|
|
||||||
body,
|
|
||||||
Some("borrowck"),
|
|
||||||
);
|
|
||||||
|
|
||||||
let movable_coroutine =
|
let movable_coroutine =
|
||||||
// The first argument is the coroutine type passed by value
|
// The first argument is the coroutine type passed by value
|
||||||
|
@ -275,7 +243,6 @@ fn do_mir_borrowck<'tcx>(
|
||||||
let promoted_body = &promoted[idx];
|
let promoted_body = &promoted[idx];
|
||||||
let mut promoted_mbcx = MirBorrowckCtxt {
|
let mut promoted_mbcx = MirBorrowckCtxt {
|
||||||
infcx: &infcx,
|
infcx: &infcx,
|
||||||
param_env,
|
|
||||||
body: promoted_body,
|
body: promoted_body,
|
||||||
move_data: &move_data,
|
move_data: &move_data,
|
||||||
location_table: &location_table, // no need to create a real one for the promoted, it is not used
|
location_table: &location_table, // no need to create a real one for the promoted, it is not used
|
||||||
|
@ -299,7 +266,6 @@ fn do_mir_borrowck<'tcx>(
|
||||||
};
|
};
|
||||||
MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
|
MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
|
||||||
promoted_mbcx.report_move_errors();
|
promoted_mbcx.report_move_errors();
|
||||||
diags = promoted_mbcx.diags;
|
|
||||||
|
|
||||||
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
|
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
|
||||||
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
|
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
|
||||||
|
@ -316,7 +282,6 @@ fn do_mir_borrowck<'tcx>(
|
||||||
|
|
||||||
let mut mbcx = MirBorrowckCtxt {
|
let mut mbcx = MirBorrowckCtxt {
|
||||||
infcx: &infcx,
|
infcx: &infcx,
|
||||||
param_env,
|
|
||||||
body,
|
body,
|
||||||
move_data: &move_data,
|
move_data: &move_data,
|
||||||
location_table: &location_table,
|
location_table: &location_table,
|
||||||
|
@ -342,16 +307,11 @@ fn do_mir_borrowck<'tcx>(
|
||||||
// Compute and report region errors, if any.
|
// Compute and report region errors, if any.
|
||||||
mbcx.report_region_errors(nll_errors);
|
mbcx.report_region_errors(nll_errors);
|
||||||
|
|
||||||
let mut results = BorrowckResults {
|
let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
|
||||||
ever_inits: flow_ever_inits,
|
visit_results(
|
||||||
uninits: flow_uninits,
|
|
||||||
borrows: flow_borrows,
|
|
||||||
};
|
|
||||||
|
|
||||||
rustc_mir_dataflow::visit_results(
|
|
||||||
body,
|
body,
|
||||||
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
||||||
&mut results,
|
&mut flow_results,
|
||||||
&mut mbcx,
|
&mut mbcx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -434,15 +394,58 @@ fn do_mir_borrowck<'tcx>(
|
||||||
(result, body_with_facts)
|
(result, body_with_facts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BorrowckInferCtxt<'tcx> {
|
fn get_flow_results<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
body: &'a Body<'tcx>,
|
||||||
|
move_data: &'a MoveData<'tcx>,
|
||||||
|
borrow_set: &'a BorrowSet<'tcx>,
|
||||||
|
regioncx: &RegionInferenceContext<'tcx>,
|
||||||
|
) -> Results<'tcx, Borrowck<'a, 'tcx>> {
|
||||||
|
// We compute these three analyses individually, but them combine them into
|
||||||
|
// a single results so that `mbcx` can visit them all together.
|
||||||
|
let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
Some("borrowck"),
|
||||||
|
);
|
||||||
|
let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
Some("borrowck"),
|
||||||
|
);
|
||||||
|
let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
Some("borrowck"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let analysis = Borrowck {
|
||||||
|
borrows: borrows.analysis,
|
||||||
|
uninits: uninits.analysis,
|
||||||
|
ever_inits: ever_inits.analysis,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len());
|
||||||
|
assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len());
|
||||||
|
let entry_sets: EntrySets<'_, Borrowck<'_, '_>> =
|
||||||
|
itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets)
|
||||||
|
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Results { analysis, entry_sets }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct BorrowckInferCtxt<'tcx> {
|
||||||
pub(crate) infcx: InferCtxt<'tcx>,
|
pub(crate) infcx: InferCtxt<'tcx>,
|
||||||
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
|
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
|
||||||
|
pub(crate) param_env: ParamEnv<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> BorrowckInferCtxt<'tcx> {
|
impl<'tcx> BorrowckInferCtxt<'tcx> {
|
||||||
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
|
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
|
||||||
let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id));
|
let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id));
|
||||||
BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) }
|
let param_env = tcx.param_env(def_id);
|
||||||
|
BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn next_region_var<F>(
|
pub(crate) fn next_region_var<F>(
|
||||||
|
@ -521,7 +524,6 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
|
||||||
|
|
||||||
struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
||||||
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
||||||
param_env: ParamEnv<'tcx>,
|
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
move_data: &'a MoveData<'tcx>,
|
move_data: &'a MoveData<'tcx>,
|
||||||
|
|
||||||
|
@ -587,7 +589,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
||||||
/// Results of Polonius analysis.
|
/// Results of Polonius analysis.
|
||||||
polonius_output: Option<Box<PoloniusOutput>>,
|
polonius_output: Option<Box<PoloniusOutput>>,
|
||||||
|
|
||||||
diags: diags::BorrowckDiags<'infcx, 'tcx>,
|
diags: &'a mut diags::BorrowckDiags<'infcx, 'tcx>,
|
||||||
move_errors: Vec<MoveError<'tcx>>,
|
move_errors: Vec<MoveError<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,14 +598,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
||||||
// 2. loans made in overlapping scopes do not conflict
|
// 2. loans made in overlapping scopes do not conflict
|
||||||
// 3. assignments do not affect things loaned out as immutable
|
// 3. assignments do not affect things loaned out as immutable
|
||||||
// 4. moves do not affect things loaned out in any way
|
// 4. moves do not affect things loaned out in any way
|
||||||
impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
for MirBorrowckCtxt<'a, '_, 'tcx>
|
|
||||||
{
|
|
||||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
|
||||||
|
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||||
state: &BorrowckDomain<'a, 'tcx>,
|
state: &BorrowckDomain<'a, 'tcx>,
|
||||||
stmt: &'a Statement<'tcx>,
|
stmt: &'a Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -638,7 +636,9 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
StatementKind::Intrinsic(box kind) => match kind {
|
StatementKind::Intrinsic(box kind) => match kind {
|
||||||
NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), state),
|
NonDivergingIntrinsic::Assume(op) => {
|
||||||
|
self.consume_operand(location, (op, span), state);
|
||||||
|
}
|
||||||
NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
|
NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
|
||||||
span,
|
span,
|
||||||
"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
|
"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
|
||||||
|
@ -652,6 +652,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||||
| StatementKind::Coverage(..)
|
| StatementKind::Coverage(..)
|
||||||
// These do not actually affect borrowck
|
// These do not actually affect borrowck
|
||||||
| StatementKind::ConstEvalCounter
|
| StatementKind::ConstEvalCounter
|
||||||
|
// This do not affect borrowck
|
||||||
|
| StatementKind::BackwardIncompatibleDropHint { .. }
|
||||||
| StatementKind::StorageLive(..) => {}
|
| StatementKind::StorageLive(..) => {}
|
||||||
StatementKind::StorageDead(local) => {
|
StatementKind::StorageDead(local) => {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
|
@ -673,7 +675,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||||
|
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||||
state: &BorrowckDomain<'a, 'tcx>,
|
state: &BorrowckDomain<'a, 'tcx>,
|
||||||
term: &'a Terminator<'tcx>,
|
term: &'a Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -786,7 +788,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||||
|
|
||||||
fn visit_terminator_after_primary_effect(
|
fn visit_terminator_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||||
state: &BorrowckDomain<'a, 'tcx>,
|
state: &BorrowckDomain<'a, 'tcx>,
|
||||||
term: &'a Terminator<'tcx>,
|
term: &'a Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -2105,7 +2107,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
| Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
|
| Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
|
||||||
let is_local_mutation_allowed = match mut_borrow_kind {
|
let is_local_mutation_allowed = match mut_borrow_kind {
|
||||||
// `ClosureCapture` is used for mutable variable with an immutable binding.
|
// `ClosureCapture` is used for mutable variable with an immutable binding.
|
||||||
// This is only behaviour difference between `ClosureCapture` and mutable borrows.
|
// This is only behaviour difference between `ClosureCapture` and mutable
|
||||||
|
// borrows.
|
||||||
MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
|
MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
|
||||||
MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
|
MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
|
||||||
is_local_mutation_allowed
|
is_local_mutation_allowed
|
||||||
|
@ -2350,23 +2353,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
) => Err(place),
|
) => Err(place),
|
||||||
(Mutability::Not, LocalMutationIsAllowed::Yes)
|
(Mutability::Not, LocalMutationIsAllowed::Yes)
|
||||||
| (Mutability::Mut, _) => {
|
| (Mutability::Mut, _) => {
|
||||||
// Subtle: this is an upvar
|
// Subtle: this is an upvar reference, so it looks like
|
||||||
// reference, so it looks like
|
// `self.foo` -- we want to double check that the location
|
||||||
// `self.foo` -- we want to double
|
// `*self` is mutable (i.e., this is not a `Fn` closure). But
|
||||||
// check that the location `*self`
|
// if that check succeeds, we want to *blame* the mutability on
|
||||||
// is mutable (i.e., this is not a
|
// `place` (that is, `self.foo`). This is used to propagate the
|
||||||
// `Fn` closure). But if that
|
// info about whether mutability declarations are used
|
||||||
// check succeeds, we want to
|
// outwards, so that we register the outer variable as mutable.
|
||||||
// *blame* the mutability on
|
// Otherwise a test like this fails to record the `mut` as
|
||||||
// `place` (that is,
|
// needed:
|
||||||
// `self.foo`). This is used to
|
|
||||||
// propagate the info about
|
|
||||||
// whether mutability declarations
|
|
||||||
// are used outwards, so that we register
|
|
||||||
// the outer variable as mutable. Otherwise a
|
|
||||||
// test like this fails to record the `mut`
|
|
||||||
// as needed:
|
|
||||||
//
|
|
||||||
// ```
|
// ```
|
||||||
// fn foo<F: FnOnce()>(_f: F) { }
|
// fn foo<F: FnOnce()>(_f: F) { }
|
||||||
// fn main() {
|
// fn main() {
|
||||||
|
@ -2511,7 +2506,7 @@ mod diags {
|
||||||
// Buffer any move errors that we collected and de-duplicated.
|
// Buffer any move errors that we collected and de-duplicated.
|
||||||
for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) {
|
for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) {
|
||||||
// We have already set tainted for this error, so just buffer it.
|
// We have already set tainted for this error, so just buffer it.
|
||||||
self.diags.buffered_diags.push(BufferedDiag::Error(diag));
|
self.diags.buffer_error(diag);
|
||||||
}
|
}
|
||||||
for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) {
|
for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) {
|
||||||
if count > 10 {
|
if count > 10 {
|
||||||
|
@ -2519,7 +2514,7 @@ mod diags {
|
||||||
#[allow(rustc::untranslatable_diagnostic)]
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||||
}
|
}
|
||||||
self.diags.buffered_diags.push(BufferedDiag::Error(diag));
|
self.diags.buffer_error(diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.diags.buffered_diags.is_empty() {
|
if !self.diags.buffered_diags.is_empty() {
|
||||||
|
|
|
@ -30,7 +30,7 @@ use crate::diagnostics::RegionErrors;
|
||||||
use crate::facts::{AllFacts, AllFactsExt, RustcFacts};
|
use crate::facts::{AllFacts, AllFactsExt, RustcFacts};
|
||||||
use crate::location::LocationTable;
|
use crate::location::LocationTable;
|
||||||
use crate::region_infer::RegionInferenceContext;
|
use crate::region_infer::RegionInferenceContext;
|
||||||
use crate::type_check::{self, MirTypeckRegionConstraints, MirTypeckResults};
|
use crate::type_check::{self, MirTypeckResults};
|
||||||
use crate::universal_regions::UniversalRegions;
|
use crate::universal_regions::UniversalRegions;
|
||||||
use crate::{BorrowckInferCtxt, polonius, renumber};
|
use crate::{BorrowckInferCtxt, polonius, renumber};
|
||||||
|
|
||||||
|
@ -50,10 +50,9 @@ pub(crate) struct NllOutput<'tcx> {
|
||||||
/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
|
/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
|
||||||
/// regions (e.g., region parameters) declared on the function. That set will need to be given to
|
/// regions (e.g., region parameters) declared on the function. That set will need to be given to
|
||||||
/// `compute_regions`.
|
/// `compute_regions`.
|
||||||
#[instrument(skip(infcx, param_env, body, promoted), level = "debug")]
|
#[instrument(skip(infcx, body, promoted), level = "debug")]
|
||||||
pub(crate) fn replace_regions_in_mir<'tcx>(
|
pub(crate) fn replace_regions_in_mir<'tcx>(
|
||||||
infcx: &BorrowckInferCtxt<'tcx>,
|
infcx: &BorrowckInferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
body: &mut Body<'tcx>,
|
body: &mut Body<'tcx>,
|
||||||
promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
|
promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
|
||||||
) -> UniversalRegions<'tcx> {
|
) -> UniversalRegions<'tcx> {
|
||||||
|
@ -62,7 +61,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
|
||||||
debug!(?def);
|
debug!(?def);
|
||||||
|
|
||||||
// Compute named region information. This also renumbers the inputs/outputs.
|
// Compute named region information. This also renumbers the inputs/outputs.
|
||||||
let universal_regions = UniversalRegions::new(infcx, def, param_env);
|
let universal_regions = UniversalRegions::new(infcx, def);
|
||||||
|
|
||||||
// Replace all remaining regions with fresh inference variables.
|
// Replace all remaining regions with fresh inference variables.
|
||||||
renumber::renumber_mir(infcx, body, promoted);
|
renumber::renumber_mir(infcx, body, promoted);
|
||||||
|
@ -81,11 +80,9 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||||
location_table: &LocationTable,
|
location_table: &LocationTable,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
upvars: &[&ty::CapturedPlace<'tcx>],
|
|
||||||
consumer_options: Option<ConsumerOptions>,
|
consumer_options: Option<ConsumerOptions>,
|
||||||
) -> NllOutput<'tcx> {
|
) -> NllOutput<'tcx> {
|
||||||
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
||||||
|
@ -96,41 +93,27 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
let mut all_facts =
|
let mut all_facts =
|
||||||
(polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
|
(polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
|
||||||
|
|
||||||
let universal_regions = Rc::new(universal_regions);
|
|
||||||
|
|
||||||
let elements = Rc::new(DenseLocationMap::new(body));
|
let elements = Rc::new(DenseLocationMap::new(body));
|
||||||
|
|
||||||
// Run the MIR type-checker.
|
// Run the MIR type-checker.
|
||||||
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
|
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
|
||||||
type_check::type_check(
|
type_check::type_check(
|
||||||
infcx,
|
infcx,
|
||||||
param_env,
|
|
||||||
body,
|
body,
|
||||||
promoted,
|
promoted,
|
||||||
Rc::clone(&universal_regions),
|
universal_regions,
|
||||||
location_table,
|
location_table,
|
||||||
borrow_set,
|
borrow_set,
|
||||||
&mut all_facts,
|
&mut all_facts,
|
||||||
flow_inits,
|
flow_inits,
|
||||||
move_data,
|
move_data,
|
||||||
Rc::clone(&elements),
|
Rc::clone(&elements),
|
||||||
upvars,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the region inference context, taking ownership of the
|
// Create the region inference context, taking ownership of the
|
||||||
// region inference data that was contained in `infcx`, and the
|
// region inference data that was contained in `infcx`, and the
|
||||||
// base constraints generated by the type-check.
|
// base constraints generated by the type-check.
|
||||||
let var_origins = infcx.get_region_var_origins();
|
let var_origins = infcx.get_region_var_origins();
|
||||||
let MirTypeckRegionConstraints {
|
|
||||||
placeholder_indices,
|
|
||||||
placeholder_index_to_region: _,
|
|
||||||
liveness_constraints,
|
|
||||||
mut outlives_constraints,
|
|
||||||
mut member_constraints,
|
|
||||||
universe_causes,
|
|
||||||
type_tests,
|
|
||||||
} = constraints;
|
|
||||||
let placeholder_indices = Rc::new(placeholder_indices);
|
|
||||||
|
|
||||||
// If requested, emit legacy polonius facts.
|
// If requested, emit legacy polonius facts.
|
||||||
polonius::emit_facts(
|
polonius::emit_facts(
|
||||||
|
@ -140,31 +123,14 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
body,
|
body,
|
||||||
borrow_set,
|
borrow_set,
|
||||||
move_data,
|
move_data,
|
||||||
&universal_regions,
|
|
||||||
&universal_region_relations,
|
&universal_region_relations,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(guar) = universal_regions.tainted_by_errors() {
|
|
||||||
// Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all
|
|
||||||
// outlives bounds that we may end up checking.
|
|
||||||
outlives_constraints = Default::default();
|
|
||||||
member_constraints = Default::default();
|
|
||||||
|
|
||||||
// Also taint the entire scope.
|
|
||||||
infcx.set_tainted_by_errors(guar);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut regioncx = RegionInferenceContext::new(
|
let mut regioncx = RegionInferenceContext::new(
|
||||||
infcx,
|
infcx,
|
||||||
var_origins,
|
var_origins,
|
||||||
universal_regions,
|
constraints,
|
||||||
placeholder_indices,
|
|
||||||
universal_region_relations,
|
universal_region_relations,
|
||||||
outlives_constraints,
|
|
||||||
member_constraints,
|
|
||||||
universe_causes,
|
|
||||||
type_tests,
|
|
||||||
liveness_constraints,
|
|
||||||
elements,
|
elements,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
use rustc_abi::FieldIdx;
|
||||||
use rustc_data_structures::graph::dominators::Dominators;
|
use rustc_data_structures::graph::dominators::Dominators;
|
||||||
use rustc_middle::mir::{BasicBlock, Body, BorrowKind, Location, Place, PlaceRef, ProjectionElem};
|
use rustc_middle::mir::{BasicBlock, Body, BorrowKind, Location, Place, PlaceRef, ProjectionElem};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_target::abi::FieldIdx;
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
|
use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
|
||||||
|
|
|
@ -88,6 +88,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
|
||||||
| StatementKind::Nop
|
| StatementKind::Nop
|
||||||
| StatementKind::Retag { .. }
|
| StatementKind::Retag { .. }
|
||||||
| StatementKind::Deinit(..)
|
| StatementKind::Deinit(..)
|
||||||
|
| StatementKind::BackwardIncompatibleDropHint { .. }
|
||||||
| StatementKind::SetDiscriminant { .. } => {
|
| StatementKind::SetDiscriminant { .. } => {
|
||||||
bug!("Statement not allowed in this MIR phase")
|
bug!("Statement not allowed in this MIR phase")
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ use crate::borrow_set::BorrowSet;
|
||||||
use crate::facts::{AllFacts, PoloniusRegionVid};
|
use crate::facts::{AllFacts, PoloniusRegionVid};
|
||||||
use crate::location::LocationTable;
|
use crate::location::LocationTable;
|
||||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||||
use crate::universal_regions::UniversalRegions;
|
|
||||||
|
|
||||||
mod loan_invalidations;
|
mod loan_invalidations;
|
||||||
mod loan_kills;
|
mod loan_kills;
|
||||||
|
@ -32,7 +31,6 @@ pub(crate) fn emit_facts<'tcx>(
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
move_data: &MoveData<'_>,
|
move_data: &MoveData<'_>,
|
||||||
universal_regions: &UniversalRegions<'_>,
|
|
||||||
universal_region_relations: &UniversalRegionRelations<'_>,
|
universal_region_relations: &UniversalRegionRelations<'_>,
|
||||||
) {
|
) {
|
||||||
let Some(all_facts) = all_facts else {
|
let Some(all_facts) = all_facts else {
|
||||||
|
@ -41,12 +39,7 @@ pub(crate) fn emit_facts<'tcx>(
|
||||||
};
|
};
|
||||||
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
|
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
|
||||||
emit_move_facts(all_facts, move_data, location_table, body);
|
emit_move_facts(all_facts, move_data, location_table, body);
|
||||||
emit_universal_region_facts(
|
emit_universal_region_facts(all_facts, borrow_set, universal_region_relations);
|
||||||
all_facts,
|
|
||||||
borrow_set,
|
|
||||||
universal_regions,
|
|
||||||
universal_region_relations,
|
|
||||||
);
|
|
||||||
emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
|
emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
|
||||||
emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);
|
emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +122,6 @@ fn emit_move_facts(
|
||||||
fn emit_universal_region_facts(
|
fn emit_universal_region_facts(
|
||||||
all_facts: &mut AllFacts,
|
all_facts: &mut AllFacts,
|
||||||
borrow_set: &BorrowSet<'_>,
|
borrow_set: &BorrowSet<'_>,
|
||||||
universal_regions: &UniversalRegions<'_>,
|
|
||||||
universal_region_relations: &UniversalRegionRelations<'_>,
|
universal_region_relations: &UniversalRegionRelations<'_>,
|
||||||
) {
|
) {
|
||||||
// 1: universal regions are modeled in Polonius as a pair:
|
// 1: universal regions are modeled in Polonius as a pair:
|
||||||
|
@ -138,9 +130,10 @@ fn emit_universal_region_facts(
|
||||||
// the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
|
// the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
|
||||||
// added to the existing number of loans, as if they succeeded them in the set.
|
// added to the existing number of loans, as if they succeeded them in the set.
|
||||||
//
|
//
|
||||||
|
let universal_regions = &universal_region_relations.universal_regions;
|
||||||
all_facts
|
all_facts
|
||||||
.universal_region
|
.universal_region
|
||||||
.extend(universal_regions.universal_regions().map(PoloniusRegionVid::from));
|
.extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from));
|
||||||
let borrow_count = borrow_set.len();
|
let borrow_count = borrow_set.len();
|
||||||
debug!(
|
debug!(
|
||||||
"emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
|
"emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
|
||||||
|
@ -148,7 +141,7 @@ fn emit_universal_region_facts(
|
||||||
borrow_count
|
borrow_count
|
||||||
);
|
);
|
||||||
|
|
||||||
for universal_region in universal_regions.universal_regions() {
|
for universal_region in universal_regions.universal_regions_iter() {
|
||||||
let universal_region_idx = universal_region.index();
|
let universal_region_idx = universal_region.index();
|
||||||
let placeholder_loan_idx = borrow_count + universal_region_idx;
|
let placeholder_loan_idx = borrow_count + universal_region_idx;
|
||||||
all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
|
all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
|
||||||
|
|
|
@ -53,7 +53,7 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
|
||||||
// may hold one further down (e.g., we never return
|
// may hold one further down (e.g., we never return
|
||||||
// downcasts here, but may return a base of a downcast).
|
// downcasts here, but may return a base of a downcast).
|
||||||
|
|
||||||
'cursor: loop {
|
loop {
|
||||||
match cursor.last_projection() {
|
match cursor.last_projection() {
|
||||||
None => {
|
None => {
|
||||||
self.next = None;
|
self.next = None;
|
||||||
|
@ -72,7 +72,6 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
|
||||||
| ProjectionElem::ConstantIndex { .. }
|
| ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Index(_) => {
|
| ProjectionElem::Index(_) => {
|
||||||
cursor = cursor_base;
|
cursor = cursor_base;
|
||||||
continue 'cursor;
|
|
||||||
}
|
}
|
||||||
ProjectionElem::Subtype(..) => {
|
ProjectionElem::Subtype(..) => {
|
||||||
panic!("Subtype projection is not allowed before borrow check")
|
panic!("Subtype projection is not allowed before borrow check")
|
||||||
|
|
|
@ -23,7 +23,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
for region in self.regions() {
|
for region in self.regions() {
|
||||||
if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin {
|
if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin {
|
||||||
let classification = self.universal_regions.region_classification(region).unwrap();
|
let classification =
|
||||||
|
self.universal_regions().region_classification(region).unwrap();
|
||||||
let outlived_by = self.universal_region_relations.regions_outlived_by(region);
|
let outlived_by = self.universal_region_relations.regions_outlived_by(region);
|
||||||
writeln!(
|
writeln!(
|
||||||
out,
|
out,
|
||||||
|
|
|
@ -31,11 +31,9 @@ use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
|
||||||
use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
|
use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
|
||||||
use crate::nll::PoloniusOutput;
|
use crate::nll::PoloniusOutput;
|
||||||
use crate::region_infer::reverse_sccs::ReverseSccGraph;
|
use crate::region_infer::reverse_sccs::ReverseSccGraph;
|
||||||
use crate::region_infer::values::{
|
use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, ToElementIndex};
|
||||||
LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
|
|
||||||
};
|
|
||||||
use crate::type_check::Locations;
|
|
||||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||||
|
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||||
use crate::universal_regions::UniversalRegions;
|
use crate::universal_regions::UniversalRegions;
|
||||||
|
|
||||||
mod dump_mir;
|
mod dump_mir;
|
||||||
|
@ -99,9 +97,9 @@ impl RegionTracker {
|
||||||
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
|
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
|
||||||
let (representative_is_placeholder, representative_is_existential) = match definition.origin
|
let (representative_is_placeholder, representative_is_existential) = match definition.origin
|
||||||
{
|
{
|
||||||
rustc_infer::infer::NllRegionVariableOrigin::FreeRegion => (false, false),
|
NllRegionVariableOrigin::FreeRegion => (false, false),
|
||||||
rustc_infer::infer::NllRegionVariableOrigin::Placeholder(_) => (true, false),
|
NllRegionVariableOrigin::Placeholder(_) => (true, false),
|
||||||
rustc_infer::infer::NllRegionVariableOrigin::Existential { .. } => (false, true),
|
NllRegionVariableOrigin::Existential { .. } => (false, true),
|
||||||
};
|
};
|
||||||
|
|
||||||
let placeholder_universe =
|
let placeholder_universe =
|
||||||
|
@ -191,10 +189,6 @@ pub struct RegionInferenceContext<'tcx> {
|
||||||
/// Type constraints that we check after solving.
|
/// Type constraints that we check after solving.
|
||||||
type_tests: Vec<TypeTest<'tcx>>,
|
type_tests: Vec<TypeTest<'tcx>>,
|
||||||
|
|
||||||
/// Information about the universally quantified regions in scope
|
|
||||||
/// on this function.
|
|
||||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
|
||||||
|
|
||||||
/// Information about how the universally quantified regions in
|
/// Information about how the universally quantified regions in
|
||||||
/// scope on this function relate to one another.
|
/// scope on this function relate to one another.
|
||||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||||
|
@ -399,21 +393,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
infcx: &BorrowckInferCtxt<'tcx>,
|
infcx: &BorrowckInferCtxt<'tcx>,
|
||||||
var_infos: VarInfos,
|
var_infos: VarInfos,
|
||||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||||
placeholder_indices: Rc<PlaceholderIndices>,
|
|
||||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||||
mut outlives_constraints: OutlivesConstraintSet<'tcx>,
|
|
||||||
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
|
|
||||||
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
|
||||||
type_tests: Vec<TypeTest<'tcx>>,
|
|
||||||
liveness_constraints: LivenessValues,
|
|
||||||
elements: Rc<DenseLocationMap>,
|
elements: Rc<DenseLocationMap>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug!("universal_regions: {:#?}", universal_regions);
|
let universal_regions = &universal_region_relations.universal_regions;
|
||||||
|
let MirTypeckRegionConstraints {
|
||||||
|
placeholder_indices,
|
||||||
|
placeholder_index_to_region: _,
|
||||||
|
liveness_constraints,
|
||||||
|
mut outlives_constraints,
|
||||||
|
mut member_constraints,
|
||||||
|
universe_causes,
|
||||||
|
type_tests,
|
||||||
|
} = constraints;
|
||||||
|
|
||||||
|
debug!("universal_regions: {:#?}", universal_region_relations.universal_regions);
|
||||||
debug!("outlives constraints: {:#?}", outlives_constraints);
|
debug!("outlives constraints: {:#?}", outlives_constraints);
|
||||||
debug!("placeholder_indices: {:#?}", placeholder_indices);
|
debug!("placeholder_indices: {:#?}", placeholder_indices);
|
||||||
debug!("type tests: {:#?}", type_tests);
|
debug!("type tests: {:#?}", type_tests);
|
||||||
|
|
||||||
|
if let Some(guar) = universal_region_relations.universal_regions.tainted_by_errors() {
|
||||||
|
// Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all
|
||||||
|
// outlives bounds that we may end up checking.
|
||||||
|
outlives_constraints = Default::default();
|
||||||
|
member_constraints = Default::default();
|
||||||
|
|
||||||
|
// Also taint the entire scope.
|
||||||
|
infcx.set_tainted_by_errors(guar);
|
||||||
|
}
|
||||||
|
|
||||||
// Create a RegionDefinition for each inference variable.
|
// Create a RegionDefinition for each inference variable.
|
||||||
let definitions: IndexVec<_, _> = var_infos
|
let definitions: IndexVec<_, _> = var_infos
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -438,7 +447,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let member_constraints =
|
let member_constraints =
|
||||||
Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
|
Rc::new(member_constraints.into_mapped(|r| constraint_sccs.scc(r)));
|
||||||
|
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
var_infos,
|
var_infos,
|
||||||
|
@ -453,7 +462,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
universe_causes,
|
universe_causes,
|
||||||
scc_values,
|
scc_values,
|
||||||
type_tests,
|
type_tests,
|
||||||
universal_regions,
|
|
||||||
universal_region_relations,
|
universal_region_relations,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -518,7 +526,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
fn init_free_and_bound_regions(&mut self) {
|
fn init_free_and_bound_regions(&mut self) {
|
||||||
// Update the names (if any)
|
// Update the names (if any)
|
||||||
// This iterator has unstable order but we collect it all into an IndexVec
|
// This iterator has unstable order but we collect it all into an IndexVec
|
||||||
for (external_name, variable) in self.universal_regions.named_universal_regions() {
|
for (external_name, variable) in
|
||||||
|
self.universal_region_relations.universal_regions.named_universal_regions_iter()
|
||||||
|
{
|
||||||
debug!(
|
debug!(
|
||||||
"init_free_and_bound_regions: region {:?} has external name {:?}",
|
"init_free_and_bound_regions: region {:?} has external name {:?}",
|
||||||
variable, external_name
|
variable, external_name
|
||||||
|
@ -553,7 +563,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all the region indices.
|
/// Returns an iterator over all the region indices.
|
||||||
pub fn regions(&self) -> impl Iterator<Item = RegionVid> + 'tcx {
|
pub(crate) fn regions(&self) -> impl Iterator<Item = RegionVid> + 'tcx {
|
||||||
self.definitions.indices()
|
self.definitions.indices()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,18 +571,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
/// corresponding index.
|
/// corresponding index.
|
||||||
///
|
///
|
||||||
/// (Panics if `r` is not a registered universal region.)
|
/// (Panics if `r` is not a registered universal region.)
|
||||||
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
|
pub(crate) fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
|
||||||
self.universal_regions.to_region_vid(r)
|
self.universal_regions().to_region_vid(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all the outlives constraints.
|
/// Returns an iterator over all the outlives constraints.
|
||||||
pub fn outlives_constraints(&self) -> impl Iterator<Item = OutlivesConstraint<'tcx>> + '_ {
|
pub(crate) fn outlives_constraints(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = OutlivesConstraint<'tcx>> + '_ {
|
||||||
self.constraints.outlives().iter().copied()
|
self.constraints.outlives().iter().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
|
/// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
|
||||||
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) {
|
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) {
|
||||||
self.universal_regions.annotate(tcx, err)
|
self.universal_regions().annotate(tcx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the region `r` contains the point `p`.
|
/// Returns `true` if the region `r` contains the point `p`.
|
||||||
|
@ -684,7 +696,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
if outlives_requirements.is_empty() {
|
if outlives_requirements.is_empty() {
|
||||||
(None, errors_buffer)
|
(None, errors_buffer)
|
||||||
} else {
|
} else {
|
||||||
let num_external_vids = self.universal_regions.num_global_and_external_regions();
|
let num_external_vids = self.universal_regions().num_global_and_external_regions();
|
||||||
(
|
(
|
||||||
Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }),
|
Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }),
|
||||||
errors_buffer,
|
errors_buffer,
|
||||||
|
@ -987,7 +999,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
// always be in the root universe.
|
// always be in the root universe.
|
||||||
if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
|
if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
|
||||||
debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
|
debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
|
||||||
let static_r = self.universal_regions.fr_static;
|
let static_r = self.universal_regions().fr_static;
|
||||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||||
subject,
|
subject,
|
||||||
outlived_free_region: static_r,
|
outlived_free_region: static_r,
|
||||||
|
@ -1030,8 +1042,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
// avoid potential non-determinism we approximate this by requiring
|
// avoid potential non-determinism we approximate this by requiring
|
||||||
// T: '1 and T: '2.
|
// T: '1 and T: '2.
|
||||||
for upper_bound in non_local_ub {
|
for upper_bound in non_local_ub {
|
||||||
debug_assert!(self.universal_regions.is_universal_region(upper_bound));
|
debug_assert!(self.universal_regions().is_universal_region(upper_bound));
|
||||||
debug_assert!(!self.universal_regions.is_local_free_region(upper_bound));
|
debug_assert!(!self.universal_regions().is_local_free_region(upper_bound));
|
||||||
|
|
||||||
let requirement = ClosureOutlivesRequirement {
|
let requirement = ClosureOutlivesRequirement {
|
||||||
subject,
|
subject,
|
||||||
|
@ -1099,7 +1111,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
// To do so, we simply check every candidate `u_r` for equality.
|
// To do so, we simply check every candidate `u_r` for equality.
|
||||||
self.scc_values
|
self.scc_values
|
||||||
.universal_regions_outlived_by(r_scc)
|
.universal_regions_outlived_by(r_scc)
|
||||||
.filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
|
.filter(|&u_r| !self.universal_regions().is_local_free_region(u_r))
|
||||||
.find(|&u_r| self.eval_equal(u_r, r_vid))
|
.find(|&u_r| self.eval_equal(u_r, r_vid))
|
||||||
.map(|u_r| ty::Region::new_var(tcx, u_r))
|
.map(|u_r| ty::Region::new_var(tcx, u_r))
|
||||||
// In case we could not find a named region to map to,
|
// In case we could not find a named region to map to,
|
||||||
|
@ -1137,9 +1149,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
// Find the smallest universal region that contains all other
|
// Find the smallest universal region that contains all other
|
||||||
// universal regions within `region`.
|
// universal regions within `region`.
|
||||||
let mut lub = self.universal_regions.fr_fn_body;
|
let mut lub = self.universal_regions().fr_fn_body;
|
||||||
let r_scc = self.constraint_sccs.scc(r);
|
let r_scc = self.constraint_sccs.scc(r);
|
||||||
let static_r = self.universal_regions.fr_static;
|
let static_r = self.universal_regions().fr_static;
|
||||||
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
|
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
|
||||||
let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
|
let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
|
||||||
debug!(?ur, ?lub, ?new_lub);
|
debug!(?ur, ?lub, ?new_lub);
|
||||||
|
@ -1286,12 +1298,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
debug!(
|
debug!(
|
||||||
"sup_region's value = {:?} universal={:?}",
|
"sup_region's value = {:?} universal={:?}",
|
||||||
self.region_value_str(sup_region),
|
self.region_value_str(sup_region),
|
||||||
self.universal_regions.is_universal_region(sup_region),
|
self.universal_regions().is_universal_region(sup_region),
|
||||||
);
|
);
|
||||||
debug!(
|
debug!(
|
||||||
"sub_region's value = {:?} universal={:?}",
|
"sub_region's value = {:?} universal={:?}",
|
||||||
self.region_value_str(sub_region),
|
self.region_value_str(sub_region),
|
||||||
self.universal_regions.is_universal_region(sub_region),
|
self.universal_regions().is_universal_region(sub_region),
|
||||||
);
|
);
|
||||||
|
|
||||||
let sub_region_scc = self.constraint_sccs.scc(sub_region);
|
let sub_region_scc = self.constraint_sccs.scc(sub_region);
|
||||||
|
@ -1306,7 +1318,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
by super `{sup_region_scc:?}`, promoting to static",
|
by super `{sup_region_scc:?}`, promoting to static",
|
||||||
);
|
);
|
||||||
|
|
||||||
return self.eval_outlives(sup_region, self.universal_regions.fr_static);
|
return self.eval_outlives(sup_region, self.universal_regions().fr_static);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both the `sub_region` and `sup_region` consist of the union
|
// Both the `sub_region` and `sup_region` consist of the union
|
||||||
|
@ -1330,7 +1342,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
// Now we have to compare all the points in the sub region and make
|
// Now we have to compare all the points in the sub region and make
|
||||||
// sure they exist in the sup region.
|
// sure they exist in the sup region.
|
||||||
|
|
||||||
if self.universal_regions.is_universal_region(sup_region) {
|
if self.universal_regions().is_universal_region(sup_region) {
|
||||||
// Micro-opt: universal regions contain all points.
|
// Micro-opt: universal regions contain all points.
|
||||||
debug!("super is universal and hence contains all points");
|
debug!("super is universal and hence contains all points");
|
||||||
return true;
|
return true;
|
||||||
|
@ -1495,6 +1507,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
|
fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
|
||||||
self.constraint_sccs().annotation(scc).min_universe()
|
self.constraint_sccs().annotation(scc).min_universe()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks the final value for the free region `fr` to see if it
|
/// Checks the final value for the free region `fr` to see if it
|
||||||
/// grew too large. In particular, examine what `end(X)` points
|
/// grew too large. In particular, examine what `end(X)` points
|
||||||
/// wound up in `fr`'s final value; for each `end(X)` where `X !=
|
/// wound up in `fr`'s final value; for each `end(X)` where `X !=
|
||||||
|
@ -1667,7 +1680,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
placeholder,
|
placeholder,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stop after the first error, it gets too noisy otherwise, and does not provide more information.
|
// Stop after the first error, it gets too noisy otherwise, and does not provide more
|
||||||
|
// information.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
debug!("check_bound_universal_region: all bounds satisfied");
|
debug!("check_bound_universal_region: all bounds satisfied");
|
||||||
|
@ -1732,7 +1746,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2);
|
debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2);
|
||||||
let result = {
|
let result = {
|
||||||
r == fr2 || {
|
r == fr2 || {
|
||||||
fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r)
|
fr2 == self.universal_regions().fr_static && self.cannot_name_placeholder(fr1, r)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug!("provides_universal_region: result = {:?}", result);
|
debug!("provides_universal_region: result = {:?}", result);
|
||||||
|
@ -1833,7 +1847,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
// A constraint like `'r: 'x` can come from our constraint
|
// A constraint like `'r: 'x` can come from our constraint
|
||||||
// graph.
|
// graph.
|
||||||
let fr_static = self.universal_regions.fr_static;
|
let fr_static = self.universal_regions().fr_static;
|
||||||
let outgoing_edges_from_graph =
|
let outgoing_edges_from_graph =
|
||||||
self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static);
|
self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static);
|
||||||
|
|
||||||
|
@ -1948,7 +1962,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> {
|
pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> {
|
||||||
self.universal_regions.as_ref()
|
&self.universal_region_relations.universal_regions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to find the best constraint to blame for the fact that
|
/// Tries to find the best constraint to blame for the fact that
|
||||||
|
@ -2000,8 +2014,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
|
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
|
||||||
// Instead, we use it to produce an improved `ObligationCauseCode`.
|
// Instead, we use it to produce an improved `ObligationCauseCode`.
|
||||||
// FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
|
// FIXME - determine what we should do if we encounter multiple
|
||||||
// constraints. Currently, we just pick the first one.
|
// `ConstraintCategory::Predicate` constraints. Currently, we just pick the first one.
|
||||||
let cause_code = path
|
let cause_code = path
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|constraint| {
|
.find_map(|constraint| {
|
||||||
|
@ -2208,7 +2222,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
/// Access to the region graph, built from the outlives constraints.
|
/// Access to the region graph, built from the outlives constraints.
|
||||||
pub(crate) fn region_graph(&self) -> RegionGraph<'_, 'tcx, graph::Normal> {
|
pub(crate) fn region_graph(&self) -> RegionGraph<'_, 'tcx, graph::Normal> {
|
||||||
self.constraint_graph.region_graph(&self.constraints, self.universal_regions.fr_static)
|
self.constraint_graph.region_graph(&self.constraints, self.universal_regions().fr_static)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given region is considered live at all points: whether it is a
|
/// Returns whether the given region is considered live at all points: whether it is a
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir::OpaqueTyOrigin;
|
|
||||||
use rustc_hir::def::DefKind;
|
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
|
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
|
||||||
use rustc_infer::traits::{Obligation, ObligationCause};
|
|
||||||
use rustc_macros::extension;
|
use rustc_macros::extension;
|
||||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
|
@ -12,7 +9,6 @@ use rustc_middle::ty::{
|
||||||
TypingMode,
|
TypingMode,
|
||||||
};
|
};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
|
||||||
use rustc_trait_selection::traits::ObligationCtxt;
|
use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
@ -78,7 +74,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
debug!(?opaque_type_key, ?concrete_type);
|
debug!(?opaque_type_key, ?concrete_type);
|
||||||
|
|
||||||
let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> =
|
let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> =
|
||||||
vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)];
|
vec![(self.universal_regions().fr_static, infcx.tcx.lifetimes.re_static)];
|
||||||
|
|
||||||
let opaque_type_key =
|
let opaque_type_key =
|
||||||
opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| {
|
opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| {
|
||||||
|
@ -92,12 +88,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
// the same name and simplifies subsequent handling.
|
// the same name and simplifies subsequent handling.
|
||||||
// See [rustc-dev-guide chapter] § "Semantic lifetime equality".
|
// See [rustc-dev-guide chapter] § "Semantic lifetime equality".
|
||||||
NllRegionVariableOrigin::FreeRegion => self
|
NllRegionVariableOrigin::FreeRegion => self
|
||||||
.universal_regions
|
|
||||||
.universal_regions()
|
.universal_regions()
|
||||||
|
.universal_regions_iter()
|
||||||
.filter(|&ur| {
|
.filter(|&ur| {
|
||||||
// See [rustc-dev-guide chapter] § "Closure restrictions".
|
// See [rustc-dev-guide chapter] § "Closure restrictions".
|
||||||
!matches!(
|
!matches!(
|
||||||
self.universal_regions.region_classification(ur),
|
self.universal_regions().region_classification(ur),
|
||||||
Some(RegionClassification::External)
|
Some(RegionClassification::External)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -145,9 +141,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Sometimes two opaque types are the same only after we remap the generic parameters
|
// Sometimes two opaque types are the same only after we remap the generic parameters
|
||||||
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
|
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to
|
||||||
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
|
// `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we
|
||||||
// once we convert the generic parameters to those of the opaque type.
|
// only know that once we convert the generic parameters to those of the opaque type.
|
||||||
if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
|
if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
|
||||||
if prev.ty != ty {
|
if prev.ty != ty {
|
||||||
let guar = ty.error_reported().err().unwrap_or_else(|| {
|
let guar = ty.error_reported().err().unwrap_or_else(|| {
|
||||||
|
@ -303,91 +299,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
return Ty::new_error(self.tcx, e);
|
return Ty::new_error(self.tcx, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// `definition_ty` does not live in of the current inference context,
|
definition_ty
|
||||||
// so lets make sure that we don't accidentally misuse our current `infcx`.
|
|
||||||
match check_opaque_type_well_formed(
|
|
||||||
self.tcx,
|
|
||||||
self.next_trait_solver(),
|
|
||||||
opaque_type_key.def_id,
|
|
||||||
instantiated_ty.span,
|
|
||||||
definition_ty,
|
|
||||||
) {
|
|
||||||
Ok(hidden_ty) => hidden_ty,
|
|
||||||
Err(guar) => Ty::new_error(self.tcx, guar),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This logic duplicates most of `check_opaque_meets_bounds`.
|
|
||||||
/// FIXME(oli-obk): Also do region checks here and then consider removing
|
|
||||||
/// `check_opaque_meets_bounds` entirely.
|
|
||||||
fn check_opaque_type_well_formed<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
next_trait_solver: bool,
|
|
||||||
def_id: LocalDefId,
|
|
||||||
definition_span: Span,
|
|
||||||
definition_ty: Ty<'tcx>,
|
|
||||||
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
|
|
||||||
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
|
|
||||||
// on stable and we'd break that.
|
|
||||||
let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id);
|
|
||||||
let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else {
|
|
||||||
return Ok(definition_ty);
|
|
||||||
};
|
|
||||||
let param_env = tcx.param_env(def_id);
|
|
||||||
|
|
||||||
let mut parent_def_id = def_id;
|
|
||||||
while tcx.def_kind(parent_def_id) == DefKind::OpaqueTy {
|
|
||||||
parent_def_id = tcx.local_parent(parent_def_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(#132279): This should eventually use the already defined hidden types
|
|
||||||
// instead. Alternatively we'll entirely remove this function given we also check
|
|
||||||
// the opaque in `check_opaque_meets_bounds` later.
|
|
||||||
let infcx = tcx
|
|
||||||
.infer_ctxt()
|
|
||||||
.with_next_trait_solver(next_trait_solver)
|
|
||||||
.build(TypingMode::analysis_in_body(tcx, parent_def_id));
|
|
||||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
|
||||||
let identity_args = GenericArgs::identity_for_item(tcx, def_id);
|
|
||||||
|
|
||||||
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
|
||||||
// the bounds that the function supplies.
|
|
||||||
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args);
|
|
||||||
ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
|
|
||||||
.map_err(|err| {
|
|
||||||
infcx
|
|
||||||
.err_ctxt()
|
|
||||||
.report_mismatched_types(
|
|
||||||
&ObligationCause::misc(definition_span, def_id),
|
|
||||||
param_env,
|
|
||||||
opaque_ty,
|
|
||||||
definition_ty,
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
.emit()
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Require the hidden type to be well-formed with only the generics of the opaque type.
|
|
||||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
|
||||||
// hidden type is well formed even without those bounds.
|
|
||||||
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
|
|
||||||
definition_ty.into(),
|
|
||||||
)));
|
|
||||||
ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));
|
|
||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
|
||||||
// version.
|
|
||||||
let errors = ocx.select_all_or_error();
|
|
||||||
|
|
||||||
// This is fishy, but we check it again in `check_opaque_meets_bounds`.
|
|
||||||
// Remove once we can prepopulate with known hidden types.
|
|
||||||
let _ = infcx.take_opaque_types();
|
|
||||||
|
|
||||||
if errors.is_empty() {
|
|
||||||
Ok(definition_ty)
|
|
||||||
} else {
|
|
||||||
Err(infcx.err_ctxt().report_fulfillment_errors(errors))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,8 @@ impl RegionInferenceContext<'_> {
|
||||||
|
|
||||||
let graph = self.constraint_sccs.reverse();
|
let graph = self.constraint_sccs.reverse();
|
||||||
let mut paired_scc_regions = self
|
let mut paired_scc_regions = self
|
||||||
.universal_regions
|
|
||||||
.universal_regions()
|
.universal_regions()
|
||||||
|
.universal_regions_iter()
|
||||||
.map(|region| (self.constraint_sccs.scc(region), region))
|
.map(|region| (self.constraint_sccs.scc(region), region))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
paired_scc_regions.sort();
|
paired_scc_regions.sort();
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::BorrowIndex;
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
/// A single integer representing a `ty::Placeholder`.
|
/// A single integer representing a `ty::Placeholder`.
|
||||||
#[debug_format = "PlaceholderIndex({})"]
|
#[debug_format = "PlaceholderIndex({})"]
|
||||||
pub struct PlaceholderIndex {}
|
pub(crate) struct PlaceholderIndex {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An individual element in a region value -- the value of a
|
/// An individual element in a region value -- the value of a
|
||||||
|
@ -258,10 +258,9 @@ impl PlaceholderIndices {
|
||||||
/// Here, the variable `'0` would contain the free region `'a`,
|
/// Here, the variable `'0` would contain the free region `'a`,
|
||||||
/// because (since it is returned) it must live for at least `'a`. But
|
/// because (since it is returned) it must live for at least `'a`. But
|
||||||
/// it would also contain various points from within the function.
|
/// it would also contain various points from within the function.
|
||||||
#[derive(Clone)]
|
|
||||||
pub(crate) struct RegionValues<N: Idx> {
|
pub(crate) struct RegionValues<N: Idx> {
|
||||||
elements: Rc<DenseLocationMap>,
|
elements: Rc<DenseLocationMap>,
|
||||||
placeholder_indices: Rc<PlaceholderIndices>,
|
placeholder_indices: PlaceholderIndices,
|
||||||
points: SparseIntervalMatrix<N, PointIndex>,
|
points: SparseIntervalMatrix<N, PointIndex>,
|
||||||
free_regions: SparseBitMatrix<N, RegionVid>,
|
free_regions: SparseBitMatrix<N, RegionVid>,
|
||||||
|
|
||||||
|
@ -277,7 +276,7 @@ impl<N: Idx> RegionValues<N> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
elements: Rc<DenseLocationMap>,
|
elements: Rc<DenseLocationMap>,
|
||||||
num_universal_regions: usize,
|
num_universal_regions: usize,
|
||||||
placeholder_indices: Rc<PlaceholderIndices>,
|
placeholder_indices: PlaceholderIndices,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let num_points = elements.num_points();
|
let num_points = elements.num_points();
|
||||||
let num_placeholders = placeholder_indices.len();
|
let num_placeholders = placeholder_indices.len();
|
||||||
|
|
|
@ -7,6 +7,7 @@ use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
|
use rustc_trait_selection::solve::NoSolution;
|
||||||
use rustc_trait_selection::traits::ObligationCause;
|
use rustc_trait_selection::traits::ObligationCause;
|
||||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
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::query::type_op::{self, TypeOpOutput};
|
||||||
|
@ -62,7 +63,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
let universe_info = error_info.to_universe_info(old_universe);
|
let universe_info = error_info.to_universe_info(old_universe);
|
||||||
for u in (old_universe + 1)..=universe {
|
for u in (old_universe + 1)..=universe {
|
||||||
self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
|
self.constraints.universe_causes.insert(u, universe_info.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +133,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
category: ConstraintCategory<'tcx>,
|
category: ConstraintCategory<'tcx>,
|
||||||
) {
|
) {
|
||||||
let param_env = self.param_env;
|
let param_env = self.infcx.param_env;
|
||||||
let predicate = predicate.upcast(self.tcx());
|
let predicate = predicate.upcast(self.tcx());
|
||||||
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
||||||
locations,
|
locations,
|
||||||
|
@ -158,7 +159,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
where
|
where
|
||||||
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
||||||
{
|
{
|
||||||
let param_env = self.param_env;
|
let param_env = self.infcx.param_env;
|
||||||
let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
||||||
location.to_locations(),
|
location.to_locations(),
|
||||||
category,
|
category,
|
||||||
|
@ -176,7 +177,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
if self.infcx.next_trait_solver() {
|
if self.infcx.next_trait_solver() {
|
||||||
let body = self.body;
|
let body = self.body;
|
||||||
let param_env = self.param_env;
|
let param_env = self.infcx.param_env;
|
||||||
|
// FIXME: Make this into a real type op?
|
||||||
self.fully_perform_op(
|
self.fully_perform_op(
|
||||||
location.to_locations(),
|
location.to_locations(),
|
||||||
ConstraintCategory::Boring,
|
ConstraintCategory::Boring,
|
||||||
|
@ -213,6 +215,40 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
pub(super) fn structurally_resolve(
|
||||||
|
&mut self,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
location: impl NormalizeLocation,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
if self.infcx.next_trait_solver() {
|
||||||
|
let body = self.body;
|
||||||
|
let param_env = self.infcx.param_env;
|
||||||
|
// FIXME: Make this into a real type op?
|
||||||
|
self.fully_perform_op(
|
||||||
|
location.to_locations(),
|
||||||
|
ConstraintCategory::Boring,
|
||||||
|
CustomTypeOp::new(
|
||||||
|
|ocx| {
|
||||||
|
ocx.structurally_normalize(
|
||||||
|
&ObligationCause::misc(
|
||||||
|
location.to_locations().span(body),
|
||||||
|
body.source.def_id().expect_local(),
|
||||||
|
),
|
||||||
|
param_env,
|
||||||
|
ty,
|
||||||
|
)
|
||||||
|
.map_err(|_| NoSolution)
|
||||||
|
},
|
||||||
|
"normalizing struct tail",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar))
|
||||||
|
} else {
|
||||||
|
self.normalize(ty, location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
pub(super) fn ascribe_user_type(
|
pub(super) fn ascribe_user_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -223,7 +259,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
||||||
Locations::All(span),
|
Locations::All(span),
|
||||||
ConstraintCategory::Boring,
|
ConstraintCategory::Boring,
|
||||||
self.param_env.and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }),
|
self.infcx
|
||||||
|
.param_env
|
||||||
|
.and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +288,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let mir_ty = self.normalize(mir_ty, Locations::All(span));
|
let mir_ty = self.normalize(mir_ty, Locations::All(span));
|
||||||
|
|
||||||
let cause = ObligationCause::dummy_with_span(span);
|
let cause = ObligationCause::dummy_with_span(span);
|
||||||
let param_env = self.param_env;
|
let param_env = self.infcx.param_env;
|
||||||
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
||||||
Locations::All(span),
|
Locations::All(span),
|
||||||
ConstraintCategory::Boring,
|
ConstraintCategory::Boring,
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
span: Span,
|
span: Span,
|
||||||
category: ConstraintCategory<'tcx>,
|
category: ConstraintCategory<'tcx>,
|
||||||
|
@ -52,7 +52,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
span: Span,
|
span: Span,
|
||||||
category: ConstraintCategory<'tcx>,
|
category: ConstraintCategory<'tcx>,
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use rustc_data_structures::frozen::Frozen;
|
use rustc_data_structures::frozen::Frozen;
|
||||||
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
|
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
|
@ -23,7 +21,7 @@ use crate::universal_regions::UniversalRegions;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct UniversalRegionRelations<'tcx> {
|
pub(crate) struct UniversalRegionRelations<'tcx> {
|
||||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
pub(crate) universal_regions: UniversalRegions<'tcx>,
|
||||||
|
|
||||||
/// Stores the outlives relations that are known to hold from the
|
/// Stores the outlives relations that are known to hold from the
|
||||||
/// implied bounds, in-scope where-clauses, and that sort of
|
/// implied bounds, in-scope where-clauses, and that sort of
|
||||||
|
@ -46,7 +44,7 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
|
||||||
pub(crate) struct CreateResult<'tcx> {
|
pub(crate) struct CreateResult<'tcx> {
|
||||||
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||||
pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
|
pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||||
pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
pub(crate) known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||||
pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
|
pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +52,7 @@ pub(crate) fn create<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
universal_regions: UniversalRegions<'tcx>,
|
||||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||||
) -> CreateResult<'tcx> {
|
) -> CreateResult<'tcx> {
|
||||||
UniversalRegionRelationsBuilder {
|
UniversalRegionRelationsBuilder {
|
||||||
|
@ -184,7 +182,7 @@ impl UniversalRegionRelations<'_> {
|
||||||
struct UniversalRegionRelationsBuilder<'a, 'tcx> {
|
struct UniversalRegionRelationsBuilder<'a, 'tcx> {
|
||||||
infcx: &'a InferCtxt<'tcx>,
|
infcx: &'a InferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
universal_regions: UniversalRegions<'tcx>,
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||||
|
|
||||||
|
@ -220,7 +218,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
// region `'r`, all of which are provided by our caller
|
// region `'r`, all of which are provided by our caller
|
||||||
let fr_static = self.universal_regions.fr_static;
|
let fr_static = self.universal_regions.fr_static;
|
||||||
let fr_fn_body = self.universal_regions.fr_fn_body;
|
let fr_fn_body = self.universal_regions.fr_fn_body;
|
||||||
for fr in self.universal_regions.universal_regions() {
|
for fr in self.universal_regions.universal_regions_iter() {
|
||||||
debug!("build: relating free region {:?} to itself and to 'static", fr);
|
debug!("build: relating free region {:?} to itself and to 'static", fr);
|
||||||
self.relate_universal_regions(fr, fr);
|
self.relate_universal_regions(fr, fr);
|
||||||
self.relate_universal_regions(fr_static, fr);
|
self.relate_universal_regions(fr_static, fr);
|
||||||
|
@ -236,7 +234,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
// In the new solver, normalize the type-outlives obligation assumptions.
|
// In the new solver, normalize the type-outlives obligation assumptions.
|
||||||
if self.infcx.next_trait_solver() {
|
if self.infcx.next_trait_solver() {
|
||||||
match deeply_normalize(
|
match deeply_normalize(
|
||||||
self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env),
|
self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), param_env),
|
||||||
outlives,
|
outlives,
|
||||||
) {
|
) {
|
||||||
Ok(normalized_outlives) => {
|
Ok(normalized_outlives) => {
|
||||||
|
@ -250,8 +248,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
|
|
||||||
known_type_outlives_obligations.push(outlives);
|
known_type_outlives_obligations.push(outlives);
|
||||||
}
|
}
|
||||||
let known_type_outlives_obligations =
|
|
||||||
self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations);
|
|
||||||
|
|
||||||
let unnormalized_input_output_tys = self
|
let unnormalized_input_output_tys = self
|
||||||
.universal_regions
|
.universal_regions
|
||||||
|
@ -278,8 +274,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
if let Some(c) = constraints_unnorm {
|
if let Some(c) = constraints_unnorm {
|
||||||
constraints.push(c)
|
constraints.push(c)
|
||||||
}
|
}
|
||||||
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
|
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
|
||||||
.param_env
|
param_env
|
||||||
.and(type_op::normalize::Normalize { value: ty })
|
.and(type_op::normalize::Normalize { value: ty })
|
||||||
.fully_perform(self.infcx, span)
|
.fully_perform(self.infcx, span)
|
||||||
.unwrap_or_else(|guar| TypeOpOutput {
|
.unwrap_or_else(|guar| TypeOpOutput {
|
||||||
|
@ -316,8 +312,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
// Add implied bounds from impl header.
|
// Add implied bounds from impl header.
|
||||||
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
|
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
|
||||||
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
|
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
|
||||||
let result: Result<_, ErrorGuaranteed> = self
|
let result: Result<_, ErrorGuaranteed> = param_env
|
||||||
.param_env
|
|
||||||
.and(type_op::normalize::Normalize { value: ty })
|
.and(type_op::normalize::Normalize { value: ty })
|
||||||
.fully_perform(self.infcx, span);
|
.fully_perform(self.infcx, span);
|
||||||
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
|
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
|
||||||
|
@ -340,7 +335,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
&self.region_bound_pairs,
|
&self.region_bound_pairs,
|
||||||
self.implicit_region_bound,
|
self.implicit_region_bound,
|
||||||
param_env,
|
param_env,
|
||||||
known_type_outlives_obligations,
|
&known_type_outlives_obligations,
|
||||||
Locations::All(span),
|
Locations::All(span),
|
||||||
span,
|
span,
|
||||||
ConstraintCategory::Internal,
|
ConstraintCategory::Internal,
|
||||||
|
|
|
@ -19,7 +19,7 @@ use tracing::{debug, instrument};
|
||||||
|
|
||||||
use super::{Locations, TypeChecker};
|
use super::{Locations, TypeChecker};
|
||||||
use crate::renumber::RegionCtxt;
|
use crate::renumber::RegionCtxt;
|
||||||
use crate::universal_regions::{DefiningTy, UniversalRegions};
|
use crate::universal_regions::DefiningTy;
|
||||||
|
|
||||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
/// Check explicit closure signature annotation,
|
/// Check explicit closure signature annotation,
|
||||||
|
@ -48,9 +48,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// FIXME(async_closures): It's kind of wacky that we must apply this
|
// FIXME(async_closures): It's kind of wacky that we must apply this
|
||||||
// transformation here, since we do the same thing in HIR typeck.
|
// transformation here, since we do the same thing in HIR typeck.
|
||||||
// Maybe we could just fix up the canonicalized signature during HIR typeck?
|
// Maybe we could just fix up the canonicalized signature during HIR typeck?
|
||||||
if let DefiningTy::CoroutineClosure(_, args) =
|
if let DefiningTy::CoroutineClosure(_, args) = self.universal_regions.defining_ty {
|
||||||
self.borrowck_context.universal_regions.defining_ty
|
|
||||||
{
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)),
|
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)),
|
||||||
Some(hir::CoroutineKind::Desugared(
|
Some(hir::CoroutineKind::Desugared(
|
||||||
|
@ -59,8 +57,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
)),
|
)),
|
||||||
"this needs to be modified if we're lowering non-async closures"
|
"this needs to be modified if we're lowering non-async closures"
|
||||||
);
|
);
|
||||||
// Make sure to use the args from `DefiningTy` so the right NLL region vids are prepopulated
|
// Make sure to use the args from `DefiningTy` so the right NLL region vids are
|
||||||
// into the type.
|
// prepopulated into the type.
|
||||||
let args = args.as_coroutine_closure();
|
let args = args.as_coroutine_closure();
|
||||||
let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
|
let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
|
||||||
self.tcx(),
|
self.tcx(),
|
||||||
|
@ -126,11 +124,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, body, universal_regions), level = "debug")]
|
#[instrument(skip(self, body), level = "debug")]
|
||||||
pub(super) fn equate_inputs_and_outputs(
|
pub(super) fn equate_inputs_and_outputs(
|
||||||
&mut self,
|
&mut self,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
universal_regions: &UniversalRegions<'tcx>,
|
|
||||||
normalized_inputs_and_output: &[Ty<'tcx>],
|
normalized_inputs_and_output: &[Ty<'tcx>],
|
||||||
) {
|
) {
|
||||||
let (&normalized_output_ty, normalized_input_tys) =
|
let (&normalized_output_ty, normalized_input_tys) =
|
||||||
|
@ -163,7 +160,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
if let Some(mir_yield_ty) = body.yield_ty() {
|
if let Some(mir_yield_ty) = body.yield_ty() {
|
||||||
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
|
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
|
||||||
self.equate_normalized_input_or_output(
|
self.equate_normalized_input_or_output(
|
||||||
universal_regions.yield_ty.unwrap(),
|
self.universal_regions.yield_ty.unwrap(),
|
||||||
mir_yield_ty,
|
mir_yield_ty,
|
||||||
yield_span,
|
yield_span,
|
||||||
);
|
);
|
||||||
|
@ -172,7 +169,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
if let Some(mir_resume_ty) = body.resume_ty() {
|
if let Some(mir_resume_ty) = body.resume_ty() {
|
||||||
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
|
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
|
||||||
self.equate_normalized_input_or_output(
|
self.equate_normalized_input_or_output(
|
||||||
universal_regions.resume_ty.unwrap(),
|
self.universal_regions.resume_ty.unwrap(),
|
||||||
mir_resume_ty,
|
mir_resume_ty,
|
||||||
yield_span,
|
yield_span,
|
||||||
);
|
);
|
||||||
|
@ -195,8 +192,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// doing so ends up causing some other trouble.
|
// doing so ends up causing some other trouble.
|
||||||
let b = self.normalize(b, Locations::All(span));
|
let b = self.normalize(b, Locations::All(span));
|
||||||
|
|
||||||
// Note: if we have to introduce new placeholders during normalization above, then we won't have
|
// Note: if we have to introduce new placeholders during normalization above, then we
|
||||||
// added those universes to the universe info, which we would want in `relate_tys`.
|
// won't have added those universes to the universe info, which we would want in
|
||||||
|
// `relate_tys`.
|
||||||
if let Err(terr) =
|
if let Err(terr) =
|
||||||
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
|
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
|
||||||
{
|
{
|
||||||
|
|
|
@ -137,56 +137,22 @@ struct LocalUseMapBuild<'me> {
|
||||||
locals_with_use_data: IndexVec<Local, bool>,
|
locals_with_use_data: IndexVec<Local, bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalUseMapBuild<'_> {
|
|
||||||
fn insert_def(&mut self, local: Local, location: Location) {
|
|
||||||
Self::insert(
|
|
||||||
self.elements,
|
|
||||||
&mut self.local_use_map.first_def_at[local],
|
|
||||||
&mut self.local_use_map.appearances,
|
|
||||||
location,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_use(&mut self, local: Local, location: Location) {
|
|
||||||
Self::insert(
|
|
||||||
self.elements,
|
|
||||||
&mut self.local_use_map.first_use_at[local],
|
|
||||||
&mut self.local_use_map.appearances,
|
|
||||||
location,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_drop(&mut self, local: Local, location: Location) {
|
|
||||||
Self::insert(
|
|
||||||
self.elements,
|
|
||||||
&mut self.local_use_map.first_drop_at[local],
|
|
||||||
&mut self.local_use_map.appearances,
|
|
||||||
location,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(
|
|
||||||
elements: &DenseLocationMap,
|
|
||||||
first_appearance: &mut Option<AppearanceIndex>,
|
|
||||||
appearances: &mut Appearances,
|
|
||||||
location: Location,
|
|
||||||
) {
|
|
||||||
let point_index = elements.point_from_location(location);
|
|
||||||
let appearance_index =
|
|
||||||
appearances.push(Appearance { point_index, next: *first_appearance });
|
|
||||||
*first_appearance = Some(appearance_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Visitor<'_> for LocalUseMapBuild<'_> {
|
impl Visitor<'_> for LocalUseMapBuild<'_> {
|
||||||
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
|
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
|
||||||
if self.locals_with_use_data[local] {
|
if self.locals_with_use_data[local]
|
||||||
match def_use::categorize(context) {
|
&& let Some(def_use) = def_use::categorize(context)
|
||||||
Some(DefUse::Def) => self.insert_def(local, location),
|
{
|
||||||
Some(DefUse::Use) => self.insert_use(local, location),
|
let first_appearance = match def_use {
|
||||||
Some(DefUse::Drop) => self.insert_drop(local, location),
|
DefUse::Def => &mut self.local_use_map.first_def_at[local],
|
||||||
_ => (),
|
DefUse::Use => &mut self.local_use_map.first_use_at[local],
|
||||||
}
|
DefUse::Drop => &mut self.local_use_map.first_drop_at[local],
|
||||||
|
};
|
||||||
|
let point_index = self.elements.point_from_location(location);
|
||||||
|
let appearance_index = self
|
||||||
|
.local_use_map
|
||||||
|
.appearances
|
||||||
|
.push(Appearance { point_index, next: *first_appearance });
|
||||||
|
*first_appearance = Some(appearance_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,15 +32,15 @@ pub(super) fn generate<'a, 'tcx>(
|
||||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
elements: &DenseLocationMap,
|
elements: &DenseLocationMap,
|
||||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!("liveness::generate");
|
debug!("liveness::generate");
|
||||||
|
|
||||||
let free_regions = regions_that_outlive_free_regions(
|
let free_regions = regions_that_outlive_free_regions(
|
||||||
typeck.infcx.num_region_vars(),
|
typeck.infcx.num_region_vars(),
|
||||||
typeck.borrowck_context.universal_regions,
|
&typeck.universal_regions,
|
||||||
&typeck.borrowck_context.constraints.outlives_constraints,
|
&typeck.constraints.outlives_constraints,
|
||||||
);
|
);
|
||||||
let (relevant_live_locals, boring_locals) =
|
let (relevant_live_locals, boring_locals) =
|
||||||
compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
|
compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
|
||||||
|
@ -59,11 +59,7 @@ pub(super) fn generate<'a, 'tcx>(
|
||||||
|
|
||||||
// Mark regions that should be live where they appear within rvalues or within a call: like
|
// Mark regions that should be live where they appear within rvalues or within a call: like
|
||||||
// args, regions, and types.
|
// args, regions, and types.
|
||||||
record_regular_live_regions(
|
record_regular_live_regions(typeck.tcx(), &mut typeck.constraints.liveness_constraints, body);
|
||||||
typeck.tcx(),
|
|
||||||
&mut typeck.borrowck_context.constraints.liveness_constraints,
|
|
||||||
body,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The purpose of `compute_relevant_live_locals` is to define the subset of `Local`
|
// The purpose of `compute_relevant_live_locals` is to define the subset of `Local`
|
||||||
|
@ -111,7 +107,7 @@ fn regions_that_outlive_free_regions<'tcx>(
|
||||||
let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static);
|
let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static);
|
||||||
|
|
||||||
// Stack for the depth-first search. Start out with all the free regions.
|
// Stack for the depth-first search. Start out with all the free regions.
|
||||||
let mut stack: Vec<_> = universal_regions.universal_regions().collect();
|
let mut stack: Vec<_> = universal_regions.universal_regions_iter().collect();
|
||||||
|
|
||||||
// Set of all free regions, plus anything that outlives them. Initially
|
// Set of all free regions, plus anything that outlives them. Initially
|
||||||
// just contains the free regions.
|
// just contains the free regions.
|
||||||
|
|
|
@ -88,9 +88,9 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
) {
|
) {
|
||||||
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
|
if let Some(facts) = typeck.all_facts.as_mut() {
|
||||||
debug!("populate_access_facts()");
|
debug!("populate_access_facts()");
|
||||||
let location_table = typeck.borrowck_context.location_table;
|
let location_table = typeck.location_table;
|
||||||
|
|
||||||
let mut extractor = UseFactsExtractor {
|
let mut extractor = UseFactsExtractor {
|
||||||
var_defined_at: &mut facts.var_defined_at,
|
var_defined_at: &mut facts.var_defined_at,
|
||||||
|
@ -108,7 +108,7 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
|
||||||
local, local_decl.ty
|
local, local_decl.ty
|
||||||
);
|
);
|
||||||
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
||||||
let universal_regions = &typeck.borrowck_context.universal_regions;
|
let universal_regions = &typeck.universal_regions;
|
||||||
typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
|
typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
|
||||||
let region_vid = universal_regions.to_region_vid(region);
|
let region_vid = universal_regions.to_region_vid(region);
|
||||||
facts.use_of_var_derefs_origin.push((local, region_vid.into()));
|
facts.use_of_var_derefs_origin.push((local, region_vid.into()));
|
||||||
|
@ -125,9 +125,9 @@ pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
|
||||||
kind: &GenericArg<'tcx>,
|
kind: &GenericArg<'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind);
|
debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind);
|
||||||
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
|
if let Some(facts) = typeck.all_facts.as_mut() {
|
||||||
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
||||||
let universal_regions = &typeck.borrowck_context.universal_regions;
|
let universal_regions = &typeck.universal_regions;
|
||||||
typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
|
typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
|
||||||
let region_vid = universal_regions.to_region_vid(drop_live_region);
|
let region_vid = universal_regions.to_region_vid(drop_live_region);
|
||||||
facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
|
facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub(super) fn trace<'a, 'tcx>(
|
||||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
elements: &DenseLocationMap,
|
elements: &DenseLocationMap,
|
||||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
relevant_live_locals: Vec<Local>,
|
relevant_live_locals: Vec<Local>,
|
||||||
boring_locals: Vec<Local>,
|
boring_locals: Vec<Local>,
|
||||||
|
@ -47,13 +47,12 @@ pub(super) fn trace<'a, 'tcx>(
|
||||||
|
|
||||||
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
|
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
|
||||||
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
|
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||||
let borrowck_context = &mut typeck.borrowck_context;
|
let borrow_set = &typeck.borrow_set;
|
||||||
let borrow_set = &borrowck_context.borrow_set;
|
|
||||||
let mut live_loans = LiveLoans::new(borrow_set.len());
|
let mut live_loans = LiveLoans::new(borrow_set.len());
|
||||||
let outlives_constraints = &borrowck_context.constraints.outlives_constraints;
|
let outlives_constraints = &typeck.constraints.outlives_constraints;
|
||||||
let graph = outlives_constraints.graph(typeck.infcx.num_region_vars());
|
let graph = outlives_constraints.graph(typeck.infcx.num_region_vars());
|
||||||
let region_graph =
|
let region_graph =
|
||||||
graph.region_graph(outlives_constraints, borrowck_context.universal_regions.fr_static);
|
graph.region_graph(outlives_constraints, typeck.universal_regions.fr_static);
|
||||||
|
|
||||||
// Traverse each issuing region's constraints, and record the loan as flowing into the
|
// Traverse each issuing region's constraints, and record the loan as flowing into the
|
||||||
// outlived region.
|
// outlived region.
|
||||||
|
@ -73,7 +72,7 @@ pub(super) fn trace<'a, 'tcx>(
|
||||||
|
|
||||||
// Store the inflowing loans in the liveness constraints: they will be used to compute live
|
// Store the inflowing loans in the liveness constraints: they will be used to compute live
|
||||||
// loans when liveness data is recorded there.
|
// loans when liveness data is recorded there.
|
||||||
borrowck_context.constraints.liveness_constraints.loans = Some(live_loans);
|
typeck.constraints.liveness_constraints.loans = Some(live_loans);
|
||||||
};
|
};
|
||||||
|
|
||||||
let cx = LivenessContext {
|
let cx = LivenessContext {
|
||||||
|
@ -114,7 +113,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
|
||||||
|
|
||||||
/// Results of dataflow tracking which variables (and paths) have been
|
/// Results of dataflow tracking which variables (and paths) have been
|
||||||
/// initialized.
|
/// initialized.
|
||||||
flow_inits: &'a mut ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>,
|
flow_inits: ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>,
|
||||||
|
|
||||||
/// Index indicating where each variable is assigned, used, or
|
/// Index indicating where each variable is assigned, used, or
|
||||||
/// dropped.
|
/// dropped.
|
||||||
|
@ -222,7 +221,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
// It may be necessary to just pick out the parts of
|
// It may be necessary to just pick out the parts of
|
||||||
// `add_drop_live_facts_for()` that make sense.
|
// `add_drop_live_facts_for()` that make sense.
|
||||||
let facts_to_add: Vec<_> = {
|
let facts_to_add: Vec<_> = {
|
||||||
let drop_used = &self.cx.typeck.borrowck_context.all_facts.as_ref()?.var_dropped_at;
|
let drop_used = &self.cx.typeck.all_facts.as_ref()?.var_dropped_at;
|
||||||
|
|
||||||
let relevant_live_locals: FxIndexSet<_> =
|
let relevant_live_locals: FxIndexSet<_> =
|
||||||
relevant_live_locals.iter().copied().collect();
|
relevant_live_locals.iter().copied().collect();
|
||||||
|
@ -235,12 +234,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let location = match self
|
let location = match self.cx.typeck.location_table.to_location(*location_index)
|
||||||
.cx
|
|
||||||
.typeck
|
|
||||||
.borrowck_context
|
|
||||||
.location_table
|
|
||||||
.to_location(*location_index)
|
|
||||||
{
|
{
|
||||||
RichLocation::Start(l) => l,
|
RichLocation::Start(l) => l,
|
||||||
RichLocation::Mid(l) => l,
|
RichLocation::Mid(l) => l,
|
||||||
|
@ -251,7 +245,8 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: these locations seem to have a special meaning (e.g. everywhere, at the end, ...), but I don't know which one. Please help me rename it to something descriptive!
|
// FIXME: these locations seem to have a special meaning (e.g. everywhere, at the end,
|
||||||
|
// ...), but I don't know which one. Please help me rename it to something descriptive!
|
||||||
// Also, if this IntervalSet is used in many places, it maybe should have a newtype'd
|
// Also, if this IntervalSet is used in many places, it maybe should have a newtype'd
|
||||||
// name with a description of what it means for future mortals passing by.
|
// name with a description of what it means for future mortals passing by.
|
||||||
let locations = IntervalSet::new(self.cx.elements.num_points());
|
let locations = IntervalSet::new(self.cx.elements.num_points());
|
||||||
|
@ -613,15 +608,11 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
||||||
|
|
||||||
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
|
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
|
||||||
tcx: typeck.tcx(),
|
tcx: typeck.tcx(),
|
||||||
param_env: typeck.param_env,
|
param_env: typeck.infcx.param_env,
|
||||||
op: |r| {
|
op: |r| {
|
||||||
let live_region_vid = typeck.borrowck_context.universal_regions.to_region_vid(r);
|
let live_region_vid = typeck.universal_regions.to_region_vid(r);
|
||||||
|
|
||||||
typeck
|
typeck.constraints.liveness_constraints.add_points(live_region_vid, live_at);
|
||||||
.borrowck_context
|
|
||||||
.constraints
|
|
||||||
.liveness_constraints
|
|
||||||
.add_points(live_region_vid, live_at);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -630,6 +621,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
||||||
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
|
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
|
||||||
|
|
||||||
match typeck
|
match typeck
|
||||||
|
.infcx
|
||||||
.param_env
|
.param_env
|
||||||
.and(DropckOutlives { dropped_ty })
|
.and(DropckOutlives { dropped_ty })
|
||||||
.fully_perform(typeck.infcx, DUMMY_SP)
|
.fully_perform(typeck.infcx, DUMMY_SP)
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::rc::Rc;
|
||||||
use std::{fmt, iter, mem};
|
use std::{fmt, iter, mem};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
||||||
use rustc_data_structures::frozen::Frozen;
|
use rustc_data_structures::frozen::Frozen;
|
||||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
|
@ -40,7 +41,6 @@ use rustc_span::def_id::CRATE_DEF_ID;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{DUMMY_SP, Span};
|
use rustc_span::{DUMMY_SP, Span};
|
||||||
use rustc_target::abi::{FIRST_VARIANT, FieldIdx};
|
|
||||||
use rustc_trait_selection::traits::query::type_op::custom::{
|
use rustc_trait_selection::traits::query::type_op::custom::{
|
||||||
CustomTypeOp, scrape_region_constraints,
|
CustomTypeOp, scrape_region_constraints,
|
||||||
};
|
};
|
||||||
|
@ -118,17 +118,15 @@ mod relate_tys;
|
||||||
/// - `elements` -- MIR region map
|
/// - `elements` -- MIR region map
|
||||||
pub(crate) fn type_check<'a, 'tcx>(
|
pub(crate) fn type_check<'a, 'tcx>(
|
||||||
infcx: &BorrowckInferCtxt<'tcx>,
|
infcx: &BorrowckInferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
universal_regions: UniversalRegions<'tcx>,
|
||||||
location_table: &LocationTable,
|
location_table: &LocationTable,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
all_facts: &mut Option<AllFacts>,
|
all_facts: &mut Option<AllFacts>,
|
||||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
elements: Rc<DenseLocationMap>,
|
elements: Rc<DenseLocationMap>,
|
||||||
upvars: &[&ty::CapturedPlace<'tcx>],
|
|
||||||
) -> MirTypeckResults<'tcx> {
|
) -> MirTypeckResults<'tcx> {
|
||||||
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
||||||
let mut constraints = MirTypeckRegionConstraints {
|
let mut constraints = MirTypeckRegionConstraints {
|
||||||
|
@ -148,40 +146,37 @@ pub(crate) fn type_check<'a, 'tcx>(
|
||||||
known_type_outlives_obligations,
|
known_type_outlives_obligations,
|
||||||
} = free_region_relations::create(
|
} = free_region_relations::create(
|
||||||
infcx,
|
infcx,
|
||||||
param_env,
|
infcx.param_env,
|
||||||
implicit_region_bound,
|
implicit_region_bound,
|
||||||
Rc::clone(&universal_regions),
|
universal_regions,
|
||||||
&mut constraints,
|
&mut constraints,
|
||||||
);
|
);
|
||||||
|
|
||||||
debug!(?normalized_inputs_and_output);
|
debug!(?normalized_inputs_and_output);
|
||||||
|
|
||||||
let mut borrowck_context = BorrowCheckContext {
|
let mut checker = TypeChecker {
|
||||||
universal_regions: &universal_regions,
|
|
||||||
location_table,
|
|
||||||
borrow_set,
|
|
||||||
all_facts,
|
|
||||||
constraints: &mut constraints,
|
|
||||||
upvars,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut checker = TypeChecker::new(
|
|
||||||
infcx,
|
infcx,
|
||||||
|
last_span: body.span,
|
||||||
body,
|
body,
|
||||||
param_env,
|
user_type_annotations: &body.user_type_annotations,
|
||||||
®ion_bound_pairs,
|
region_bound_pairs,
|
||||||
known_type_outlives_obligations,
|
known_type_outlives_obligations,
|
||||||
implicit_region_bound,
|
implicit_region_bound,
|
||||||
&mut borrowck_context,
|
reported_errors: Default::default(),
|
||||||
);
|
universal_regions: &universal_region_relations.universal_regions,
|
||||||
|
location_table,
|
||||||
|
all_facts,
|
||||||
|
borrow_set,
|
||||||
|
constraints: &mut constraints,
|
||||||
|
};
|
||||||
|
|
||||||
checker.check_user_type_annotations();
|
checker.check_user_type_annotations();
|
||||||
|
|
||||||
let mut verifier = TypeVerifier::new(&mut checker, promoted);
|
let mut verifier = TypeVerifier { cx: &mut checker, promoted, last_span: body.span };
|
||||||
verifier.visit_body(body);
|
verifier.visit_body(body);
|
||||||
|
|
||||||
checker.typeck_mir(body);
|
checker.typeck_mir(body);
|
||||||
checker.equate_inputs_and_outputs(body, &universal_regions, &normalized_inputs_and_output);
|
checker.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
|
||||||
checker.check_signature_annotation(body);
|
checker.check_signature_annotation(body);
|
||||||
|
|
||||||
liveness::generate(&mut checker, body, &elements, flow_inits, move_data);
|
liveness::generate(&mut checker, body, &elements, flow_inits, move_data);
|
||||||
|
@ -221,13 +216,12 @@ pub(crate) fn type_check<'a, 'tcx>(
|
||||||
infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| {
|
infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| {
|
||||||
match region.kind() {
|
match region.kind() {
|
||||||
ty::ReVar(_) => region,
|
ty::ReVar(_) => region,
|
||||||
ty::RePlaceholder(placeholder) => checker
|
ty::RePlaceholder(placeholder) => {
|
||||||
.borrowck_context
|
checker.constraints.placeholder_region(infcx, placeholder)
|
||||||
.constraints
|
}
|
||||||
.placeholder_region(infcx, placeholder),
|
|
||||||
_ => ty::Region::new_var(
|
_ => ty::Region::new_var(
|
||||||
infcx.tcx,
|
infcx.tcx,
|
||||||
checker.borrowck_context.universal_regions.to_region_vid(region),
|
checker.universal_regions.to_region_vid(region),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -240,11 +234,11 @@ pub(crate) fn type_check<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
|
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
|
||||||
let cx = &mut typeck.borrowck_context;
|
if let Some(facts) = typeck.all_facts {
|
||||||
if let Some(facts) = cx.all_facts {
|
|
||||||
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
||||||
let location_table = cx.location_table;
|
let location_table = typeck.location_table;
|
||||||
facts.subset_base.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map(
|
facts.subset_base.extend(
|
||||||
|
typeck.constraints.outlives_constraints.outlives().iter().flat_map(
|
||||||
|constraint: &OutlivesConstraint<'_>| {
|
|constraint: &OutlivesConstraint<'_>| {
|
||||||
if let Some(from_location) = constraint.locations.from_location() {
|
if let Some(from_location) = constraint.locations.from_location() {
|
||||||
Either::Left(iter::once((
|
Either::Left(iter::once((
|
||||||
|
@ -258,7 +252,8 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,13 +298,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||||
let ty = self.sanitize_type(constant, constant.const_.ty());
|
let ty = self.sanitize_type(constant, constant.const_.ty());
|
||||||
|
|
||||||
self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
|
self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
|
||||||
let live_region_vid =
|
let live_region_vid = self.cx.universal_regions.to_region_vid(live_region);
|
||||||
self.cx.borrowck_context.universal_regions.to_region_vid(live_region);
|
self.cx.constraints.liveness_constraints.add_location(live_region_vid, location);
|
||||||
self.cx
|
|
||||||
.borrowck_context
|
|
||||||
.constraints
|
|
||||||
.liveness_constraints
|
|
||||||
.add_location(live_region_vid, location);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// HACK(compiler-errors): Constants that are gathered into Body.required_consts
|
// HACK(compiler-errors): Constants that are gathered into Body.required_consts
|
||||||
|
@ -473,13 +463,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
fn new(
|
|
||||||
cx: &'a mut TypeChecker<'b, 'tcx>,
|
|
||||||
promoted: &'b IndexSlice<Promoted, Body<'tcx>>,
|
|
||||||
) -> Self {
|
|
||||||
TypeVerifier { promoted, last_span: cx.body.span, cx }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn body(&self) -> &Body<'tcx> {
|
fn body(&self) -> &Body<'tcx> {
|
||||||
self.cx.body
|
self.cx.body
|
||||||
}
|
}
|
||||||
|
@ -561,15 +544,9 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
// Don't try to add borrow_region facts for the promoted MIR
|
// Don't try to add borrow_region facts for the promoted MIR
|
||||||
|
|
||||||
let mut swap_constraints = |this: &mut Self| {
|
let mut swap_constraints = |this: &mut Self| {
|
||||||
mem::swap(this.cx.borrowck_context.all_facts, all_facts);
|
mem::swap(this.cx.all_facts, all_facts);
|
||||||
mem::swap(
|
mem::swap(&mut this.cx.constraints.outlives_constraints, &mut constraints);
|
||||||
&mut this.cx.borrowck_context.constraints.outlives_constraints,
|
mem::swap(&mut this.cx.constraints.liveness_constraints, &mut liveness_constraints);
|
||||||
&mut constraints,
|
|
||||||
);
|
|
||||||
mem::swap(
|
|
||||||
&mut this.cx.borrowck_context.constraints.liveness_constraints,
|
|
||||||
&mut liveness_constraints,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
swap_constraints(self);
|
swap_constraints(self);
|
||||||
|
@ -594,7 +571,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
// temporary from the user's point of view.
|
// temporary from the user's point of view.
|
||||||
constraint.category = ConstraintCategory::Boring;
|
constraint.category = ConstraintCategory::Boring;
|
||||||
}
|
}
|
||||||
self.cx.borrowck_context.constraints.outlives_constraints.push(constraint)
|
self.cx.constraints.outlives_constraints.push(constraint)
|
||||||
}
|
}
|
||||||
// If the region is live at least one location in the promoted MIR,
|
// If the region is live at least one location in the promoted MIR,
|
||||||
// then add a liveness constraint to the main MIR for this region
|
// then add a liveness constraint to the main MIR for this region
|
||||||
|
@ -604,11 +581,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
// unordered.
|
// unordered.
|
||||||
#[allow(rustc::potential_query_instability)]
|
#[allow(rustc::potential_query_instability)]
|
||||||
for region in liveness_constraints.live_regions_unordered() {
|
for region in liveness_constraints.live_regions_unordered() {
|
||||||
self.cx
|
self.cx.constraints.liveness_constraints.add_location(region, location);
|
||||||
.borrowck_context
|
|
||||||
.constraints
|
|
||||||
.liveness_constraints
|
|
||||||
.add_location(region, location);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,26 +826,20 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
/// NLL region checking.
|
/// NLL region checking.
|
||||||
struct TypeChecker<'a, 'tcx> {
|
struct TypeChecker<'a, 'tcx> {
|
||||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
infcx: &'a BorrowckInferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
last_span: Span,
|
last_span: Span,
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
/// User type annotations are shared between the main MIR and the MIR of
|
/// User type annotations are shared between the main MIR and the MIR of
|
||||||
/// all of the promoted items.
|
/// all of the promoted items.
|
||||||
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
|
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
|
||||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
universal_regions: &'a UniversalRegions<'tcx>,
|
||||||
}
|
|
||||||
|
|
||||||
struct BorrowCheckContext<'a, 'tcx> {
|
|
||||||
pub(crate) universal_regions: &'a UniversalRegions<'tcx>,
|
|
||||||
location_table: &'a LocationTable,
|
location_table: &'a LocationTable,
|
||||||
all_facts: &'a mut Option<AllFacts>,
|
all_facts: &'a mut Option<AllFacts>,
|
||||||
borrow_set: &'a BorrowSet<'tcx>,
|
borrow_set: &'a BorrowSet<'tcx>,
|
||||||
pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||||
upvars: &'a [&'a ty::CapturedPlace<'tcx>],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions
|
/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions
|
||||||
|
@ -1006,29 +973,6 @@ impl Locations {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
fn new(
|
|
||||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
|
||||||
body: &'a Body<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
|
||||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
|
||||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
infcx,
|
|
||||||
last_span: body.span,
|
|
||||||
body,
|
|
||||||
user_type_annotations: &body.user_type_annotations,
|
|
||||||
param_env,
|
|
||||||
region_bound_pairs,
|
|
||||||
known_type_outlives_obligations,
|
|
||||||
implicit_region_bound,
|
|
||||||
borrowck_context,
|
|
||||||
reported_errors: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn body(&self) -> &Body<'tcx> {
|
fn body(&self) -> &Body<'tcx> {
|
||||||
self.body
|
self.body
|
||||||
}
|
}
|
||||||
|
@ -1067,15 +1011,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
|
||||||
constraint_conversion::ConstraintConversion::new(
|
constraint_conversion::ConstraintConversion::new(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
self.borrowck_context.universal_regions,
|
self.universal_regions,
|
||||||
self.region_bound_pairs,
|
&self.region_bound_pairs,
|
||||||
self.implicit_region_bound,
|
self.implicit_region_bound,
|
||||||
self.param_env,
|
self.infcx.param_env,
|
||||||
self.known_type_outlives_obligations,
|
&self.known_type_outlives_obligations,
|
||||||
locations,
|
locations,
|
||||||
locations.span(self.body),
|
locations.span(self.body),
|
||||||
category,
|
category,
|
||||||
self.borrowck_context.constraints,
|
self.constraints,
|
||||||
)
|
)
|
||||||
.convert_all(data);
|
.convert_all(data);
|
||||||
}
|
}
|
||||||
|
@ -1120,7 +1064,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
|
|
||||||
for proj in &user_ty.projs {
|
for proj in &user_ty.projs {
|
||||||
if let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind() {
|
if !self.infcx.next_trait_solver()
|
||||||
|
&& let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind()
|
||||||
|
{
|
||||||
// There is nothing that we can compare here if we go through an opaque type.
|
// There is nothing that we can compare here if we go through an opaque type.
|
||||||
// We're always in its defining scope as we can otherwise not project through
|
// We're always in its defining scope as we can otherwise not project through
|
||||||
// it, so we're constraining it anyways.
|
// it, so we're constraining it anyways.
|
||||||
|
@ -1131,7 +1077,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
proj,
|
proj,
|
||||||
|this, field, ()| {
|
|this, field, ()| {
|
||||||
let ty = this.field_ty(tcx, field);
|
let ty = this.field_ty(tcx, field);
|
||||||
self.normalize(ty, locations)
|
self.structurally_resolve(ty, locations)
|
||||||
},
|
},
|
||||||
|_, _| unreachable!(),
|
|_, _| unreachable!(),
|
||||||
);
|
);
|
||||||
|
@ -1191,7 +1137,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// though.
|
// though.
|
||||||
let category = match place.as_local() {
|
let category = match place.as_local() {
|
||||||
Some(RETURN_PLACE) => {
|
Some(RETURN_PLACE) => {
|
||||||
let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
|
let defining_ty = &self.universal_regions.defining_ty;
|
||||||
if defining_ty.is_const() {
|
if defining_ty.is_const() {
|
||||||
if tcx.is_static(defining_ty.def_id()) {
|
if tcx.is_static(defining_ty.def_id()) {
|
||||||
ConstraintCategory::UseAsStatic
|
ConstraintCategory::UseAsStatic
|
||||||
|
@ -1308,6 +1254,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
| StatementKind::Coverage(..)
|
| StatementKind::Coverage(..)
|
||||||
| StatementKind::ConstEvalCounter
|
| StatementKind::ConstEvalCounter
|
||||||
| StatementKind::PlaceMention(..)
|
| StatementKind::PlaceMention(..)
|
||||||
|
| StatementKind::BackwardIncompatibleDropHint { .. }
|
||||||
| StatementKind::Nop => {}
|
| StatementKind::Nop => {}
|
||||||
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
||||||
bug!("Statement not allowed in this MIR phase")
|
bug!("Statement not allowed in this MIR phase")
|
||||||
|
@ -1375,9 +1322,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
|
||||||
let region_ctxt_fn = || {
|
let region_ctxt_fn = || {
|
||||||
let reg_info = match br.kind {
|
let reg_info = match br.kind {
|
||||||
ty::BoundRegionKind::BrAnon => sym::anon,
|
ty::BoundRegionKind::Anon => sym::anon,
|
||||||
ty::BoundRegionKind::BrNamed(_, name) => name,
|
ty::BoundRegionKind::Named(_, name) => name,
|
||||||
ty::BoundRegionKind::BrEnv => sym::env,
|
ty::BoundRegionKind::ClosureEnv => sym::env,
|
||||||
};
|
};
|
||||||
|
|
||||||
RegionCtxt::LateBound(reg_info)
|
RegionCtxt::LateBound(reg_info)
|
||||||
|
@ -1439,12 +1386,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// output) types in the signature must be live, since
|
// output) types in the signature must be live, since
|
||||||
// all the inputs that fed into it were live.
|
// all the inputs that fed into it were live.
|
||||||
for &late_bound_region in map.values() {
|
for &late_bound_region in map.values() {
|
||||||
let region_vid =
|
let region_vid = self.universal_regions.to_region_vid(late_bound_region);
|
||||||
self.borrowck_context.universal_regions.to_region_vid(late_bound_region);
|
self.constraints.liveness_constraints.add_location(region_vid, term_location);
|
||||||
self.borrowck_context
|
|
||||||
.constraints
|
|
||||||
.liveness_constraints
|
|
||||||
.add_location(region_vid, term_location);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_call_inputs(body, term, func, &sig, args, term_location, call_source);
|
self.check_call_inputs(body, term, func, &sig, args, term_location, call_source);
|
||||||
|
@ -1532,18 +1475,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let dest_ty = self.normalize(dest_ty, term_location);
|
let dest_ty = self.normalize(dest_ty, term_location);
|
||||||
let category = match destination.as_local() {
|
let category = match destination.as_local() {
|
||||||
Some(RETURN_PLACE) => {
|
Some(RETURN_PLACE) => {
|
||||||
if let BorrowCheckContext {
|
if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) =
|
||||||
universal_regions:
|
self.universal_regions.defining_ty
|
||||||
UniversalRegions {
|
|
||||||
defining_ty:
|
|
||||||
DefiningTy::Const(def_id, _)
|
|
||||||
| DefiningTy::InlineConst(def_id, _),
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} = self.borrowck_context
|
|
||||||
{
|
{
|
||||||
if tcx.is_static(*def_id) {
|
if tcx.is_static(def_id) {
|
||||||
ConstraintCategory::UseAsStatic
|
ConstraintCategory::UseAsStatic
|
||||||
} else {
|
} else {
|
||||||
ConstraintCategory::UseAsConst
|
ConstraintCategory::UseAsConst
|
||||||
|
@ -1582,7 +1517,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// The signature in this call can reference region variables,
|
// The signature in this call can reference region variables,
|
||||||
// so erase them before calling a query.
|
// so erase them before calling a query.
|
||||||
let output_ty = self.tcx().erase_regions(sig.output());
|
let output_ty = self.tcx().erase_regions(sig.output());
|
||||||
if !output_ty.is_privately_uninhabited(self.tcx(), self.param_env) {
|
if !output_ty.is_privately_uninhabited(
|
||||||
|
self.tcx(),
|
||||||
|
self.infcx.typing_env(self.infcx.param_env),
|
||||||
|
) {
|
||||||
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1606,9 +1544,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
|
||||||
let func_ty = func.ty(body, self.infcx.tcx);
|
let func_ty = func.ty(body, self.infcx.tcx);
|
||||||
if let ty::FnDef(def_id, _) = *func_ty.kind() {
|
if let ty::FnDef(def_id, _) = *func_ty.kind() {
|
||||||
// Some of the SIMD intrinsics are special: they need a particular argument to be a constant.
|
// Some of the SIMD intrinsics are special: they need a particular argument to be a
|
||||||
// (Eventually this should use const-generics, but those are not up for the task yet:
|
// constant. (Eventually this should use const-generics, but those are not up for the
|
||||||
// https://github.com/rust-lang/rust/issues/85229.)
|
// task yet: https://github.com/rust-lang/rust/issues/85229.)
|
||||||
if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) =
|
if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) =
|
||||||
self.tcx().intrinsic(def_id).map(|i| i.name)
|
self.tcx().intrinsic(def_id).map(|i| i.name)
|
||||||
{
|
{
|
||||||
|
@ -1792,7 +1730,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// `Sized` bound in no way depends on precise regions, so this
|
// `Sized` bound in no way depends on precise regions, so this
|
||||||
// shouldn't affect `is_sized`.
|
// shouldn't affect `is_sized`.
|
||||||
let erased_ty = tcx.erase_regions(ty);
|
let erased_ty = tcx.erase_regions(ty);
|
||||||
if !erased_ty.is_sized(tcx, self.param_env) {
|
// FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here.
|
||||||
|
if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) {
|
||||||
// in current MIR construction, all non-control-flow rvalue
|
// in current MIR construction, all non-control-flow rvalue
|
||||||
// expressions evaluate through `as_temp` or `into` a return
|
// expressions evaluate through `as_temp` or `into` a return
|
||||||
// slot or local, so to find all unsized rvalues it is enough
|
// slot or local, so to find all unsized rvalues it is enough
|
||||||
|
@ -1921,7 +1860,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
if len.try_to_target_usize(tcx).is_none_or(|len| len > 1) {
|
if len.try_to_target_usize(tcx).is_none_or(|len| len > 1) {
|
||||||
match operand {
|
match operand {
|
||||||
Operand::Copy(..) | Operand::Constant(..) => {
|
Operand::Copy(..) | Operand::Constant(..) => {
|
||||||
// These are always okay: direct use of a const, or a value that can evidently be copied.
|
// These are always okay: direct use of a const, or a value that can
|
||||||
|
// evidently be copied.
|
||||||
}
|
}
|
||||||
Operand::Move(place) => {
|
Operand::Move(place) => {
|
||||||
// Make sure that repeated elements implement `Copy`.
|
// Make sure that repeated elements implement `Copy`.
|
||||||
|
@ -2402,9 +2342,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let dst_tail = self.struct_tail(dst.ty, location);
|
let dst_tail = self.struct_tail(dst.ty, location);
|
||||||
|
|
||||||
// This checks (lifetime part of) vtable validity for pointer casts,
|
// This checks (lifetime part of) vtable validity for pointer casts,
|
||||||
// which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
|
// which is irrelevant when there are aren't principal traits on
|
||||||
|
// both sides (aka only auto traits).
|
||||||
//
|
//
|
||||||
// Note that other checks (such as denying `dyn Send` -> `dyn Debug`) are in `rustc_hir_typeck`.
|
// Note that other checks (such as denying `dyn Send` -> `dyn
|
||||||
|
// Debug`) are in `rustc_hir_typeck`.
|
||||||
if let ty::Dynamic(src_tty, ..) = src_tail.kind()
|
if let ty::Dynamic(src_tty, ..) = src_tail.kind()
|
||||||
&& let ty::Dynamic(dst_tty, ..) = dst_tail.kind()
|
&& let ty::Dynamic(dst_tty, ..) = dst_tail.kind()
|
||||||
&& src_tty.principal().is_some()
|
&& src_tty.principal().is_some()
|
||||||
|
@ -2427,8 +2369,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
ty::Dyn,
|
ty::Dyn,
|
||||||
));
|
));
|
||||||
|
|
||||||
// Replace trait object lifetimes with fresh vars, to allow casts like
|
// Replace trait object lifetimes with fresh vars, to allow
|
||||||
// `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static`,
|
// casts like
|
||||||
|
// `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static`
|
||||||
let src_obj =
|
let src_obj =
|
||||||
freshen_single_trait_object_lifetime(self.infcx, src_obj);
|
freshen_single_trait_object_lifetime(self.infcx, src_obj);
|
||||||
let dst_obj =
|
let dst_obj =
|
||||||
|
@ -2650,8 +2593,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
borrowed_place: &Place<'tcx>,
|
borrowed_place: &Place<'tcx>,
|
||||||
) {
|
) {
|
||||||
// These constraints are only meaningful during borrowck:
|
// These constraints are only meaningful during borrowck:
|
||||||
let BorrowCheckContext { borrow_set, location_table, all_facts, constraints, .. } =
|
let Self { borrow_set, location_table, all_facts, constraints, .. } = self;
|
||||||
self.borrowck_context;
|
|
||||||
|
|
||||||
// In Polonius mode, we also push a `loan_issued_at` fact
|
// In Polonius mode, we also push a `loan_issued_at` fact
|
||||||
// linking the loan to the region (in some cases, though,
|
// linking the loan to the region (in some cases, though,
|
||||||
|
@ -2681,12 +2623,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let field = path_utils::is_upvar_field_projection(
|
let def = self.body.source.def_id().expect_local();
|
||||||
tcx,
|
let upvars = tcx.closure_captures(def);
|
||||||
self.borrowck_context.upvars,
|
let field =
|
||||||
borrowed_place.as_ref(),
|
path_utils::is_upvar_field_projection(tcx, upvars, borrowed_place.as_ref(), body);
|
||||||
body,
|
|
||||||
);
|
|
||||||
let category = if let Some(field) = field {
|
let category = if let Some(field) = field {
|
||||||
ConstraintCategory::ClosureUpvar(field)
|
ConstraintCategory::ClosureUpvar(field)
|
||||||
} else {
|
} else {
|
||||||
|
@ -2840,15 +2780,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
|
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
|
||||||
constraint_conversion::ConstraintConversion::new(
|
constraint_conversion::ConstraintConversion::new(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
self.borrowck_context.universal_regions,
|
self.universal_regions,
|
||||||
self.region_bound_pairs,
|
&self.region_bound_pairs,
|
||||||
self.implicit_region_bound,
|
self.implicit_region_bound,
|
||||||
self.param_env,
|
self.infcx.param_env,
|
||||||
self.known_type_outlives_obligations,
|
&self.known_type_outlives_obligations,
|
||||||
locations,
|
locations,
|
||||||
self.body.span, // irrelevant; will be overridden.
|
self.body.span, // irrelevant; will be overridden.
|
||||||
ConstraintCategory::Boring, // same as above.
|
ConstraintCategory::Boring, // same as above.
|
||||||
self.borrowck_context.constraints,
|
self.constraints,
|
||||||
)
|
)
|
||||||
.apply_closure_requirements(closure_requirements, def_id.to_def_id(), args);
|
.apply_closure_requirements(closure_requirements, def_id.to_def_id(), args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,11 +240,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
||||||
|
|
||||||
fn create_next_universe(&mut self) -> ty::UniverseIndex {
|
fn create_next_universe(&mut self) -> ty::UniverseIndex {
|
||||||
let universe = self.type_checker.infcx.create_next_universe();
|
let universe = self.type_checker.infcx.create_next_universe();
|
||||||
self.type_checker
|
self.type_checker.constraints.universe_causes.insert(universe, self.universe_info.clone());
|
||||||
.borrowck_context
|
|
||||||
.constraints
|
|
||||||
.universe_causes
|
|
||||||
.insert(universe, self.universe_info.clone());
|
|
||||||
universe
|
universe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,16 +260,13 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
|
fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
|
||||||
let reg = self
|
let reg =
|
||||||
.type_checker
|
self.type_checker.constraints.placeholder_region(self.type_checker.infcx, placeholder);
|
||||||
.borrowck_context
|
|
||||||
.constraints
|
|
||||||
.placeholder_region(self.type_checker.infcx, placeholder);
|
|
||||||
|
|
||||||
let reg_info = match placeholder.bound.kind {
|
let reg_info = match placeholder.bound.kind {
|
||||||
ty::BoundRegionKind::BrAnon => sym::anon,
|
ty::BoundRegionKind::Anon => sym::anon,
|
||||||
ty::BoundRegionKind::BrNamed(_, name) => name,
|
ty::BoundRegionKind::Named(_, name) => name,
|
||||||
ty::BoundRegionKind::BrEnv => sym::env,
|
ty::BoundRegionKind::ClosureEnv => sym::env,
|
||||||
};
|
};
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
|
@ -294,10 +287,9 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
||||||
sub: ty::Region<'tcx>,
|
sub: ty::Region<'tcx>,
|
||||||
info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub);
|
let sub = self.type_checker.universal_regions.to_region_vid(sub);
|
||||||
let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup);
|
let sup = self.type_checker.universal_regions.to_region_vid(sup);
|
||||||
self.type_checker.borrowck_context.constraints.outlives_constraints.push(
|
self.type_checker.constraints.outlives_constraints.push(OutlivesConstraint {
|
||||||
OutlivesConstraint {
|
|
||||||
sup,
|
sup,
|
||||||
sub,
|
sub,
|
||||||
locations: self.locations,
|
locations: self.locations,
|
||||||
|
@ -305,8 +297,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
||||||
category: self.category,
|
category: self.category,
|
||||||
variance_info: info,
|
variance_info: info,
|
||||||
from_closure: false,
|
from_closure: false,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +522,7 @@ impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_
|
||||||
}
|
}
|
||||||
|
|
||||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||||
self.type_checker.param_env
|
self.type_checker.infcx.param_env
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_predicates(
|
fn register_predicates(
|
||||||
|
|
|
@ -248,12 +248,8 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||||
/// MIR -- that is, all the regions that appear in the function's
|
/// MIR -- that is, all the regions that appear in the function's
|
||||||
/// signature. This will also compute the relationships that are
|
/// signature. This will also compute the relationships that are
|
||||||
/// known between those regions.
|
/// known between those regions.
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId) -> Self {
|
||||||
infcx: &BorrowckInferCtxt<'tcx>,
|
UniversalRegionsBuilder { infcx, mir_def }.build()
|
||||||
mir_def: LocalDefId,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
) -> Self {
|
|
||||||
UniversalRegionsBuilder { infcx, mir_def, param_env }.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a reference to a closure type, extracts all the values
|
/// Given a reference to a closure type, extracts all the values
|
||||||
|
@ -312,7 +308,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||||
|
|
||||||
/// Returns an iterator over all the RegionVids corresponding to
|
/// Returns an iterator over all the RegionVids corresponding to
|
||||||
/// universally quantified free regions.
|
/// universally quantified free regions.
|
||||||
pub(crate) fn universal_regions(&self) -> impl Iterator<Item = RegionVid> {
|
pub(crate) fn universal_regions_iter(&self) -> impl Iterator<Item = RegionVid> {
|
||||||
(FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize)
|
(FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +332,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an iterator over all the early-bound regions that have names.
|
/// Gets an iterator over all the early-bound regions that have names.
|
||||||
pub(crate) fn named_universal_regions<'s>(
|
pub(crate) fn named_universal_regions_iter<'s>(
|
||||||
&'s self,
|
&'s self,
|
||||||
) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> + 's {
|
) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> + 's {
|
||||||
self.indices.indices.iter().map(|(&r, &v)| (r, v))
|
self.indices.indices.iter().map(|(&r, &v)| (r, v))
|
||||||
|
@ -426,7 +422,6 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||||
struct UniversalRegionsBuilder<'infcx, 'tcx> {
|
struct UniversalRegionsBuilder<'infcx, 'tcx> {
|
||||||
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
||||||
mir_def: LocalDefId,
|
mir_def: LocalDefId,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion;
|
const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion;
|
||||||
|
@ -435,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||||
fn build(self) -> UniversalRegions<'tcx> {
|
fn build(self) -> UniversalRegions<'tcx> {
|
||||||
debug!("build(mir_def={:?})", self.mir_def);
|
debug!("build(mir_def={:?})", self.mir_def);
|
||||||
|
|
||||||
let param_env = self.param_env;
|
let param_env = self.infcx.param_env;
|
||||||
debug!("build: param_env={:?}", param_env);
|
debug!("build: param_env={:?}", param_env);
|
||||||
|
|
||||||
assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars());
|
assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars());
|
||||||
|
@ -696,14 +691,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||||
let closure_sig = args.as_closure().sig();
|
let closure_sig = args.as_closure().sig();
|
||||||
let inputs_and_output = closure_sig.inputs_and_output();
|
let inputs_and_output = closure_sig.inputs_and_output();
|
||||||
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
|
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
|
||||||
inputs_and_output
|
inputs_and_output.bound_vars().iter().chain(iter::once(
|
||||||
.bound_vars()
|
ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),
|
||||||
.iter()
|
)),
|
||||||
.chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
|
|
||||||
);
|
);
|
||||||
let br = ty::BoundRegion {
|
let br = ty::BoundRegion {
|
||||||
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
|
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
|
||||||
kind: ty::BrEnv,
|
kind: ty::BoundRegionKind::ClosureEnv,
|
||||||
};
|
};
|
||||||
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
|
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
|
||||||
let closure_ty = tcx.closure_env_ty(
|
let closure_ty = tcx.closure_env_ty(
|
||||||
|
@ -751,15 +745,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||||
DefiningTy::CoroutineClosure(def_id, args) => {
|
DefiningTy::CoroutineClosure(def_id, args) => {
|
||||||
assert_eq!(self.mir_def.to_def_id(), def_id);
|
assert_eq!(self.mir_def.to_def_id(), def_id);
|
||||||
let closure_sig = args.as_coroutine_closure().coroutine_closure_sig();
|
let closure_sig = args.as_coroutine_closure().coroutine_closure_sig();
|
||||||
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
|
let bound_vars =
|
||||||
closure_sig
|
tcx.mk_bound_variable_kinds_from_iter(closure_sig.bound_vars().iter().chain(
|
||||||
.bound_vars()
|
iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv)),
|
||||||
.iter()
|
));
|
||||||
.chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
|
|
||||||
);
|
|
||||||
let br = ty::BoundRegion {
|
let br = ty::BoundRegion {
|
||||||
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
|
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
|
||||||
kind: ty::BrEnv,
|
kind: ty::BoundRegionKind::ClosureEnv,
|
||||||
};
|
};
|
||||||
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
|
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
|
||||||
let closure_kind = args.as_coroutine_closure().kind();
|
let closure_kind = args.as_coroutine_closure().kind();
|
||||||
|
|
|
@ -300,7 +300,10 @@ pub fn parse_asm_args<'a>(
|
||||||
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
|
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
|
||||||
dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
|
dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
|
||||||
}
|
}
|
||||||
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
|
if args.options.contains(ast::InlineAsmOptions::NORETURN)
|
||||||
|
&& !outputs_sp.is_empty()
|
||||||
|
&& labels_sp.is_empty()
|
||||||
|
{
|
||||||
let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
|
let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
|
||||||
// Bail out now since this is likely to confuse MIR
|
// Bail out now since this is likely to confuse MIR
|
||||||
return Err(err);
|
return Err(err);
|
||||||
|
|
|
@ -39,50 +39,10 @@ pub(crate) fn cfg_eval(
|
||||||
let features = Some(features);
|
let features = Some(features);
|
||||||
CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id })
|
CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id })
|
||||||
.configure_annotatable(annotatable)
|
.configure_annotatable(annotatable)
|
||||||
// Since the item itself has already been configured by the `InvocationCollector`,
|
|
||||||
// we know that fold result vector will contain exactly one element.
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CfgEval<'a>(StripUnconfigured<'a>);
|
struct CfgEval<'a>(StripUnconfigured<'a>);
|
||||||
|
|
||||||
fn flat_map_annotatable(
|
|
||||||
vis: &mut impl MutVisitor,
|
|
||||||
annotatable: Annotatable,
|
|
||||||
) -> Option<Annotatable> {
|
|
||||||
match annotatable {
|
|
||||||
Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item),
|
|
||||||
Annotatable::AssocItem(item, ctxt) => {
|
|
||||||
Some(Annotatable::AssocItem(vis.flat_map_assoc_item(item, ctxt).pop()?, ctxt))
|
|
||||||
}
|
|
||||||
Annotatable::ForeignItem(item) => {
|
|
||||||
vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)
|
|
||||||
}
|
|
||||||
Annotatable::Stmt(stmt) => {
|
|
||||||
vis.flat_map_stmt(stmt.into_inner()).pop().map(P).map(Annotatable::Stmt)
|
|
||||||
}
|
|
||||||
Annotatable::Expr(mut expr) => {
|
|
||||||
vis.visit_expr(&mut expr);
|
|
||||||
Some(Annotatable::Expr(expr))
|
|
||||||
}
|
|
||||||
Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm),
|
|
||||||
Annotatable::ExprField(field) => {
|
|
||||||
vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField)
|
|
||||||
}
|
|
||||||
Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField),
|
|
||||||
Annotatable::GenericParam(param) => {
|
|
||||||
vis.flat_map_generic_param(param).pop().map(Annotatable::GenericParam)
|
|
||||||
}
|
|
||||||
Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
|
|
||||||
Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
|
|
||||||
Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
|
|
||||||
Annotatable::Crate(mut krate) => {
|
|
||||||
vis.visit_crate(&mut krate);
|
|
||||||
Some(Annotatable::Crate(krate))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
||||||
struct CfgFinder;
|
struct CfgFinder;
|
||||||
|
|
||||||
|
@ -106,14 +66,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
||||||
Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
|
Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
|
||||||
Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
|
Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
|
||||||
Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
|
Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
|
||||||
Annotatable::Arm(arm) => CfgFinder.visit_arm(arm),
|
_ => unreachable!(),
|
||||||
Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field),
|
|
||||||
Annotatable::PatField(field) => CfgFinder.visit_pat_field(field),
|
|
||||||
Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param),
|
|
||||||
Annotatable::Param(param) => CfgFinder.visit_param(param),
|
|
||||||
Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field),
|
|
||||||
Annotatable::Variant(variant) => CfgFinder.visit_variant(variant),
|
|
||||||
Annotatable::Crate(krate) => CfgFinder.visit_crate(krate),
|
|
||||||
};
|
};
|
||||||
res.is_break()
|
res.is_break()
|
||||||
}
|
}
|
||||||
|
@ -123,11 +76,11 @@ impl CfgEval<'_> {
|
||||||
self.0.configure(node)
|
self.0.configure(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
|
fn configure_annotatable(mut self, annotatable: Annotatable) -> Annotatable {
|
||||||
// Tokenizing and re-parsing the `Annotatable` can have a significant
|
// Tokenizing and re-parsing the `Annotatable` can have a significant
|
||||||
// performance impact, so try to avoid it if possible
|
// performance impact, so try to avoid it if possible
|
||||||
if !has_cfg_or_cfg_attr(&annotatable) {
|
if !has_cfg_or_cfg_attr(&annotatable) {
|
||||||
return Some(annotatable);
|
return annotatable;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The majority of parsed attribute targets will never need to have early cfg-expansion
|
// The majority of parsed attribute targets will never need to have early cfg-expansion
|
||||||
|
@ -140,39 +93,6 @@ impl CfgEval<'_> {
|
||||||
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
|
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
|
||||||
// process is lossless, so this process is invisible to proc-macros.
|
// process is lossless, so this process is invisible to proc-macros.
|
||||||
|
|
||||||
let parse_annotatable_with: for<'a> fn(&mut Parser<'a>) -> PResult<'a, _> =
|
|
||||||
match annotatable {
|
|
||||||
Annotatable::Item(_) => {
|
|
||||||
|parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap()))
|
|
||||||
}
|
|
||||||
Annotatable::AssocItem(_, AssocCtxt::Trait) => |parser| {
|
|
||||||
Ok(Annotatable::AssocItem(
|
|
||||||
parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(),
|
|
||||||
AssocCtxt::Trait,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
Annotatable::AssocItem(_, AssocCtxt::Impl) => |parser| {
|
|
||||||
Ok(Annotatable::AssocItem(
|
|
||||||
parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(),
|
|
||||||
AssocCtxt::Impl,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
Annotatable::ForeignItem(_) => |parser| {
|
|
||||||
Ok(Annotatable::ForeignItem(
|
|
||||||
parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
Annotatable::Stmt(_) => |parser| {
|
|
||||||
Ok(Annotatable::Stmt(P(parser
|
|
||||||
.parse_stmt_without_recovery(false, ForceCollect::Yes)?
|
|
||||||
.unwrap())))
|
|
||||||
},
|
|
||||||
Annotatable::Expr(_) => {
|
|
||||||
|parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?))
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
|
// 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
|
||||||
// to `None`-delimited groups containing the corresponding tokens. This
|
// to `None`-delimited groups containing the corresponding tokens. This
|
||||||
// is normally delayed until the proc-macro server actually needs to
|
// is normally delayed until the proc-macro server actually needs to
|
||||||
|
@ -191,19 +111,56 @@ impl CfgEval<'_> {
|
||||||
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
|
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
|
||||||
// to the captured `AttrTokenStream` (specifically, we capture
|
// to the captured `AttrTokenStream` (specifically, we capture
|
||||||
// `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
|
// `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
|
||||||
|
//
|
||||||
|
// After that we have our re-parsed `AttrTokenStream`, recursively configuring
|
||||||
|
// our attribute target will correctly configure the tokens as well.
|
||||||
let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None);
|
let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None);
|
||||||
parser.capture_cfg = true;
|
parser.capture_cfg = true;
|
||||||
match parse_annotatable_with(&mut parser) {
|
let res: PResult<'_, Annotatable> = try {
|
||||||
Ok(a) => annotatable = a,
|
match annotatable {
|
||||||
|
Annotatable::Item(_) => {
|
||||||
|
let item = parser.parse_item(ForceCollect::Yes)?.unwrap();
|
||||||
|
Annotatable::Item(self.flat_map_item(item).pop().unwrap())
|
||||||
|
}
|
||||||
|
Annotatable::AssocItem(_, AssocCtxt::Trait) => {
|
||||||
|
let item = parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap();
|
||||||
|
Annotatable::AssocItem(
|
||||||
|
self.flat_map_assoc_item(item, AssocCtxt::Trait).pop().unwrap(),
|
||||||
|
AssocCtxt::Trait,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Annotatable::AssocItem(_, AssocCtxt::Impl) => {
|
||||||
|
let item = parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap();
|
||||||
|
Annotatable::AssocItem(
|
||||||
|
self.flat_map_assoc_item(item, AssocCtxt::Impl).pop().unwrap(),
|
||||||
|
AssocCtxt::Impl,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Annotatable::ForeignItem(_) => {
|
||||||
|
let item = parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap();
|
||||||
|
Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
|
||||||
|
}
|
||||||
|
Annotatable::Stmt(_) => {
|
||||||
|
let stmt =
|
||||||
|
parser.parse_stmt_without_recovery(false, ForceCollect::Yes)?.unwrap();
|
||||||
|
Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap()))
|
||||||
|
}
|
||||||
|
Annotatable::Expr(_) => {
|
||||||
|
let mut expr = parser.parse_expr_force_collect()?;
|
||||||
|
self.visit_expr(&mut expr);
|
||||||
|
Annotatable::Expr(expr)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(ann) => ann,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
err.emit();
|
err.emit();
|
||||||
return Some(annotatable);
|
annotatable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we have our re-parsed `AttrTokenStream`, recursively configuring
|
|
||||||
// our attribute target will correctly configure the tokens as well.
|
|
||||||
flat_map_annotatable(self, annotatable)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,10 +204,10 @@ impl MutVisitor for CfgEval<'_> {
|
||||||
fn flat_map_assoc_item(
|
fn flat_map_assoc_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
item: P<ast::AssocItem>,
|
item: P<ast::AssocItem>,
|
||||||
_ctxt: AssocCtxt,
|
ctxt: AssocCtxt,
|
||||||
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||||
let item = configure!(self, item);
|
let item = configure!(self, item);
|
||||||
mut_visit::walk_flat_map_item(self, item)
|
mut_visit::walk_flat_map_assoc_item(self, item, ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flat_map_foreign_item(
|
fn flat_map_foreign_item(
|
||||||
|
@ -258,7 +215,7 @@ impl MutVisitor for CfgEval<'_> {
|
||||||
foreign_item: P<ast::ForeignItem>,
|
foreign_item: P<ast::ForeignItem>,
|
||||||
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
|
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
|
||||||
let foreign_item = configure!(self, foreign_item);
|
let foreign_item = configure!(self, foreign_item);
|
||||||
mut_visit::walk_flat_map_item(self, foreign_item)
|
mut_visit::walk_flat_map_foreign_item(self, foreign_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
|
fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
|
||||||
|
|
|
@ -288,19 +288,18 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
||||||
//
|
//
|
||||||
// We should also write a few new `where` bounds from `#[pointee] T` to `__S`
|
// We should also write a few new `where` bounds from `#[pointee] T` to `__S`
|
||||||
// as well as any bound that indirectly involves the `#[pointee] T` type.
|
// as well as any bound that indirectly involves the `#[pointee] T` type.
|
||||||
for bound in &generics.where_clause.predicates {
|
for predicate in &generics.where_clause.predicates {
|
||||||
if let ast::WherePredicate::BoundPredicate(bound) = bound {
|
if let ast::WherePredicateKind::BoundPredicate(bound) = &predicate.kind {
|
||||||
let mut substitution = TypeSubstitution {
|
let mut substitution = TypeSubstitution {
|
||||||
from_name: pointee_ty_ident.name,
|
from_name: pointee_ty_ident.name,
|
||||||
to_ty: &s_ty,
|
to_ty: &s_ty,
|
||||||
rewritten: false,
|
rewritten: false,
|
||||||
};
|
};
|
||||||
let mut predicate = ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
let mut predicate = ast::WherePredicate {
|
||||||
span: bound.span,
|
kind: ast::WherePredicateKind::BoundPredicate(bound.clone()),
|
||||||
bound_generic_params: bound.bound_generic_params.clone(),
|
span: predicate.span,
|
||||||
bounded_ty: bound.bounded_ty.clone(),
|
id: ast::DUMMY_NODE_ID,
|
||||||
bounds: bound.bounds.clone(),
|
};
|
||||||
});
|
|
||||||
substitution.visit_where_predicate(&mut predicate);
|
substitution.visit_where_predicate(&mut predicate);
|
||||||
if substitution.rewritten {
|
if substitution.rewritten {
|
||||||
impl_generics.where_clause.predicates.push(predicate);
|
impl_generics.where_clause.predicates.push(predicate);
|
||||||
|
@ -319,7 +318,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
||||||
|
|
||||||
fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool {
|
fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool {
|
||||||
for bound in predicates {
|
for bound in predicates {
|
||||||
if let ast::WherePredicate::BoundPredicate(bound) = bound
|
if let ast::WherePredicateKind::BoundPredicate(bound) = &bound.kind
|
||||||
&& bound.bounded_ty.kind.is_simple_path().is_some_and(|name| name == pointee)
|
&& bound.bounded_ty.kind.is_simple_path().is_some_and(|name| name == pointee)
|
||||||
{
|
{
|
||||||
for bound in &bound.bounds {
|
for bound in &bound.bounds {
|
||||||
|
@ -385,8 +384,8 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_where_predicate(&mut self, where_predicate: &mut ast::WherePredicate) {
|
fn visit_where_predicate(&mut self, where_predicate: &mut ast::WherePredicate) {
|
||||||
match where_predicate {
|
match &mut where_predicate.kind {
|
||||||
rustc_ast::WherePredicate::BoundPredicate(bound) => {
|
rustc_ast::WherePredicateKind::BoundPredicate(bound) => {
|
||||||
bound
|
bound
|
||||||
.bound_generic_params
|
.bound_generic_params
|
||||||
.flat_map_in_place(|param| self.flat_map_generic_param(param));
|
.flat_map_in_place(|param| self.flat_map_generic_param(param));
|
||||||
|
@ -395,8 +394,8 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
|
||||||
self.visit_param_bound(bound, BoundKind::Bound)
|
self.visit_param_bound(bound, BoundKind::Bound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rustc_ast::WherePredicate::RegionPredicate(_)
|
rustc_ast::WherePredicateKind::RegionPredicate(_)
|
||||||
| rustc_ast::WherePredicate::EqPredicate(_) => {}
|
| rustc_ast::WherePredicateKind::EqPredicate(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -680,29 +680,20 @@ impl<'a> TraitDef<'a> {
|
||||||
param_clone
|
param_clone
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.map(|mut param| {
|
||||||
|
// Remove all attributes, because there might be helper attributes
|
||||||
|
// from other macros that will not be valid in the expanded implementation.
|
||||||
|
param.attrs.clear();
|
||||||
|
param
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// and similarly for where clauses
|
// and similarly for where clauses
|
||||||
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
|
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
|
||||||
match clause {
|
ast::WherePredicate {
|
||||||
ast::WherePredicate::BoundPredicate(wb) => {
|
kind: clause.kind.clone(),
|
||||||
let span = wb.span.with_ctxt(ctxt);
|
id: ast::DUMMY_NODE_ID,
|
||||||
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
span: clause.span.with_ctxt(ctxt),
|
||||||
span,
|
|
||||||
..wb.clone()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
ast::WherePredicate::RegionPredicate(wr) => {
|
|
||||||
let span = wr.span.with_ctxt(ctxt);
|
|
||||||
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
|
||||||
span,
|
|
||||||
..wr.clone()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
ast::WherePredicate::EqPredicate(we) => {
|
|
||||||
let span = we.span.with_ctxt(ctxt);
|
|
||||||
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { span, ..we.clone() })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -751,13 +742,14 @@ impl<'a> TraitDef<'a> {
|
||||||
|
|
||||||
if !bounds.is_empty() {
|
if !bounds.is_empty() {
|
||||||
let predicate = ast::WhereBoundPredicate {
|
let predicate = ast::WhereBoundPredicate {
|
||||||
span: self.span,
|
|
||||||
bound_generic_params: field_ty_param.bound_generic_params,
|
bound_generic_params: field_ty_param.bound_generic_params,
|
||||||
bounded_ty: field_ty_param.ty,
|
bounded_ty: field_ty_param.ty,
|
||||||
bounds,
|
bounds,
|
||||||
};
|
};
|
||||||
|
|
||||||
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
let kind = ast::WherePredicateKind::BoundPredicate(predicate);
|
||||||
|
let predicate =
|
||||||
|
ast::WherePredicate { kind, id: ast::DUMMY_NODE_ID, span: self.span };
|
||||||
where_clause.predicates.push(predicate);
|
where_clause.predicates.push(predicate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code that generates a test runner to run all the tests in a crate
|
// Code that generates a test runner to run all the tests in a crate
|
||||||
|
|
||||||
use std::{iter, mem};
|
use std::mem;
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::entry::EntryPointType;
|
use rustc_ast::entry::EntryPointType;
|
||||||
|
@ -19,7 +19,7 @@ use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
|
||||||
use rustc_span::symbol::{Ident, Symbol, sym};
|
use rustc_span::symbol::{Ident, Symbol, sym};
|
||||||
use rustc_span::{DUMMY_SP, Span};
|
use rustc_span::{DUMMY_SP, Span};
|
||||||
use rustc_target::spec::PanicStrategy;
|
use rustc_target::spec::PanicStrategy;
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::smallvec;
|
||||||
use thin_vec::{ThinVec, thin_vec};
|
use thin_vec::{ThinVec, thin_vec};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
@ -129,8 +129,9 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||||
c.items.push(mk_main(&mut self.cx));
|
c.items.push(mk_main(&mut self.cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flat_map_item(&mut self, mut i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
fn visit_item(&mut self, item: &mut P<ast::Item>) {
|
||||||
let item = &mut *i;
|
let item = &mut **item;
|
||||||
|
|
||||||
if let Some(name) = get_test_name(&item) {
|
if let Some(name) = get_test_name(&item) {
|
||||||
debug!("this is a test item");
|
debug!("this is a test item");
|
||||||
|
|
||||||
|
@ -144,13 +145,20 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||||
item.kind
|
item.kind
|
||||||
{
|
{
|
||||||
let prev_tests = mem::take(&mut self.tests);
|
let prev_tests = mem::take(&mut self.tests);
|
||||||
walk_item_kind(&mut item.kind, item.span, item.id, self);
|
walk_item_kind(
|
||||||
|
&mut item.kind,
|
||||||
|
item.span,
|
||||||
|
item.id,
|
||||||
|
&mut item.ident,
|
||||||
|
&mut item.vis,
|
||||||
|
(),
|
||||||
|
self,
|
||||||
|
);
|
||||||
self.add_test_cases(item.id, span, prev_tests);
|
self.add_test_cases(item.id, span, prev_tests);
|
||||||
} else {
|
} else {
|
||||||
// But in those cases, we emit a lint to warn the user of these missing tests.
|
// But in those cases, we emit a lint to warn the user of these missing tests.
|
||||||
walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
|
walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
|
||||||
}
|
}
|
||||||
smallvec![i]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,17 +198,16 @@ struct EntryPointCleaner<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MutVisitor for EntryPointCleaner<'a> {
|
impl<'a> MutVisitor for EntryPointCleaner<'a> {
|
||||||
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
fn visit_item(&mut self, item: &mut P<ast::Item>) {
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
let item = walk_flat_map_item(self, i).expect_one("noop did something");
|
ast::mut_visit::walk_item(self, item);
|
||||||
self.depth -= 1;
|
self.depth -= 1;
|
||||||
|
|
||||||
// Remove any #[rustc_main] or #[start] from the AST so it doesn't
|
// Remove any #[rustc_main] or #[start] from the AST so it doesn't
|
||||||
// clash with the one we're going to add, but mark it as
|
// clash with the one we're going to add, but mark it as
|
||||||
// #[allow(dead_code)] to avoid printing warnings.
|
// #[allow(dead_code)] to avoid printing warnings.
|
||||||
let item = match entry_point_type(&item, self.depth == 0) {
|
match entry_point_type(&item, self.depth == 0) {
|
||||||
EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
|
EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
|
||||||
item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
|
|
||||||
let allow_dead_code = attr::mk_attr_nested_word(
|
let allow_dead_code = attr::mk_attr_nested_word(
|
||||||
&self.sess.psess.attr_id_generator,
|
&self.sess.psess.attr_id_generator,
|
||||||
ast::AttrStyle::Outer,
|
ast::AttrStyle::Outer,
|
||||||
|
@ -209,21 +216,12 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
|
||||||
sym::dead_code,
|
sym::dead_code,
|
||||||
self.def_site,
|
self.def_site,
|
||||||
);
|
);
|
||||||
let attrs = attrs
|
item.attrs
|
||||||
.into_iter()
|
.retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start));
|
||||||
.filter(|attr| {
|
item.attrs.push(allow_dead_code);
|
||||||
!attr.has_name(sym::rustc_main) && !attr.has_name(sym::start)
|
|
||||||
})
|
|
||||||
.chain(iter::once(allow_dead_code))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
ast::Item { id, ident, attrs, kind, vis, span, tokens }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
EntryPointType::None | EntryPointType::OtherMain => item,
|
EntryPointType::None | EntryPointType::OtherMain => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
smallvec![item]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +282,7 @@ fn generate_test_harness(
|
||||||
/// Most of the Ident have the usual def-site hygiene for the AST pass. The
|
/// Most of the Ident have the usual def-site hygiene for the AST pass. The
|
||||||
/// exception is the `test_const`s. These have a syntax context that has two
|
/// exception is the `test_const`s. These have a syntax context that has two
|
||||||
/// opaque marks: one from the expansion of `test` or `test_case`, and one
|
/// opaque marks: one from the expansion of `test` or `test_case`, and one
|
||||||
/// generated in `TestHarnessGenerator::flat_map_item`. When resolving this
|
/// generated in `TestHarnessGenerator::visit_item`. When resolving this
|
||||||
/// identifier after failing to find a matching identifier in the root module
|
/// identifier after failing to find a matching identifier in the root module
|
||||||
/// we remove the outer mark, and try resolving at its def-site, which will
|
/// we remove the outer mark, and try resolving at its def-site, which will
|
||||||
/// then resolve to `test_const`.
|
/// then resolve to `test_const`.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
|
@ -46,24 +46,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-bforest"
|
name = "cranelift-bforest"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b80c3a50b9c4c7e5b5f73c0ed746687774fc9e36ef652b110da8daebf0c6e0e6"
|
checksum = "8ea5e7afe85cadb55c4c1176268a2ac046fdff8dfaeca39e18581b9dc319ca9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-entity",
|
"cranelift-entity",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-bitset"
|
name = "cranelift-bitset"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38778758c2ca918b05acb2199134e0c561fb577c50574259b26190b6c2d95ded"
|
checksum = "8ab25ef3be935a80680e393183e1f94ef507e93a24a8369494d2c6818aedb3e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-codegen"
|
name = "cranelift-codegen"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58258667ad10e468bfc13a8d620f50dfcd4bb35d668123e97defa2549b9ad397"
|
checksum = "900a19b84545924f1851cbfe386962edfc4ecbc3366a254825cf1ecbcda8ba08"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"cranelift-bforest",
|
"cranelift-bforest",
|
||||||
|
@ -74,7 +74,7 @@ dependencies = [
|
||||||
"cranelift-entity",
|
"cranelift-entity",
|
||||||
"cranelift-isle",
|
"cranelift-isle",
|
||||||
"gimli",
|
"gimli",
|
||||||
"hashbrown 0.14.5",
|
"hashbrown",
|
||||||
"log",
|
"log",
|
||||||
"regalloc2",
|
"regalloc2",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
|
@ -84,42 +84,42 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-codegen-meta"
|
name = "cranelift-codegen-meta"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "043f0b702e529dcb07ff92bd7d40e7d5317b5493595172c5eb0983343751ee06"
|
checksum = "08c73b2395ffe9e7b4fdf7e2ebc052e7e27af13f68a964985346be4da477a5fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-codegen-shared",
|
"cranelift-codegen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-codegen-shared"
|
name = "cranelift-codegen-shared"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7763578888ab53eca5ce7da141953f828e82c2bfadcffc106d10d1866094ffbb"
|
checksum = "7d9ed0854e96a4ff0879bff39d078de8dea7f002721c9494c1fdb4e1baa86ccc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-control"
|
name = "cranelift-control"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32db15f08c05df570f11e8ab33cb1ec449a64b37c8a3498377b77650bef33d8b"
|
checksum = "b4aca921dd422e781409de0129c255768fec5dec1dae83239b497fb9138abb89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arbitrary",
|
"arbitrary",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-entity"
|
name = "cranelift-entity"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5289cdb399381a27e7bbfa1b42185916007c3d49aeef70b1d01cb4caa8010130"
|
checksum = "e2d770e6605eccee15b49decdd82cd26f2b6404767802471459ea49c57379a98"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-bitset",
|
"cranelift-bitset",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-frontend"
|
name = "cranelift-frontend"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "31ba8ab24eb9470477e98ddfa3c799a649ac5a0d9a2042868c4c952133c234e8"
|
checksum = "29268711cb889cb39215b10faf88b9087d4c9e1d2633581e4f722a2bf4bb4ef9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
"log",
|
"log",
|
||||||
|
@ -129,15 +129,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-isle"
|
name = "cranelift-isle"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b72a3c5c166a70426dcb209bdd0bb71a787c1ea76023dc0974fbabca770e8f9"
|
checksum = "dc65156f010aed1985767ad1bff0eb8d186743b7b03e23d0c17604a253e3f356"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-jit"
|
name = "cranelift-jit"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df32578a47582e49b4fc1f9a5786839d9be1fedaa9f00bea7612c54425663c6b"
|
checksum = "40ba6b46367a4f466cfb1abe32793fa1a0f96d862251491b01a44726b8ed9445"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
|
@ -150,14 +150,14 @@ dependencies = [
|
||||||
"region",
|
"region",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"wasmtime-jit-icache-coherence",
|
"wasmtime-jit-icache-coherence",
|
||||||
"windows-sys",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-module"
|
name = "cranelift-module"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96094a758cdb543c9143f70817cd31069fecd49f50981a0fac06820ac011dc2f"
|
checksum = "007607022a4883ebdffc46c0925e2e10babf2a565ae78518034ade722aa825d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
|
@ -166,9 +166,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-native"
|
name = "cranelift-native"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46a42424c956bbc31fc5c2706073df896156c5420ae8fa2a5d48dbc7b295d71b"
|
checksum = "d8bf9b361eaf5a7627647270fabf1dc910d993edbeaf272a652c107861ebe9c2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -177,9 +177,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-object"
|
name = "cranelift-object"
|
||||||
version = "0.111.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1cf5e2484ab47fe38a3150747cdd2016535f13542a925acca152b63383a6591b"
|
checksum = "30ca5c38fa00c0cd943035391bdcc84ed00748f17c66c682e410f5a62f234d44"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
|
@ -213,24 +213,15 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.29.0"
|
version = "0.31.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fallible-iterator",
|
"fallible-iterator",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.13.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.5"
|
version = "0.14.5"
|
||||||
|
@ -247,7 +238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.5",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -273,10 +264,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mach"
|
name = "mach2"
|
||||||
version = "0.3.2"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
|
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
@ -294,7 +285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
|
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"hashbrown 0.14.5",
|
"hashbrown",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -325,11 +316,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regalloc2"
|
name = "regalloc2"
|
||||||
version = "0.9.3"
|
version = "0.10.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6"
|
checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown 0.13.2",
|
"hashbrown",
|
||||||
"log",
|
"log",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"slice-group-by",
|
"slice-group-by",
|
||||||
|
@ -338,21 +329,21 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "region"
|
name = "region"
|
||||||
version = "2.2.0"
|
version = "3.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
|
checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
"mach",
|
"mach2",
|
||||||
"winapi",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_codegen_cranelift"
|
name = "rustc_codegen_cranelift"
|
||||||
|
@ -421,38 +412,16 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmtime-jit-icache-coherence"
|
name = "wasmtime-jit-icache-coherence"
|
||||||
version = "24.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d15de8429db996f0d17a4163a35eccc3f874cbfb50f29c379951ea1bbb39452e"
|
checksum = "6e458e6a1a010a53f86ac8d75837c0c6b2ce3e54b7503b2f1dc5629a4a541f5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[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]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
@ -462,6 +431,15 @@ dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
|
|
|
@ -8,14 +8,14 @@ crate-type = ["dylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# These have to be in sync with each other
|
# These have to be in sync with each other
|
||||||
cranelift-codegen = { version = "0.111.0", default-features = false, features = ["std", "unwind", "all-arch"] }
|
cranelift-codegen = { version = "0.113.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
|
||||||
cranelift-frontend = { version = "0.111.0" }
|
cranelift-frontend = { version = "0.113.0" }
|
||||||
cranelift-module = { version = "0.111.0" }
|
cranelift-module = { version = "0.113.0" }
|
||||||
cranelift-native = { version = "0.111.0" }
|
cranelift-native = { version = "0.113.0" }
|
||||||
cranelift-jit = { version = "0.111.0", optional = true }
|
cranelift-jit = { version = "0.113.0", optional = true }
|
||||||
cranelift-object = { version = "0.111.0" }
|
cranelift-object = { version = "0.113.0" }
|
||||||
target-lexicon = "0.12.0"
|
target-lexicon = "0.12.0"
|
||||||
gimli = { version = "0.29", default-features = false, features = ["write"] }
|
gimli = { version = "0.31", default-features = false, features = ["write"] }
|
||||||
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||||
|
|
||||||
indexmap = "2.0.0"
|
indexmap = "2.0.0"
|
||||||
|
|
|
@ -102,15 +102,6 @@ pub(crate) fn build_sysroot(
|
||||||
.install_into_sysroot(&dist_dir);
|
.install_into_sysroot(&dist_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy std for the host to the lib dir. This is necessary for the jit mode to find
|
|
||||||
// libstd.
|
|
||||||
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, dist_dir.join("lib").join(lib.file_name().unwrap()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut target_compiler = {
|
let mut target_compiler = {
|
||||||
let rustc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustc-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"));
|
let rustdoc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif"));
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::{fs, io};
|
||||||
|
|
||||||
use crate::path::{Dirs, RelPath};
|
use crate::path::{Dirs, RelPath};
|
||||||
use crate::utils::{copy_dir_recursively, ensure_empty_dir, spawn_and_wait};
|
use crate::utils::{copy_dir_recursively, ensure_empty_dir, spawn_and_wait};
|
||||||
|
@ -89,6 +89,19 @@ impl GitRepo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn verify_checksum(&self, dirs: &Dirs) {
|
||||||
|
let download_dir = self.download_dir(dirs);
|
||||||
|
let actual_hash = format!("{:016x}", hash_dir(&download_dir));
|
||||||
|
if actual_hash != self.content_hash {
|
||||||
|
eprintln!(
|
||||||
|
"Mismatched content hash for {download_dir}: {actual_hash} != {content_hash}. Please run ./y.sh prepare again.",
|
||||||
|
download_dir = download_dir.display(),
|
||||||
|
content_hash = self.content_hash,
|
||||||
|
);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn fetch(&self, dirs: &Dirs) {
|
pub(crate) fn fetch(&self, dirs: &Dirs) {
|
||||||
let download_dir = self.download_dir(dirs);
|
let download_dir = self.download_dir(dirs);
|
||||||
|
|
||||||
|
@ -126,18 +139,11 @@ impl GitRepo {
|
||||||
assert!(target_lockfile.exists());
|
assert!(target_lockfile.exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
let actual_hash = format!("{:016x}", hash_dir(&download_dir));
|
self.verify_checksum(dirs);
|
||||||
if actual_hash != self.content_hash {
|
|
||||||
eprintln!(
|
|
||||||
"Download of {download_dir} failed with mismatched content hash: {actual_hash} != {content_hash}",
|
|
||||||
download_dir = download_dir.display(),
|
|
||||||
content_hash = self.content_hash,
|
|
||||||
);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn patch(&self, dirs: &Dirs) {
|
pub(crate) fn patch(&self, dirs: &Dirs) {
|
||||||
|
self.verify_checksum(dirs);
|
||||||
apply_patches(
|
apply_patches(
|
||||||
dirs,
|
dirs,
|
||||||
self.patch_name,
|
self.patch_name,
|
||||||
|
@ -149,6 +155,13 @@ impl GitRepo {
|
||||||
|
|
||||||
fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
|
fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
|
||||||
eprintln!("[CLONE] {}", repo);
|
eprintln!("[CLONE] {}", repo);
|
||||||
|
|
||||||
|
match fs::remove_dir_all(download_dir) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) if err.kind() == io::ErrorKind::NotFound => {}
|
||||||
|
Err(err) => panic!("Failed to remove {path}: {err}", path = download_dir.display()),
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore exit code as the repo may already have been checked out
|
// Ignore exit code as the repo may already have been checked out
|
||||||
git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap();
|
git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap();
|
||||||
|
|
||||||
|
|
|
@ -616,25 +616,70 @@ pub union MaybeUninit<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod intrinsics {
|
pub mod intrinsics {
|
||||||
extern "rust-intrinsic" {
|
#[rustc_intrinsic]
|
||||||
#[rustc_safe_intrinsic]
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
pub fn abort() -> !;
|
pub fn abort() -> ! {
|
||||||
#[rustc_safe_intrinsic]
|
loop {}
|
||||||
pub fn size_of<T>() -> usize;
|
}
|
||||||
pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
|
#[rustc_intrinsic]
|
||||||
#[rustc_safe_intrinsic]
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
pub fn min_align_of<T>() -> usize;
|
pub fn size_of<T>() -> usize {
|
||||||
pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
loop {}
|
||||||
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
}
|
||||||
pub fn transmute<T, U>(e: T) -> U;
|
#[rustc_intrinsic]
|
||||||
pub fn ctlz_nonzero<T>(x: T) -> u32;
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
#[rustc_safe_intrinsic]
|
pub unsafe fn size_of_val<T: ?::Sized>(_val: *const T) -> usize {
|
||||||
pub fn needs_drop<T: ?::Sized>() -> bool;
|
loop {}
|
||||||
#[rustc_safe_intrinsic]
|
}
|
||||||
pub fn bitreverse<T>(x: T) -> T;
|
#[rustc_intrinsic]
|
||||||
#[rustc_safe_intrinsic]
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
pub fn bswap<T>(x: T) -> T;
|
pub fn min_align_of<T>() -> usize {
|
||||||
pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub unsafe fn min_align_of_val<T: ?::Sized>(_val: *const T) -> usize {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize) {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub unsafe fn transmute<T, U>(_e: T) -> U {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32 {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub fn needs_drop<T: ?::Sized>() -> bool {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub fn bitreverse<T>(_x: T) -> T {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub fn bswap<T>(_x: T) -> T {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize) {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
pub unsafe fn unreachable() -> ! {
|
||||||
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,23 @@ Subject: [PATCH] Disable broken tests
|
||||||
src/report.rs | 36 ++++++++++++++++++++++++++++++++++++
|
src/report.rs | 36 ++++++++++++++++++++++++++++++++++++
|
||||||
1 file changed, 36 insertions(+)
|
1 file changed, 36 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/toolchains/rust.rs b/src/toolchains/rust.rs
|
||||||
|
index 0c50f7a..bfde2b1 100644
|
||||||
|
--- a/src/toolchains/rust.rs
|
||||||
|
+++ b/src/toolchains/rust.rs
|
||||||
|
@@ -83,6 +83,7 @@ impl Toolchain for RustcToolchain {
|
||||||
|
.arg(out_dir)
|
||||||
|
.arg("--target")
|
||||||
|
.arg(built_info::TARGET)
|
||||||
|
+ .arg("-g")
|
||||||
|
.arg(format!("-Cmetadata={lib_name}"))
|
||||||
|
.arg(src_path);
|
||||||
|
if let Some(codegen_backend) = &self.codegen_backend {
|
||||||
diff --git a/src/report.rs b/src/report.rs
|
diff --git a/src/report.rs b/src/report.rs
|
||||||
index 958ab43..dcf1044 100644
|
index 958ab43..dcf1044 100644
|
||||||
--- a/src/report.rs
|
--- a/src/report.rs
|
||||||
+++ b/src/report.rs
|
+++ b/src/report.rs
|
||||||
@@ -48,6 +48,58 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn Toolchain, callee: &dyn Toolc
|
@@ -48,6 +48,40 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn Toolchain, callee: &dyn Toolc
|
||||||
//
|
//
|
||||||
// THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
|
// THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
|
||||||
|
|
||||||
|
@ -19,10 +31,6 @@ index 958ab43..dcf1044 100644
|
||||||
+ if test.test == "F32Array" && test.options.convention == CallingConvention::C {
|
+ if test.test == "F32Array" && test.options.convention == CallingConvention::C {
|
||||||
+ result.check = Busted(Check);
|
+ result.check = Busted(Check);
|
||||||
+ }
|
+ }
|
||||||
+
|
|
||||||
+ if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
|
|
||||||
+ result.check = Busted(Check);
|
|
||||||
+ }
|
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if cfg!(all(target_arch = "aarch64", target_os = "macos")) {
|
+ if cfg!(all(target_arch = "aarch64", target_os = "macos")) {
|
||||||
|
@ -39,21 +47,7 @@ index 958ab43..dcf1044 100644
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if cfg!(all(target_arch = "x86_64", unix)) {
|
|
||||||
+ if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::Rust {
|
|
||||||
+ result.check = Busted(Run);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if cfg!(all(target_arch = "x86_64", windows)) {
|
+ if cfg!(all(target_arch = "x86_64", windows)) {
|
||||||
+ if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust {
|
|
||||||
+ result.check = Busted(Check);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && (test.caller == "rustc" || test.options.repr == LangRepr::Rust) {
|
|
||||||
+ result.check = Busted(Run);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if test.test == "simple" && test.options.convention == CallingConvention::Rust {
|
+ if test.test == "simple" && test.options.convention == CallingConvention::Rust {
|
||||||
+ result.check = Busted(Check);
|
+ result.check = Busted(Check);
|
||||||
+ }
|
+ }
|
||||||
|
|
|
@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644
|
||||||
@@ -1,3 +1,4 @@
|
@@ -1,3 +1,4 @@
|
||||||
+#![cfg(test)]
|
+#![cfg(test)]
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![cfg_attr(bootstrap, feature(const_mut_refs))]
|
#![cfg_attr(bootstrap, feature(const_three_way_compare))]
|
||||||
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
#![cfg_attr(bootstrap, feature(strict_provenance))]
|
||||||
--
|
--
|
||||||
2.21.0 (Apple Git-122)
|
2.21.0 (Apple Git-122)
|
||||||
|
|
|
@ -14,13 +14,14 @@ diff --git a/lib.rs b/lib.rs
|
||||||
index 1e336bf..35e6f54 100644
|
index 1e336bf..35e6f54 100644
|
||||||
--- a/lib.rs
|
--- a/lib.rs
|
||||||
+++ b/lib.rs
|
+++ b/lib.rs
|
||||||
@@ -1,6 +1,5 @@
|
@@ -2,7 +2,6 @@
|
||||||
#![cfg(test)]
|
#![cfg_attr(bootstrap, feature(const_three_way_compare))]
|
||||||
// tidy-alphabetical-start
|
#![cfg_attr(bootstrap, feature(strict_provenance))]
|
||||||
#![cfg_attr(bootstrap, feature(const_mut_refs))]
|
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
|
||||||
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
||||||
#![cfg_attr(test, feature(cfg_match))]
|
#![cfg_attr(test, feature(cfg_match))]
|
||||||
#![feature(alloc_layout_extra)]
|
#![feature(alloc_layout_extra)]
|
||||||
|
#![feature(array_chunks)]
|
||||||
diff --git a/atomic.rs b/atomic.rs
|
diff --git a/atomic.rs b/atomic.rs
|
||||||
index b735957..ea728b6 100644
|
index b735957..ea728b6 100644
|
||||||
--- a/atomic.rs
|
--- a/atomic.rs
|
||||||
|
|
|
@ -12,7 +12,7 @@ index 8402833..84592e0 100644
|
||||||
--- a/slice.rs
|
--- a/slice.rs
|
||||||
+++ b/slice.rs
|
+++ b/slice.rs
|
||||||
@@ -1809,6 +1809,7 @@ fn sort_unstable() {
|
@@ -1809,6 +1809,7 @@ fn sort_unstable() {
|
||||||
assert!(v == [0xDEADBEEF]);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+/*
|
+/*
|
||||||
|
@ -43,26 +43,6 @@ index 8402833..84592e0 100644
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_slice_from_ptr_range() {
|
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
|
2.26.2.7.g19db9cfb68
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2024-09-23"
|
channel = "nightly-2024-11-09"
|
||||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
|
|
|
@ -38,6 +38,11 @@ local-rebuild = true
|
||||||
codegen-backends = ["cranelift"]
|
codegen-backends = ["cranelift"]
|
||||||
deny-warnings = false
|
deny-warnings = false
|
||||||
verbose-tests = false
|
verbose-tests = false
|
||||||
|
# The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is
|
||||||
|
# disabled bootstrap will crash trying to copy llvm tools for the bootstrap
|
||||||
|
# compiler.
|
||||||
|
llvm_tools = false
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
|
|
@ -11,5 +11,22 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src}
|
||||||
cp ../Cargo.* compiler/rustc_codegen_cranelift/
|
cp ../Cargo.* compiler/rustc_codegen_cranelift/
|
||||||
cp -r ../src compiler/rustc_codegen_cranelift/src
|
cp -r ../src compiler/rustc_codegen_cranelift/src
|
||||||
|
|
||||||
|
# FIXME(rust-lang/rust#132719) remove once it doesn't break without this patch
|
||||||
|
cat <<EOF | git apply -
|
||||||
|
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
|
||||||
|
index 3394f2a84a0..cb980dd4d7c 100644
|
||||||
|
--- a/src/bootstrap/src/core/build_steps/compile.rs
|
||||||
|
+++ b/src/bootstrap/src/core/build_steps/compile.rs
|
||||||
|
@@ -1976,7 +1976,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- {
|
||||||
|
+ if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled {
|
||||||
|
// \`llvm-strip\` is used by rustc, which is actually just a symlink to \`llvm-objcopy\`,
|
||||||
|
// so copy and rename \`llvm-objcopy\`.
|
||||||
|
let src_exe = exe("llvm-objcopy", target_compiler.host);
|
||||||
|
EOF
|
||||||
|
|
||||||
./x.py build --stage 1 library/std
|
./x.py build --stage 1 library/std
|
||||||
popd
|
popd
|
||||||
|
|
|
@ -47,9 +47,6 @@ rm tests/ui/abi/variadic-ffi.rs # requires callee side vararg support
|
||||||
rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg support
|
rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg support
|
||||||
rm tests/ui/delegation/fn-header.rs
|
rm tests/ui/delegation/fn-header.rs
|
||||||
|
|
||||||
# unsized locals
|
|
||||||
rm -r tests/run-pass-valgrind/unsized-locals
|
|
||||||
|
|
||||||
# misc unimplemented things
|
# misc unimplemented things
|
||||||
rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
|
rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
|
||||||
rm -r tests/run-make/repr128-dwarf # debuginfo test
|
rm -r tests/run-make/repr128-dwarf # debuginfo test
|
||||||
|
@ -148,6 +145,7 @@ rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same
|
||||||
rm tests/ui/process/process-panic-after-fork.rs # same
|
rm tests/ui/process/process-panic-after-fork.rs # same
|
||||||
|
|
||||||
cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist
|
cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist
|
||||||
|
cp $(../dist/rustc-clif --print target-libdir)/libstd-*.so ../dist/lib/
|
||||||
|
|
||||||
# prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by
|
# prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by
|
||||||
# rustdoc-clif
|
# rustdoc-clif
|
||||||
|
@ -180,92 +178,20 @@ index 9607ff02f96..b7d97caf9a2 100644
|
||||||
Self { cmd }
|
Self { cmd }
|
||||||
}
|
}
|
||||||
|
|
||||||
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
|
|
||||||
index 2047345d78a..a7e9352bb1c 100644
|
|
||||||
--- a/src/bootstrap/src/core/build_steps/test.rs
|
|
||||||
+++ b/src/bootstrap/src/core/build_steps/test.rs
|
|
||||||
@@ -1733,11 +1733,6 @@ fn run(self, builder: &Builder<'_>) {
|
|
||||||
|
|
||||||
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<PathBuf>,
|
|
||||||
-
|
|
||||||
/// The rustdoc executable.
|
|
||||||
pub rustdoc_path: Option<PathBuf>,
|
|
||||||
|
|
||||||
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<String>) -> 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
|
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
|
||||||
index 75fe6a6baaf..852568ae925 100644
|
index e7ae773ffa1d3..04bc2d7787da7 100644
|
||||||
--- a/src/tools/compiletest/src/runtest/run_make.rs
|
--- a/src/tools/compiletest/src/runtest/run_make.rs
|
||||||
+++ b/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) {
|
@@ -329,7 +329,6 @@ impl TestCx<'_> {
|
||||||
.env_remove("MFLAGS")
|
.arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
|
||||||
.env_remove("CARGO_MAKEFLAGS");
|
.arg("--edition=2021")
|
||||||
|
.arg(&self.testpaths.file.join("rmake.rs"))
|
||||||
|
- .arg("-Cprefer-dynamic")
|
||||||
|
// Provide necessary library search paths for rustc.
|
||||||
|
.env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap());
|
||||||
|
|
||||||
- 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
|
EOF
|
||||||
|
|
||||||
echo "[TEST] rustc test suite"
|
echo "[TEST] rustc test suite"
|
||||||
COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
|
COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,ui,incremental}
|
||||||
popd
|
popd
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use rustc_target::abi::call::PassMode;
|
use rustc_target::callconv::PassMode;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use std::mem;
|
||||||
use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
|
use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
|
||||||
use cranelift_codegen::isa::CallConv;
|
use cranelift_codegen::isa::CallConv;
|
||||||
use cranelift_module::ModuleError;
|
use cranelift_module::ModuleError;
|
||||||
|
use rustc_abi::ExternAbi;
|
||||||
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||||
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
|
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
|
@ -18,8 +19,7 @@ use rustc_middle::ty::layout::FnAbiOf;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_target::abi::call::{Conv, FnAbi, PassMode};
|
use rustc_target::callconv::{Conv, FnAbi, PassMode};
|
||||||
use rustc_target::spec::abi::Abi;
|
|
||||||
|
|
||||||
use self::pass_mode::*;
|
use self::pass_mode::*;
|
||||||
pub(crate) use self::returning::codegen_return;
|
pub(crate) use self::returning::codegen_return;
|
||||||
|
@ -80,7 +80,7 @@ pub(crate) fn get_function_sig<'tcx>(
|
||||||
clif_sig_from_fn_abi(
|
clif_sig_from_fn_abi(
|
||||||
tcx,
|
tcx,
|
||||||
default_call_conv,
|
default_call_conv,
|
||||||
&RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
|
&FullyMonomorphizedLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||||
let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() {
|
let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() {
|
||||||
let instance = ty::Instance::expect_resolve(
|
let instance = ty::Instance::expect_resolve(
|
||||||
fx.tcx,
|
fx.tcx,
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::TypingEnv::fully_monomorphized(),
|
||||||
def_id,
|
def_id,
|
||||||
fn_args,
|
fn_args,
|
||||||
source_info.span,
|
source_info.span,
|
||||||
|
@ -389,7 +389,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||||
let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id));
|
let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id));
|
||||||
fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
|
fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
|
||||||
} else {
|
} else {
|
||||||
fx.bcx.ins().trap(TrapCode::User(0));
|
fx.bcx.ins().trap(TrapCode::user(2).unwrap());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,12 +438,12 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||||
extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.node.ty(fx.mir, fx.tcx))),
|
extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.node.ty(fx.mir, fx.tcx))),
|
||||||
);
|
);
|
||||||
let fn_abi = if let Some(instance) = instance {
|
let fn_abi = if let Some(instance) = instance {
|
||||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
|
FullyMonomorphizedLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
|
||||||
} else {
|
} else {
|
||||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
|
FullyMonomorphizedLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_cold = if fn_sig.abi() == Abi::RustCold {
|
let is_cold = if fn_sig.abi() == ExternAbi::RustCold {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
instance.is_some_and(|inst| {
|
instance.is_some_and(|inst| {
|
||||||
|
@ -458,7 +458,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack arguments tuple for closures
|
// Unpack arguments tuple for closures
|
||||||
let mut args = if fn_sig.abi() == Abi::RustCall {
|
let mut args = if fn_sig.abi() == ExternAbi::RustCall {
|
||||||
let (self_arg, pack_arg) = match args {
|
let (self_arg, pack_arg) = match args {
|
||||||
[pack_arg] => (None, codegen_call_argument_operand(fx, &pack_arg.node)),
|
[pack_arg] => (None, codegen_call_argument_operand(fx, &pack_arg.node)),
|
||||||
[self_arg, pack_arg] => (
|
[self_arg, pack_arg] => (
|
||||||
|
@ -562,6 +562,11 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||||
adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args);
|
adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fx.clif_comments.enabled() {
|
||||||
|
let nop_inst = fx.bcx.ins().nop();
|
||||||
|
with_no_trimmed_paths!(fx.add_comment(nop_inst, format!("abi: {:?}", fn_abi)));
|
||||||
|
}
|
||||||
|
|
||||||
match func_ref {
|
match func_ref {
|
||||||
CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args),
|
CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args),
|
||||||
CallTarget::Indirect(sig, func_ptr) => {
|
CallTarget::Indirect(sig, func_ptr) => {
|
||||||
|
@ -574,7 +579,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||||
let ret_block = fx.get_block(dest);
|
let ret_block = fx.get_block(dest);
|
||||||
fx.bcx.ins().jump(ret_block, &[]);
|
fx.bcx.ins().jump(ret_block, &[]);
|
||||||
} else {
|
} else {
|
||||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adjust_call_for_c_variadic<'tcx>(
|
fn adjust_call_for_c_variadic<'tcx>(
|
||||||
|
@ -716,8 +721,8 @@ pub(crate) fn codegen_drop<'tcx>(
|
||||||
def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0),
|
def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0),
|
||||||
args: drop_instance.args,
|
args: drop_instance.args,
|
||||||
};
|
};
|
||||||
let fn_abi =
|
let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx)
|
||||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
|
.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||||
|
|
||||||
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
||||||
let sig = fx.bcx.import_signature(sig);
|
let sig = fx.bcx.import_signature(sig);
|
||||||
|
@ -759,8 +764,8 @@ pub(crate) fn codegen_drop<'tcx>(
|
||||||
def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0),
|
def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0),
|
||||||
args: drop_instance.args,
|
args: drop_instance.args,
|
||||||
};
|
};
|
||||||
let fn_abi =
|
let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx)
|
||||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
|
.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||||
|
|
||||||
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
||||||
let sig = fx.bcx.import_signature(sig);
|
let sig = fx.bcx.import_signature(sig);
|
||||||
|
@ -769,8 +774,8 @@ pub(crate) fn codegen_drop<'tcx>(
|
||||||
_ => {
|
_ => {
|
||||||
assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _)));
|
assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _)));
|
||||||
|
|
||||||
let fn_abi =
|
let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx)
|
||||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
|
.fn_abi_of_instance(drop_instance, ty::List::empty());
|
||||||
|
|
||||||
let arg_value = drop_place.place_ref(
|
let arg_value = drop_place.place_ref(
|
||||||
fx,
|
fx,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
//! Argument passing
|
//! Argument passing
|
||||||
|
|
||||||
use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
|
use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
|
||||||
use rustc_target::abi::call::{
|
use rustc_abi::{Reg, RegKind};
|
||||||
ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind,
|
use rustc_target::callconv::{
|
||||||
|
ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode,
|
||||||
};
|
};
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Return value handling
|
//! Return value handling
|
||||||
|
|
||||||
use rustc_target::abi::call::{ArgAbi, PassMode};
|
use rustc_target::callconv::{ArgAbi, PassMode};
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
use rustc_codegen_ssa::back::archive::{
|
|
||||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
|
||||||
};
|
|
||||||
use rustc_session::Session;
|
|
||||||
|
|
||||||
pub(crate) struct ArArchiveBuilderBuilder;
|
|
||||||
|
|
||||||
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
|
||||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
|
||||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use rustc_middle::mir::InlineAsmMacro;
|
use rustc_middle::mir::InlineAsmMacro;
|
||||||
use rustc_middle::ty::TypeVisitableExt;
|
use rustc_middle::ty::TypeVisitableExt;
|
||||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||||
use rustc_middle::ty::layout::FnAbiOf;
|
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
|
|
||||||
use crate::constant::ConstantCx;
|
use crate::constant::ConstantCx;
|
||||||
|
@ -103,12 +103,12 @@ pub(crate) fn codegen_fn<'tcx>(
|
||||||
let block_map: IndexVec<BasicBlock, Block> =
|
let block_map: IndexVec<BasicBlock, Block> =
|
||||||
(0..mir.basic_blocks.len()).map(|_| bcx.create_block()).collect();
|
(0..mir.basic_blocks.len()).map(|_| bcx.create_block()).collect();
|
||||||
|
|
||||||
|
let fn_abi = FullyMonomorphizedLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty());
|
||||||
|
|
||||||
// Make FunctionCx
|
// Make FunctionCx
|
||||||
let target_config = module.target_config();
|
let target_config = module.target_config();
|
||||||
let pointer_type = target_config.pointer_type();
|
let pointer_type = target_config.pointer_type();
|
||||||
let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
|
let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance, fn_abi);
|
||||||
|
|
||||||
let fn_abi = RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty());
|
|
||||||
|
|
||||||
let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context {
|
let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context {
|
||||||
Some(debug_context.define_function(tcx, type_dbg, instance, fn_abi, &symbol_name, mir.span))
|
Some(debug_context.define_function(tcx, type_dbg, instance, fn_abi, &symbol_name, mir.span))
|
||||||
|
@ -294,7 +294,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
if arg_uninhabited {
|
if arg_uninhabited {
|
||||||
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
|
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
|
||||||
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
|
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
|
||||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fx.tcx
|
fx.tcx
|
||||||
|
@ -311,7 +311,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
if !reachable_blocks.contains(bb) {
|
if !reachable_blocks.contains(bb) {
|
||||||
// We want to skip this block, because it's not reachable. But we still create
|
// 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.
|
// the block so terminators in other blocks can reference it.
|
||||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +379,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
|
|
||||||
let target = fx.get_block(*target);
|
let target = fx.get_block(*target);
|
||||||
let failure = fx.bcx.create_block();
|
let failure = fx.bcx.create_block();
|
||||||
fx.bcx.set_cold_block(failure);
|
|
||||||
|
|
||||||
if *expected {
|
if *expected {
|
||||||
fx.bcx.ins().brif(cond, target, &[], failure, &[]);
|
fx.bcx.ins().brif(cond, target, &[], failure, &[]);
|
||||||
|
@ -541,10 +540,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
}
|
}
|
||||||
TerminatorKind::UnwindResume => {
|
TerminatorKind::UnwindResume => {
|
||||||
// FIXME implement unwinding
|
// FIXME implement unwinding
|
||||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
|
||||||
}
|
}
|
||||||
TerminatorKind::Unreachable => {
|
TerminatorKind::Unreachable => {
|
||||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
fx.bcx.set_cold_block(block);
|
||||||
|
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
|
||||||
}
|
}
|
||||||
TerminatorKind::Yield { .. }
|
TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
@ -666,7 +666,7 @@ fn codegen_stmt<'tcx>(
|
||||||
let func_ref = fx.get_function_ref(
|
let func_ref = fx.get_function_ref(
|
||||||
Instance::resolve_for_fn_ptr(
|
Instance::resolve_for_fn_ptr(
|
||||||
fx.tcx,
|
fx.tcx,
|
||||||
ParamEnv::reveal_all(),
|
ty::TypingEnv::fully_monomorphized(),
|
||||||
def_id,
|
def_id,
|
||||||
args,
|
args,
|
||||||
)
|
)
|
||||||
|
@ -841,14 +841,18 @@ fn codegen_stmt<'tcx>(
|
||||||
lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
|
lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
|
||||||
}
|
}
|
||||||
Rvalue::NullaryOp(ref null_op, ty) => {
|
Rvalue::NullaryOp(ref null_op, ty) => {
|
||||||
assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all()));
|
assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env()));
|
||||||
let layout = fx.layout_of(fx.monomorphize(ty));
|
let layout = fx.layout_of(fx.monomorphize(ty));
|
||||||
let val = match null_op {
|
let val = match null_op {
|
||||||
NullOp::SizeOf => layout.size.bytes(),
|
NullOp::SizeOf => layout.size.bytes(),
|
||||||
NullOp::AlignOf => layout.align.abi.bytes(),
|
NullOp::AlignOf => layout.align.abi.bytes(),
|
||||||
NullOp::OffsetOf(fields) => fx
|
NullOp::OffsetOf(fields) => fx
|
||||||
.tcx
|
.tcx
|
||||||
.offset_of_subfield(ParamEnv::reveal_all(), layout, fields.iter())
|
.offset_of_subfield(
|
||||||
|
ty::TypingEnv::fully_monomorphized(),
|
||||||
|
layout,
|
||||||
|
fields.iter(),
|
||||||
|
)
|
||||||
.bytes(),
|
.bytes(),
|
||||||
NullOp::UbChecks => {
|
NullOp::UbChecks => {
|
||||||
let val = fx.tcx.sess.ub_checks();
|
let val = fx.tcx.sess.ub_checks();
|
||||||
|
@ -920,6 +924,7 @@ fn codegen_stmt<'tcx>(
|
||||||
| StatementKind::FakeRead(..)
|
| StatementKind::FakeRead(..)
|
||||||
| StatementKind::Retag { .. }
|
| StatementKind::Retag { .. }
|
||||||
| StatementKind::PlaceMention(..)
|
| StatementKind::PlaceMention(..)
|
||||||
|
| StatementKind::BackwardIncompatibleDropHint { .. }
|
||||||
| StatementKind::AscribeUserType(..) => {}
|
| StatementKind::AscribeUserType(..) => {}
|
||||||
|
|
||||||
StatementKind::Coverage { .. } => unreachable!(),
|
StatementKind::Coverage { .. } => unreachable!(),
|
||||||
|
@ -934,7 +939,7 @@ fn codegen_stmt<'tcx>(
|
||||||
let dst = codegen_operand(fx, dst);
|
let dst = codegen_operand(fx, dst);
|
||||||
let pointee = dst
|
let pointee = dst
|
||||||
.layout()
|
.layout()
|
||||||
.pointee_info_at(fx, rustc_target::abi::Size::ZERO)
|
.pointee_info_at(fx, rustc_abi::Size::ZERO)
|
||||||
.expect("Expected pointer");
|
.expect("Expected pointer");
|
||||||
let dst = dst.load_scalar(fx);
|
let dst = dst.load_scalar(fx);
|
||||||
let src = codegen_operand(fx, src).load_scalar(fx);
|
let src = codegen_operand(fx, src).load_scalar(fx);
|
||||||
|
@ -1075,12 +1080,14 @@ fn codegen_panic_inner<'tcx>(
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
) {
|
) {
|
||||||
|
fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
|
||||||
|
|
||||||
let def_id = fx.tcx.require_lang_item(lang_item, span);
|
let def_id = fx.tcx.require_lang_item(lang_item, span);
|
||||||
|
|
||||||
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
||||||
|
|
||||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||||
fx.bcx.ins().trap(TrapCode::User(0));
|
fx.bcx.ins().trap(TrapCode::user(2).unwrap());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1093,5 +1100,5 @@ fn codegen_panic_inner<'tcx>(
|
||||||
args,
|
args,
|
||||||
);
|
);
|
||||||
|
|
||||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
|
use rustc_abi::{Float, Integer, Primitive};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::ty::TypeFoldable;
|
use rustc_middle::ty::TypeFoldable;
|
||||||
use rustc_middle::ty::layout::{
|
use rustc_middle::ty::layout::{
|
||||||
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
|
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
|
||||||
};
|
};
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_target::abi::call::FnAbi;
|
use rustc_target::callconv::FnAbi;
|
||||||
use rustc_target::abi::{Float, Integer, Primitive};
|
|
||||||
use rustc_target::spec::{HasTargetSpec, Target};
|
use rustc_target::spec::{HasTargetSpec, Target};
|
||||||
|
|
||||||
use crate::constant::ConstantCx;
|
use crate::constant::ConstantCx;
|
||||||
|
@ -103,11 +103,11 @@ fn clif_pair_type_from_ty<'tcx>(
|
||||||
|
|
||||||
/// Is a pointer to this type a wide ptr?
|
/// Is a pointer to this type a wide ptr?
|
||||||
pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
if ty.is_sized(tcx, ParamEnv::reveal_all()) {
|
if ty.is_sized(tcx, ty::TypingEnv::fully_monomorphized()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tail = tcx.struct_tail_for_codegen(ty, ParamEnv::reveal_all());
|
let tail = tcx.struct_tail_for_codegen(ty, ty::TypingEnv::fully_monomorphized());
|
||||||
match tail.kind() {
|
match tail.kind() {
|
||||||
ty::Foreign(..) => false,
|
ty::Foreign(..) => false,
|
||||||
ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
|
ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
|
||||||
|
@ -162,8 +162,8 @@ pub(crate) fn codegen_icmp_imm(
|
||||||
pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value {
|
pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value {
|
||||||
let mut flags = MemFlags::new();
|
let mut flags = MemFlags::new();
|
||||||
flags.set_endianness(match fx.tcx.data_layout.endian {
|
flags.set_endianness(match fx.tcx.data_layout.endian {
|
||||||
rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
|
rustc_abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
|
||||||
rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
|
rustc_abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
|
||||||
});
|
});
|
||||||
fx.bcx.ins().bitcast(dst_ty, flags, val)
|
fx.bcx.ins().bitcast(dst_ty, flags, val)
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
|
||||||
impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
|
impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||||
RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty)
|
FullyMonomorphizedLayoutCx(self.tcx).handle_layout_err(err, span, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
fn_abi_request: FnAbiRequest<'tcx>,
|
fn_abi_request: FnAbiRequest<'tcx>,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
|
FullyMonomorphizedLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,15 +333,15 @@ impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> rustc_target::abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> {
|
impl<'tcx> rustc_abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> {
|
||||||
fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
|
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
|
||||||
&self.tcx.data_layout
|
&self.tcx.data_layout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> layout::HasParamEnv<'tcx> for FunctionCx<'_, '_, 'tcx> {
|
impl<'tcx> layout::HasTypingEnv<'tcx> for FunctionCx<'_, '_, 'tcx> {
|
||||||
fn param_env(&self) -> ParamEnv<'tcx> {
|
fn typing_env(&self) -> ty::TypingEnv<'tcx> {
|
||||||
ParamEnv::reveal_all()
|
ty::TypingEnv::fully_monomorphized()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
||||||
{
|
{
|
||||||
self.instance.instantiate_mir_and_normalize_erasing_regions(
|
self.instance.instantiate_mir_and_normalize_erasing_regions(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::TypingEnv::fully_monomorphized(),
|
||||||
ty::EarlyBinder::bind(value),
|
ty::EarlyBinder::bind(value),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -443,9 +443,9 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
|
pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
|
||||||
|
|
||||||
impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
|
impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||||
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
||||||
|
@ -459,7 +459,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
|
impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn handle_fn_abi_err(
|
fn handle_fn_abi_err(
|
||||||
&self,
|
&self,
|
||||||
|
@ -485,25 +485,25 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> {
|
impl<'tcx> layout::HasTyCtxt<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
|
impl<'tcx> rustc_abi::HasDataLayout for FullyMonomorphizedLayoutCx<'tcx> {
|
||||||
fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
|
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
|
||||||
&self.0.data_layout
|
&self.0.data_layout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> {
|
impl<'tcx> layout::HasTypingEnv<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||||
fn param_env(&self) -> ParamEnv<'tcx> {
|
fn typing_env(&self) -> ty::TypingEnv<'tcx> {
|
||||||
ParamEnv::reveal_all()
|
ty::TypingEnv::fully_monomorphized()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> {
|
impl<'tcx> HasTargetSpec for FullyMonomorphizedLayoutCx<'tcx> {
|
||||||
fn target_spec(&self) -> &Target {
|
fn target_spec(&self) -> &Target {
|
||||||
&self.0.sess.target
|
&self.0.sess.target
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
|
||||||
let cv = fx.monomorphize(constant.const_);
|
let cv = fx.monomorphize(constant.const_);
|
||||||
// This cannot fail because we checked all required_consts in advance.
|
// This cannot fail because we checked all required_consts in advance.
|
||||||
let val = cv
|
let val = cv
|
||||||
.eval(fx.tcx, ty::ParamEnv::reveal_all(), constant.span)
|
.eval(fx.tcx, ty::TypingEnv::fully_monomorphized(), constant.span)
|
||||||
.expect("erroneous constant missed by mono item collection");
|
.expect("erroneous constant missed by mono item collection");
|
||||||
(val, cv.ty())
|
(val, cv.ty())
|
||||||
}
|
}
|
||||||
|
@ -265,8 +265,13 @@ fn data_id_for_static(
|
||||||
assert!(!definition);
|
assert!(!definition);
|
||||||
assert!(!tcx.is_mutable_static(def_id));
|
assert!(!tcx.is_mutable_static(def_id));
|
||||||
|
|
||||||
let ty = instance.ty(tcx, ParamEnv::reveal_all());
|
let ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized());
|
||||||
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
|
let align = tcx
|
||||||
|
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
|
||||||
|
.unwrap()
|
||||||
|
.align
|
||||||
|
.pref
|
||||||
|
.bytes();
|
||||||
|
|
||||||
let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
|
let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
|
||||||
|| import_linkage == rustc_middle::mir::mono::Linkage::WeakAny
|
|| import_linkage == rustc_middle::mir::mono::Linkage::WeakAny
|
||||||
|
@ -578,6 +583,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||||
| StatementKind::PlaceMention(..)
|
| StatementKind::PlaceMention(..)
|
||||||
| StatementKind::Coverage(_)
|
| StatementKind::Coverage(_)
|
||||||
| StatementKind::ConstEvalCounter
|
| StatementKind::ConstEvalCounter
|
||||||
|
| StatementKind::BackwardIncompatibleDropHint { .. }
|
||||||
| StatementKind::Nop => {}
|
| StatementKind::Nop => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue