From d5a32d870120109012daaa348ed97992d0e99ebc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Mar 2022 19:51:26 -0700 Subject: [PATCH 1/7] Add known-bug for #94034 --- src/test/ui/hrtb/issue-94034.rs | 96 +++++++++++++++++++++++++++++ src/test/ui/hrtb/issue-94034.stderr | 1 + 2 files changed, 97 insertions(+) create mode 100644 src/test/ui/hrtb/issue-94034.rs create mode 100644 src/test/ui/hrtb/issue-94034.stderr diff --git a/src/test/ui/hrtb/issue-94034.rs b/src/test/ui/hrtb/issue-94034.rs new file mode 100644 index 0000000000000..5239e5db11c96 --- /dev/null +++ b/src/test/ui/hrtb/issue-94034.rs @@ -0,0 +1,96 @@ +// known-bug +// failure-status: 101 +// compile-flags: --edition=2021 --crate-type=lib +// rustc-env:RUST_BACKTRACE=0 + +// normalize-stderr-test "thread 'rustc' panicked.*" -> "thread 'rustc' panicked" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" +// normalize-stderr-test "#.*\n" -> "" + +// This should not ICE. + +use std::{ + future::Future, + marker::PhantomData, + pin::Pin, + task::{Context, Poll}, +}; + +mod object { + use super::*; + + pub trait Object<'a> { + type Error; + type Future: Future; + fn create() -> Self::Future; + } + + impl<'a> Object<'a> for u8 { + type Error = (); + type Future = Pin>>; + fn create() -> Self::Future { + unimplemented!() + } + } + + impl<'a, E, A: Object<'a, Error = E>> Object<'a> for (A,) { + type Error = (); + type Future = CustomFut<'a, E, A>; + fn create() -> Self::Future { + unimplemented!() + } + } + + pub struct CustomFut<'f, E, A: Object<'f, Error = E>> { + ph: PhantomData<(A::Future,)>, + } + + impl<'f, E, A: Object<'f, Error = E>> Future for CustomFut<'f, E, A> { + type Output = (A,); + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { + unimplemented!() + } + } +} + +mod async_fn { + use super::*; + + pub trait AsyncFn { + type Future: Future; + fn call(&self) -> Self::Future; + } + + impl AsyncFn for F + where + F: Fn() -> Fut, + Fut: Future, + { + type Future = Fut; + fn call(&self) -> Self::Future { + (self)() + } + } +} + +pub async fn test() { + use self::{async_fn::AsyncFn, object::Object}; + + async fn create>() { + T::create().await; + } + + async fn call_async_fn(inner: impl AsyncFn) { + inner.call().await; + } + + call_async_fn(create::<(u8,)>).await; +} diff --git a/src/test/ui/hrtb/issue-94034.stderr b/src/test/ui/hrtb/issue-94034.stderr new file mode 100644 index 0000000000000..1d8329142fc5c --- /dev/null +++ b/src/test/ui/hrtb/issue-94034.stderr @@ -0,0 +1 @@ +thread 'rustc' panicked From 05a467e4ce0000dd5372cbca74c18c001382341a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 3 Apr 2022 19:38:25 -0700 Subject: [PATCH 2/7] Mailmap update --- .mailmap | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 246 insertions(+), 4 deletions(-) diff --git a/.mailmap b/.mailmap index d72e6ebcb65fa..30c3212810cf9 100644 --- a/.mailmap +++ b/.mailmap @@ -7,51 +7,98 @@ Aaron Todd Abhishek Chanda Abhishek Chanda +Abhijeet Bhagat +Abroskin Alexander Adolfo Ochagavía +Adrian Heine né Lang Adrien Tétar Ahmed Charles +Alan Egerton +Alan Stoate +Alessandro Decina Alex Burka Alex Burka +Alex Hansen Alex Lyon Alex Newman Alex HotShot Newman Alex Rønne Petersen +Alex Vlasov +Alex von Gluck IV Alexander Light Alexander Light +Alexander Ronald Altman +Alexandre Martin Alexis Beingessner Alfie John Alfie John +Amos Onn +Ana-Maria Mihalache Anatoly Ikorsky Andre Bogus +Andrea Ciliberti Andreas Gal +Andreas Jonson +Andrew Gauger Andrew Kuchev <0coming.soon@gmail.com> Andrew <0coming.soon@gmail.com> +Andrew Lamb Andrew Poelstra +Anhad Singh +Antoine Plaskowski Anton Löfgren +Araam Borhanian +Araam Borhanian Areski Belaid areski Ariel Ben-Yehuda Ariel Ben-Yehuda Ariel Ben-Yehuda arielb1 +Artem Chernyak +Arthur Cohen +Arthur Silva +Arthur Woimbée +Artyom Pavlov Austin Seipp +Ayaz Hafiz Aydin Kim aydin.kim +Ayush Mishra +asrar +BaoshanPang Barosl Lee Barosl LEE +Bastian Kersting +Bastien Orivel Ben Alpert -Ben Sago Ben S -Ben Sago Ben S +Ben Lewis +Ben Sago +Ben Sago +Ben Striegel Benjamin Jackman +Benoît Cortier Bheesham Persaud Bheesham Persaud Björn Steinbrink blake2-ppc +boolean_coercion Boris Egorov +Braden Nelson Brandon Sanderson Brandon Sanderson Brett Cannon Brett Cannon Brian Anderson Brian Anderson +Brian Bowman +Brian Cain Brian Dawn Brian Leibig Brian Leibig +Caleb Cartwright +Caleb Jones Noah Lev Noah Lev <37223377+camelid@users.noreply.github.com> +cameron1024 +Camille Gillot Carl-Anton Ingmarsson +Carlo Teubner Carol (Nichols || Goulding) <193874+carols10cents@users.noreply.github.com> Carol (Nichols || Goulding) Carol (Nichols || Goulding) Carol Willing +Chandler Deng Charles Lew CrLF0710 Chris C Cerami Chris C Cerami +Chris Gregory +Chris Pardy Chris Pressey Chris Thorn Chris Thorn Chris Vittal Christopher Vittal @@ -62,29 +109,53 @@ Christian Poveda Christian Poveda Christian Poveda Christian Poveda +Christian Vallentin +Christoffer Buchholz +Christopher Durham Clark Gaebel +Clement Miao +Clément Renault +Cliff Dyer Clinton Ryan Corey Richardson Elaine "See More" Nemo +Crazycolorz5 +csmoe <35686186+csmoe@users.noreply.github.com> Cyryl Płotnicki Damien Schoof +Dan Robertson +Daniel Campoverde Daniel J Rollins +Daniel Mueller Daniel Ramos +Daniele D'Orazio +Dante Broggi <34220985+Dante-Broggi@users.noreply.github.com> +David Carlier David Klein David Manescu David Ross David Wood +Deadbeef Deadbeef Derek Chiang Derek Chiang (Enchi Jiang) +DeveloperC +Devin Ragotzy +Dharma Saputra Wijaya Diggory Hardy Diggory Hardy +Dileep Bapat Donough Liu Donough Liu DingMing Liu Dustin Bensing +DutchGhost Dylan Braithwaite +Dylan DPC +Dylan MacKenzie Dzmitry Malyshau E. Dunham edunham +Ed Barnard Eduard-Mihai Burtescu Eduardo Bautista <=> Eduardo Bautista +Eduardo Broto Elliott Slaughter Elly Fong-Jones Eric Holk @@ -92,46 +163,82 @@ Eric Holk Eric Holmes Eric Reed Erick Tryzelaar +Erik Desjardins +Erik Jensen +Erin Power Erin Power Erin Power +Esteban Küber Esteban Küber Esteban Küber Esteban Küber +Ethan Dagner Evgeny Sologubov +F001 +Fabian Kössel Falco Hirschenberger Felix S. Klock II Felix S Klock II +Félix Saparelli Flaper Fesp +Florian Berger Florian Wilkens Florian Wilkens +François Mockers Frank Steffahn +Fridtjof Stoldt +fukatani +Fuqiao Xue Gareth Daniel Smith gareth Gareth Daniel Smith Gareth Smith +Gauri Kholkar Georges Dubus +Giles Cope +Glen De Cauwsemaecker Graham Fawcett Graham Fawcett Graydon Hoare Graydon Hoare +Greg V +Gregor Peach +Grzegorz Bartoszek +Guanqun Lu Guillaume Gomez Guillaume Gomez ggomez Guillaume Gomez Guillaume Gomez Guillaume Gomez Guillaume Gomez +hamidreza kalbasi Hanna Kruppe Heather Heather Herman J. Radtke III Herman J. Radtke III Hirochika Matsumoto +Hrvoje Nikšić +Hsiang-Cheng Yang Ian Jackson Ian Jackson Ian Jackson +Ibraheem Ahmed Ilyong Cho inquisitivecrystal <22333129+inquisitivecrystal@users.noreply.github.com> +Irina Popa Ivan Ivaschenko +ivan tkachenko J. J. Weber +Jack Huey +Jacob +Jacob Greenfield Jacob Pratt +Jake Vossen +Jakob Degen +Jakob Lautrup Nysom +Jakub Adam Wieczorek Jakub Adam Wieczorek Jakub Adam Wieczorek Jakub Adam Wieczorek +James [Undefined] James Deng James Hinshelwood James Miller James Perry +James Sanderson +Jaro Fietz Jason Fager Jason Liquorish Jason Orendorff @@ -140,33 +247,60 @@ Jason Toffaletti Jason Toffaletti Jauhien Piatlicki Jauhien Piatlicki Jay True Jeremy Letang +Jeremy Sorensen Jeremy Stucki Jeremy Stucki Jeremy Stucki +Jerry Hardee +Jesús Rubio Jethro Beekman +Jian Zeng Jihyun Yu Jihyun Yu jihyun Jihyun Yu Jihyun Yu João Oliveira joaoxsouls +joboet Johann Hofmann Johann John Clements John Hodge John Hodge +John Hörnvall John Kåre Alsaker John Talling +John Van Enk +Jonas Tepe Jonathan Bailey +Jonathan Chan Kwan Yin +Jonathan L Jonathan S Jonathan S +Jonathan Sieber Jonathan Turner Jorge Aparicio +Josef Reinhard Brandl +Joseph Dunne Joseph Martin +Joseph Richey +Joseph T. Lyons Joseph T. Lyons Joseph T. Lyons +Josh Cotton +Josh Driver +Josh Holmer Joshua Nelson +Julian Knodt jumbatm <30644300+jumbatm@users.noreply.github.com> Junyoung Cho Jyun-Yan You +Kalita Alexey +Kampfkarren Kang Seonghoon +Karim Snj +Katze Keegan McAllister +Kerem Kat Kevin Butler +Kevin Jiang +Kornel Lesiński +Krishna Sai Veera Reddy Kyeongwoon Lee Kyle J Strand Kyle J Strand @@ -176,57 +310,102 @@ Laurențiu Nicola lcnr Lee Jeffery Lee Jeffery Lee Wondong +lengyijun Lennart Kudling Léo Lanteri Thauvin Léo Lanteri Thauvin <38361244+LeSeulArtichaut@users.noreply.github.com> Léo Testard +Leonardo Yvens +Liigo Zhuang Lily Ballard Lindsey Kuper Lindsey Kuper +Liu Dingming +Loo Maclin +Loïc BRANSTETT +Lucy +Lukas H. +Lukas Lueg Luke Metz Luqman Aden Luqman Aden +Lzu Tao +Maik Klein +Malo Jaffré Manish Goregaokar +Mara Bos Marcell Pardavi +Marcus Klaas de Vries Margaret Meyerhofer +Mark Mansi Mark Rousskov Mark Sinclair Mark Sinclair =Mark Sinclair <=125axel125@gmail.com> +Markus Legner Markus Westerlind Markus +Martin Carton +Martin Habovštiak Martin Hafskjold Thoresen Matej Lach Matej Ľach +Mateusz Mikuła Mateusz Mikuła Mateusz Mikuła Matt Brubeck Matthew Auld +Matthew Jasper Matthew Kraai Matthew Kraai Matthew Kraai Matthew McPherrin +Matthew Tran <0e4ef622@gmail.com> Matthijs Hofstra +Max Sharnoff +Max Wase +Mazdak Farrokhzad +Meade Kincke Melody Horn +Mendes +mental +mibac138 <5672750+mibac138@users.noreply.github.com> Michael Williams Michael Woerister Michael Woerister Michael Woerister +Michael Zhang +Michał Krasnoborski +Michiel De Muynck Mickaël Raybaud-Roig m-r-r +Mikhail Babenko +Milan Landaverde +mjptree Ms2ger +msizanoen1 Mukilan Thiagarajan +Nadrieril Feneanar NAKASHIMA, Makoto NAKASHIMA, Makoto +Nathan Ringo Nathan West +Nathan Whitaker Nathan Wilson +Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Nathaniel Herman Nathaniel Herman Neil Pankey +Ngo Iok Ui (Wu Yu Wei) +Nicholas Baron Nick Platt +Niclas Schwarzlose <15schnic@gmail.com> +Nicolas Abram Nicole Mazzuca Nif Ward Nika Layzell +Nixon Enraght-Moony +NODA Kai +oliver <16816606+o752d@users.noreply.github.com> Oliver Middleton Oliver Scherer Oliver Scherer Oliver Scherer -Oliver Scherer Oliver Scherer Oliver Scherer Oliver Scherer @@ -236,76 +415,139 @@ Oliver Scherer Oliver Scherer Oliver Scherer Oliver Scherer +Ömer Sinan Ağacan +Ophir LOJKINE Ožbolt Menegatti gareins +Pankaj Chaudhary Paul Faria Paul Faria Peer Aramillo Irizar parir Peter Elmers Peter Liniker Phil Dawes Phil Dawes +Phil Hansch Philipp Brüschweiler Philipp Brüschweiler -Philipp Krones flip1995 +Philipp Krones +Philipp Krones <9744647+flip1995@users.noreply.github.com> Philipp Krones +Philipp Krones Philipp Matthias Schäfer +phosphorus +Pierre Krieger pierwill <19642016+pierwill@users.noreply.github.com> +Pradyumna Rahul Przemysław Wesołek Przemek Wesołek +r00ster Rafael Ávila de Espíndola Rafael Avila de Espindola +rail <12975677+rail-rain@users.noreply.github.com> Ralph Giles Ralph Giles Ramkumar Ramachandra +Raphaël Huchet +rChaser53 +Rémy Rakic +Rémy Rakic Renato Riccieri Santos Zannon Richard Diamond +Ricky Hosfelt +Ritiek Malhotra Rob Arnold Rob Arnold Rob Arnold Robert Foss robertfoss Robert Gawdzik Robert Gawdzik ☢ +Robert Habermeier Robert Millar +Roc Yu Rohit Joshi Rohit Joshi +Roxane Fruytier +Rui Russell Johnston +Rustin-Liu +Rusty Blitzerr +RustyYato Ruud van Asseldonk Ruud van Asseldonk +Ryan Leung Ryan Scheel +Ryan Sullivant +Ryan Wiedemann S Pradeep Kumar +Sam Radhakrishnan +Scott McMurray Scott Olson Scott Olson Sean Gillespie swgillespie +Seiichi Uchida Seonghyun Kim +Shohei Wada +Shotaro Yamada +Shotaro Yamada Shyam Sundar B Simon Barber-Dueck Simon BD Simon Sapin Simonas Kazlauskas Simonas Kazlauskas +Siva Prasad +Smittyvb +Srinivas Reddy Thatiparthy +Stanislav Tkach startling Stepan Koltsov Stepan Koltsov Steve Klabnik Steven Fackler +Steven Malis Steven Stewart-Gallus Stuart Pernsteiner Stuart Pernsteiner +Suyash458 +Sébastien Marie +Takashi Idobe +Takayuki Maeda Tamir Duberstein Tamir Duberstein +Tatsuyuki Ishi Tero Hänninen Tero Hänninen +The8472 Theo Belaire Theo Belaire +Theodore Luo Wang Thiago Pontes thiagopnts Thomas Bracht Laumann Jespersen +Tibo Delor Ticki Ticki <@> Tim Brooks Tim Brooks Tim Chevalier +Tim Diekmann +Tim Hutt Tim JIANG Tim Joseph Dumol +Timothy Maloney +Tomas Koutsky +Torsten Weber Torsten Weber Trevor Spiteri Ty Overby Tyler Mandry +Tyler Ruckinger Ulrik Sverdrup bluss Ulrik Sverdrup bluss Ulrik Sverdrup Ulrik Sverdrup Vadim Petrochenkov Vadim Petrochenkov petrochenkov +Val Markovic +Valerii Lashmanov Vitali Haravy Vitali Haravy +Vitaly Shukela +Waffle Maybe Wesley Wiser whitequark William Ting +Wim Looman +Without Boats +Without Boats +Xinye Tao Xuefeng Wu Xuefeng Wu Xuefeng Wu XuefengWu York Xiang Youngsoo Son +Youngsuk Kim +Yuki Okushi Yuki Okushi Yuki Okushi +Yuning Zhang Zach Pomerantz Zack Corr Zack Slayton From 39bff4bf9c998ba77d12b36b26c604340638fa73 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 6 Apr 2022 21:27:46 -0700 Subject: [PATCH 3/7] don't report int/float ambiguity when we have previous errors --- .../src/traits/error_reporting/mod.rs | 22 +++++++++++-- .../ui/traits/no-fallback-multiple-impls.rs | 16 ++++++++++ .../traits/no-fallback-multiple-impls.stderr | 9 ++++++ src/test/ui/traits/test-2.rs | 4 +-- src/test/ui/traits/test-2.stderr | 32 ++----------------- 5 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/traits/no-fallback-multiple-impls.rs create mode 100644 src/test/ui/traits/no-fallback-multiple-impls.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9998c5bb087e1..ac98dd5801e40 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -36,6 +36,7 @@ use rustc_span::symbol::{kw, sym}; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; use std::iter; +use std::ops::ControlFlow; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::AtExt as _; @@ -2226,9 +2227,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { post.dedup(); if self.is_tainted_by_errors() - && crate_names.len() == 1 - && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) - && spans.len() == 0 + && (crate_names.len() == 1 + && spans.len() == 0 + && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) + || predicate.visit_with(&mut HasNumericInferVisitor).is_break()) { // Avoid complaining about other inference issues for expressions like // `42 >> 1`, where the types are still `{integer}`, but we want to @@ -2666,3 +2668,17 @@ impl ArgKind { } } } + +struct HasNumericInferVisitor; + +impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { + type BreakTy = (); + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { + ControlFlow::Break(()) + } else { + ControlFlow::CONTINUE + } + } +} diff --git a/src/test/ui/traits/no-fallback-multiple-impls.rs b/src/test/ui/traits/no-fallback-multiple-impls.rs new file mode 100644 index 0000000000000..7ed3796f08b76 --- /dev/null +++ b/src/test/ui/traits/no-fallback-multiple-impls.rs @@ -0,0 +1,16 @@ +trait Fallback { + fn foo(&self) {} +} + +impl Fallback for i32 {} + +impl Fallback for u64 {} + +impl Fallback for usize {} + +fn main() { + missing(); + //~^ ERROR cannot find function `missing` in this scope + 0.foo(); + // But then we shouldn't report an inference ambiguity here... +} diff --git a/src/test/ui/traits/no-fallback-multiple-impls.stderr b/src/test/ui/traits/no-fallback-multiple-impls.stderr new file mode 100644 index 0000000000000..61c9e5aaabdb4 --- /dev/null +++ b/src/test/ui/traits/no-fallback-multiple-impls.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find function `missing` in this scope + --> $DIR/no-fallback-multiple-impls.rs:12:5 + | +LL | missing(); + | ^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/traits/test-2.rs b/src/test/ui/traits/test-2.rs index d062de25ac8c1..342928e882a55 100644 --- a/src/test/ui/traits/test-2.rs +++ b/src/test/ui/traits/test-2.rs @@ -6,9 +6,9 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } fn main() { - 10.dup::(); //~ ERROR type annotations needed + 10.dup::(); //~^ ERROR this associated function takes 0 generic arguments but 1 - 10.blah::(); //~ ERROR type annotations needed + 10.blah::(); //~^ ERROR this associated function takes 1 generic argument but 2 (Box::new(10) as Box).dup(); //~^ ERROR E0038 diff --git a/src/test/ui/traits/test-2.stderr b/src/test/ui/traits/test-2.stderr index 5eec012458450..77ea4e4e974eb 100644 --- a/src/test/ui/traits/test-2.stderr +++ b/src/test/ui/traits/test-2.stderr @@ -79,35 +79,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box<{integer}>` = note: required by cast to type `Box` -error[E0283]: type annotations needed - --> $DIR/test-2.rs:9:8 - | -LL | 10.dup::(); - | ^^^ cannot infer type for type `{integer}` - | -note: multiple `impl`s satisfying `{integer}: bar` found - --> $DIR/test-2.rs:5:1 - | -LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ -LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ - -error[E0283]: type annotations needed - --> $DIR/test-2.rs:11:8 - | -LL | 10.blah::(); - | ^^^^ cannot infer type for type `{integer}` - | -note: multiple `impl`s satisfying `{integer}: bar` found - --> $DIR/test-2.rs:5:1 - | -LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ -LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0038, E0107, E0283. +Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. From fe855919890d2c7e462763462efd479b083d015a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 14:07:02 -0400 Subject: [PATCH 4/7] make windows compat_fn (crudely) work on Miri --- library/std/src/sys/windows/compat.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index a914a3bcc120b..b6f2f894de8ec 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -77,6 +77,10 @@ macro_rules! compat_fn { static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; unsafe extern "C" fn init() { + PTR = get_f(); + } + + unsafe extern "C" fn get_f() -> Option { // There is no locking here. This code is executed before main() is entered, and // is guaranteed to be single-threaded. // @@ -91,10 +95,11 @@ macro_rules! compat_fn { match $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8).addr() { 0 => {} n => { - PTR = Some(mem::transmute::(n)); + return Some(mem::transmute::(n)); } } } + return None; } #[allow(dead_code)] @@ -105,10 +110,15 @@ macro_rules! compat_fn { #[allow(dead_code)] pub unsafe fn call($($argname: $argtype),*) -> $rettype { if let Some(ptr) = PTR { - ptr($($argname),*) - } else { - $fallback_body + return ptr($($argname),*); + } + if cfg!(miri) { + // Miri does not run `init`, so we just call `get_f` each time. + if let Some(ptr) = get_f() { + return ptr($($argname),*); + } } + $fallback_body } } From c599a4cfc3e33903d6523ba7355f862780714bda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 14:58:02 -0400 Subject: [PATCH 5/7] do not round-trip function pointer through integer --- library/std/src/sys/windows/compat.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index b6f2f894de8ec..c55df04200313 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -92,11 +92,10 @@ macro_rules! compat_fn { let symbol_name: *const u8 = concat!(stringify!($symbol), "\0").as_ptr(); let module_handle = $crate::sys::c::GetModuleHandleA(module_name as *const i8); if !module_handle.is_null() { - match $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8).addr() { - 0 => {} - n => { - return Some(mem::transmute::(n)); - } + let ptr = $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8); + if !ptr.is_null() { + // Transmute to the right function pointer type. + return Some(mem::transmute(ptr)); } } return None; From 38004b72bcfc1ec1892c3186b2627067de6414c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 16:22:09 -0400 Subject: [PATCH 6/7] interpret: err instead of ICE on size mismatches in to_bits_or_ptr_internal --- .../src/const_eval/eval_queries.rs | 23 +++++------ .../src/const_eval/machine.rs | 18 ++++----- .../rustc_const_eval/src/interpret/cast.rs | 2 +- .../src/interpret/eval_context.rs | 2 +- .../rustc_const_eval/src/interpret/intern.rs | 2 +- .../rustc_const_eval/src/interpret/memory.rs | 38 +++++++++++-------- .../rustc_const_eval/src/interpret/operand.rs | 4 +- .../rustc_const_eval/src/interpret/place.rs | 4 +- .../src/interpret/terminator.rs | 2 +- .../rustc_const_eval/src/interpret/traits.rs | 7 ++-- .../src/interpret/validity.rs | 8 ++-- .../src/mir/interpret/allocation.rs | 17 +++++++-- .../rustc_middle/src/mir/interpret/error.rs | 14 ++++--- .../rustc_middle/src/mir/interpret/mod.rs | 3 +- .../rustc_middle/src/mir/interpret/value.rs | 28 ++++++++++---- .../src/thir/pattern/deconstruct_pat.rs | 2 +- 16 files changed, 107 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index b856d1708abc9..498b2f1b081b3 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -167,17 +167,18 @@ pub(super) fn op_to_const<'tcx>( }, Immediate::ScalarPair(a, b) => { // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (data, start) = match ecx.scalar_to_ptr(a.check_init().unwrap()).into_parts() { - (Some(alloc_id), offset) => { - (ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes()) - } - (None, _offset) => ( - ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable( - b"" as &[u8], - )), - 0, - ), - }; + let (data, start) = + match ecx.scalar_to_ptr(a.check_init().unwrap()).unwrap().into_parts() { + (Some(alloc_id), offset) => { + (ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes()) + } + (None, _offset) => ( + ecx.tcx.intern_const_alloc( + Allocation::from_bytes_byte_aligned_immutable(b"" as &[u8]), + ), + 0, + ), + }; let len = b.to_machine_usize(ecx).unwrap(); let start = start.try_into().unwrap(); let len: usize = len.try_into().unwrap(); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index c44e27fc4a098..d57504deeab90 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -197,8 +197,8 @@ impl interpret::MayLeak for ! { } impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { - fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { + fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> { + Ok(match (a, b) { // Comparisons between integers are always known. (Scalar::Int { .. }, Scalar::Int { .. }) => a == b, // Equality with integers can never be known for sure. @@ -207,11 +207,11 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { // some things (like functions and vtables) do not have stable addresses // so we need to be careful around them (see e.g. #73722). (Scalar::Ptr(..), Scalar::Ptr(..)) => false, - } + }) } - fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { + fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> { + Ok(match (a, b) { // Comparisons between integers are always known. (Scalar::Int(_), Scalar::Int(_)) => a != b, // Comparisons of abstract pointers with null pointers are known if the pointer @@ -219,13 +219,13 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { // Inequality with integers other than null can never be known for sure. (Scalar::Int(int), ptr @ Scalar::Ptr(..)) | (ptr @ Scalar::Ptr(..), Scalar::Int(int)) => { - int.is_null() && !self.scalar_may_be_null(ptr) + int.is_null() && !self.scalar_may_be_null(ptr)? } // FIXME: return `true` for at least some comparisons where we can reliably // determine the result of runtime inequality tests at compile-time. // Examples include comparison of addresses in different static items. (Scalar::Ptr(..), Scalar::Ptr(..)) => false, - } + }) } } @@ -329,9 +329,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, let a = ecx.read_immediate(&args[0])?.to_scalar()?; let b = ecx.read_immediate(&args[1])?.to_scalar()?; let cmp = if intrinsic_name == sym::ptr_guaranteed_eq { - ecx.guaranteed_eq(a, b) + ecx.guaranteed_eq(a, b)? } else { - ecx.guaranteed_ne(a, b) + ecx.guaranteed_ne(a, b)? }; ecx.write_scalar(Scalar::from_bool(cmp), dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index a244b79ed0754..3ea3729dbcd17 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -283,7 +283,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(entry_idx) = vptr_entry_idx { let entry_idx = u64::try_from(entry_idx).unwrap(); let (old_data, old_vptr) = val.to_scalar_pair()?; - let old_vptr = self.scalar_to_ptr(old_vptr); + let old_vptr = self.scalar_to_ptr(old_vptr)?; let new_vptr = self .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index a2ea0f516bfa4..f0fff602fe4cf 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -640,7 +640,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Some((size, align))) } ty::Dynamic(..) => { - let vtable = self.scalar_to_ptr(metadata.unwrap_meta()); + let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?; // Read size and align from vtable (already checks size). Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index f1acb9e41c4ce..1fda60c021eed 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -202,7 +202,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory if let ty::Dynamic(..) = tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() { - let ptr = self.ecx.scalar_to_ptr(mplace.meta.unwrap_meta()); + let ptr = self.ecx.scalar_to_ptr(mplace.meta.unwrap_meta())?; if let Some(alloc_id) = ptr.provenance { // Explicitly choose const mode here, since vtables are immutable, even // if the reference of the fat pointer is mutable. diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index a02115a110b7b..556a44a523819 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1102,30 +1102,38 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Machine pointer introspection. impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn scalar_to_ptr(&self, scalar: Scalar) -> Pointer> { + pub fn scalar_to_ptr( + &self, + scalar: Scalar, + ) -> InterpResult<'tcx, Pointer>> { // We use `to_bits_or_ptr_internal` since we are just implementing the method people need to // call to force getting out a pointer. - match scalar.to_bits_or_ptr_internal(self.pointer_size()) { - Err(ptr) => ptr.into(), - Ok(bits) => { - let addr = u64::try_from(bits).unwrap(); - let ptr = M::ptr_from_addr(&self, addr); - if addr == 0 { - assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId"); + Ok( + match scalar + .to_bits_or_ptr_internal(self.pointer_size()) + .map_err(|s| err_ub!(ScalarSizeMismatch(s)))? + { + Err(ptr) => ptr.into(), + Ok(bits) => { + let addr = u64::try_from(bits).unwrap(); + let ptr = M::ptr_from_addr(&self, addr); + if addr == 0 { + assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId"); + } + ptr } - ptr - } - } + }, + ) } /// Test if this value might be null. /// If the machine does not support ptr-to-int casts, this is conservative. - pub fn scalar_may_be_null(&self, scalar: Scalar) -> bool { - match scalar.try_to_int() { + pub fn scalar_may_be_null(&self, scalar: Scalar) -> InterpResult<'tcx, bool> { + Ok(match scalar.try_to_int() { Ok(int) => int.is_null(), Err(_) => { // Can only happen during CTFE. - let ptr = self.scalar_to_ptr(scalar); + let ptr = self.scalar_to_ptr(scalar)?; match self.ptr_try_get_alloc_id(ptr) { Ok((alloc_id, offset, _)) => { let (size, _align) = self @@ -1138,7 +1146,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Err(_offset) => bug!("a non-int scalar is always a pointer"), } } - } + }) } /// Turning a "maybe pointer" into a proper pointer (and some information diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index ee1ba60829316..dfc0028e87fcc 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -342,7 +342,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, op: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, Pointer>> { - Ok(self.scalar_to_ptr(self.read_scalar(op)?.check_init()?)) + self.scalar_to_ptr(self.read_scalar(op)?.check_init()?) } // Turn the wide MPlace into a string (must already be dereferenced!) @@ -738,7 +738,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // okay. Everything else, we conservatively reject. let ptr_valid = niche_start == 0 && variants_start == variants_end - && !self.scalar_may_be_null(tag_val); + && !self.scalar_may_be_null(tag_val)?; if !ptr_valid { throw_ub!(InvalidTag(dbg_val)) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 5f7f52ef9e9f4..51d47af2f8e24 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -281,7 +281,7 @@ where }; let mplace = MemPlace { - ptr: self.scalar_to_ptr(ptr.check_init()?), + ptr: self.scalar_to_ptr(ptr.check_init()?)?, // We could use the run-time alignment here. For now, we do not, because // the point of tracking the alignment here is to make sure that the *static* // alignment information emitted with the loads is correct. The run-time @@ -1104,7 +1104,7 @@ where &self, mplace: &MPlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> { - let vtable = self.scalar_to_ptr(mplace.vtable()); // also sanity checks the type + let vtable = self.scalar_to_ptr(mplace.vtable())?; // also sanity checks the type let (instance, ty) = self.read_drop_type_from_vtable(vtable)?; let layout = self.layout_of(ty)?; diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index c2a38c6978bfb..c2664565f15cb 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -519,7 +519,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .kind(), ty::Dynamic(..) )); - let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta()); + let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?; let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; // `*mut receiver_place.layout.ty` is almost the layout that we diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 5cf3807faaa6d..235938422a893 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -50,7 +50,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let vtable_slot = self .get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? .expect("cannot be a ZST"); - let fn_ptr = self.scalar_to_ptr(vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?); + let fn_ptr = self.scalar_to_ptr(vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?)?; self.get_ptr_fn(fn_ptr) } @@ -75,7 +75,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .check_init()?; // We *need* an instance here, no other kind of function value, to be able // to determine the type. - let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn))?.as_instance()?; + let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn)?)?.as_instance()?; trace!("Found drop fn: {:?}", drop_instance); let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig); @@ -132,7 +132,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .get_ptr_alloc(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)? .expect("cannot be a ZST"); - let new_vtable = self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?); + let new_vtable = + self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?)?; Ok(new_vtable) } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 349806d997945..4a0aa41de739b 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -312,7 +312,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind() { ty::Dynamic(..) => { - let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta()); + let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?; // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. try_validation!( self.ecx.check_ptr_access_align( @@ -577,7 +577,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // If we check references recursively, also check that this points to a function. if let Some(_) = self.ref_tracking { - let ptr = self.ecx.scalar_to_ptr(value); + let ptr = self.ecx.scalar_to_ptr(value)?; let _fn = try_validation!( self.ecx.get_ptr_fn(ptr), self.path, @@ -590,7 +590,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // FIXME: Check if the signature matches } else { // Otherwise (for standalone Miri), we have to still check it to be non-null. - if self.ecx.scalar_may_be_null(value) { + if self.ecx.scalar_may_be_null(value)? { throw_validation_failure!(self.path, { "a null function pointer" }); } } @@ -667,7 +667,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // We support 2 kinds of ranges here: full range, and excluding zero. if start == 1 && end == max_value { // Only null is the niche. So make sure the ptr is NOT null. - if self.ecx.scalar_may_be_null(value) { + if self.ecx.scalar_may_be_null(value)? { throw_validation_failure!(self.path, { "a potentially null pointer" } expected { diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index fed6a608e576c..dabca2bc777da 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -15,8 +15,8 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance, - ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, UndefinedBehaviorInfo, UninitBytesAccess, - UnsupportedOpInfo, + ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, ScalarSizeMismatch, UndefinedBehaviorInfo, + UninitBytesAccess, UnsupportedOpInfo, }; use crate::ty; @@ -81,6 +81,8 @@ impl<'tcx, Tag, Extra> ConstAllocation<'tcx, Tag, Extra> { /// is added when converting to `InterpError`. #[derive(Debug)] pub enum AllocError { + /// A scalar had the wrong size. + ScalarSizeMismatch(ScalarSizeMismatch), /// Encountered a pointer where we needed raw bytes. ReadPointerAsBytes, /// Partially overwriting a pointer. @@ -90,10 +92,19 @@ pub enum AllocError { } pub type AllocResult = Result; +impl From for AllocError { + fn from(s: ScalarSizeMismatch) -> Self { + AllocError::ScalarSizeMismatch(s) + } +} + impl AllocError { pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> { use AllocError::*; match self { + ScalarSizeMismatch(s) => { + InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s)) + } ReadPointerAsBytes => InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes), PartialPointerOverwrite(offset) => InterpError::Unsupported( UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)), @@ -425,7 +436,7 @@ impl Allocation { // `to_bits_or_ptr_internal` is the right method because we just want to store this data // as-is into memory. - let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size) { + let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? { Err(val) => { let (provenance, offset) = val.into_parts(); (u128::from(offset.bytes()), Some(provenance)) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 492091a4f2540..9afe9523fcab0 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -221,6 +221,13 @@ pub struct UninitBytesAccess { pub uninit_size: Size, } +/// Information about a size mismatch. +#[derive(Debug)] +pub struct ScalarSizeMismatch { + pub target_size: u64, + pub data_size: u64, +} + /// Error information for when the program caused Undefined Behavior. pub enum UndefinedBehaviorInfo<'tcx> { /// Free-form case. Only for errors that are never caught! @@ -298,10 +305,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Working with a local that is not currently live. DeadLocal, /// Data size is not equal to target size. - ScalarSizeMismatch { - target_size: u64, - data_size: u64, - }, + ScalarSizeMismatch(ScalarSizeMismatch), /// A discriminant of an uninhabited enum variant is written. UninhabitedEnumVariantWritten, } @@ -408,7 +412,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { "using uninitialized data, but this operation requires initialized memory" ), DeadLocal => write!(f, "accessing a dead local variable"), - ScalarSizeMismatch { target_size, data_size } => write!( + ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!( f, "scalar size mismatch: expected {} bytes but got {} bytes instead", target_size, data_size diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index bce962491b7b1..d8cba39c6d97b 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -120,7 +120,8 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, - ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, + ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, + UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 8e32603a35702..9cffdf2993ed5 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -12,6 +12,7 @@ use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt}; use super::{ AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance, + ScalarSizeMismatch, }; /// Represents the result of const evaluation via the `eval_to_allocation` query. @@ -300,16 +301,29 @@ impl Scalar { /// /// This method only exists for the benefit of low-level operations that truly need to treat the /// scalar in whatever form it is. + /// + /// This throws UB (instead of ICEing) on a size mismatch since size mismatches can arise in + /// Miri when someone declares a function that we shim (such as `malloc`) with a wrong type. #[inline] - pub fn to_bits_or_ptr_internal(self, target_size: Size) -> Result> { + pub fn to_bits_or_ptr_internal( + self, + target_size: Size, + ) -> Result>, ScalarSizeMismatch> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); - match self { - Scalar::Int(int) => Ok(int.assert_bits(target_size)), + Ok(match self { + Scalar::Int(int) => Ok(int.to_bits(target_size).map_err(|size| { + ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes() } + })?), Scalar::Ptr(ptr, sz) => { - assert_eq!(target_size.bytes(), u64::from(sz)); + if target_size.bytes() != sz.into() { + return Err(ScalarSizeMismatch { + target_size: target_size.bytes(), + data_size: sz.into(), + }); + } Err(ptr) } - } + }) } } @@ -348,10 +362,10 @@ impl<'tcx, Tag: Provenance> Scalar { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsBytes))?.to_bits(target_size).map_err( |size| { - err_ub!(ScalarSizeMismatch { + err_ub!(ScalarSizeMismatch(ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes(), - }) + })) .into() }, ) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 1fadd0c26fc49..bb3ba3e596d14 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -146,7 +146,7 @@ impl IntRange { // straight to the result, after doing a bit of checking. (We // could remove this branch and just fall through, which // is more general but much slower.) - if let Ok(bits) = scalar.to_bits_or_ptr_internal(target_size) { + if let Ok(bits) = scalar.to_bits_or_ptr_internal(target_size).unwrap() { return Some(bits); } } From aa3c141c86652ce72cca6d32c69afbdc23ee51fa Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 7 Apr 2022 13:44:57 -0700 Subject: [PATCH 7/7] reword panic vs result section to remove recoverable vs unrecoverable framing --- library/core/src/macros/panic.md | 34 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md index d8206e7893114..98fb7e9e41d7a 100644 --- a/library/core/src/macros/panic.md +++ b/library/core/src/macros/panic.md @@ -24,20 +24,30 @@ See also the macro [`compile_error!`], for raising errors during compilation. # When to use `panic!` vs `Result` -The Rust model of error handling groups errors into two major categories: -recoverable and unrecoverable errors. For a recoverable error, such as a file -not found error, it’s reasonable to report the problem to the user and retry -the operation. Unrecoverable errors are always symptoms of bugs, like trying to -access a location beyond the end of an array. +The Rust language provides two complementary systems for constructing / +representing, reporting, propagating, reacting to, and discarding errors. These +responsibilities are collectively known as "error handling." `panic!` and +`Result` are similar in that they are each the primary interface of their +respective error handling systems; however, the meaning these interfaces attach +to their errors and the responsibilities they fulfill within their respective +error handling systems differ. -The Rust language and standard library provides `Result` and `panic!` as parts -of two complementary systems for representing, reporting, propagating, reacting -to, and discarding errors for in these two categories. +The `panic!` macro is used to construct errors that represent a bug that has +been detected in your program. With `panic!` you provide a message that +describes the bug and the language then constructs an error with that message, +reports it, and propagates it for you. -The `panic!` macro is provided to represent unrecoverable errors, whereas the -`Result` enum is provided to represent recoverable errors. For more detailed -information about error handling check out the [book] or the [`std::result`] -module docs. +`Result` on the other hand is used to wrap other types that represent either +the successful result of some computation, `Ok(T)`, or error types that +represent an anticipated runtime failure mode of that computation, `Err(E)`. +`Result` is used alongside user defined types which represent the various +anticipated runtime failure modes that the associated computation could +encounter. `Result` must be propagated manually, often with the the help of the +`?` operator and `Try` trait, and they must be reported manually, often with +the help of the `Error` trait. + +For more detailed information about error handling check out the [book] or the +[`std::result`] module docs. [ounwrap]: Option::unwrap [runwrap]: Result::unwrap