From 28db5214d2c48e7a58cf79b9e272097260910a33 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Wed, 2 Sep 2020 23:25:09 +0200 Subject: [PATCH 01/27] More implementations of Write for immutable refs Fixes #73836 --- library/std/src/io/stdio.rs | 54 +++++++++++++++++++++++++++++++++++++ library/std/src/io/util.rs | 24 +++++++++++++++++ library/std/src/process.rs | 19 +++++++++++++ 3 files changed, 97 insertions(+) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 3943c66aad53a..f320cf907c365 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -606,6 +606,33 @@ impl Write for Stdout { self.lock().write_fmt(args) } } + +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.lock().write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.lock().write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.lock().is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { + self.lock().flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.lock().write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.lock().write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + self.lock().write_fmt(args) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StdoutLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -782,6 +809,33 @@ impl Write for Stderr { self.lock().write_fmt(args) } } + +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.lock().write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.lock().write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.lock().is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { + self.lock().flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.lock().write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.lock().write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + self.lock().write_fmt(args) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StderrLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index a093b745b0c13..ce4dd1dcd493d 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -248,6 +248,30 @@ impl Write for Sink { } } +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Sink { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Sink { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c42bc1096528b..36521fdaec00f 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -262,6 +262,25 @@ impl Write for ChildStdin { } } +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &ChildStdin { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + impl AsInner for ChildStdin { fn as_inner(&self) -> &AnonPipe { &self.inner From ec7f9b927f1896c7f29c602d6b0f961c891d0941 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Fri, 11 Sep 2020 11:11:34 +0200 Subject: [PATCH 02/27] Deduplicates io::Write implementations --- library/std/src/io/stdio.rs | 28 ++++++++++++++-------------- library/std/src/process.rs | 8 ++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index f320cf907c365..cccc0aadf9989 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -584,26 +584,26 @@ impl fmt::Debug for Stdout { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.lock().write_vectored(bufs) + (&*self).write_vectored(bufs) } #[inline] fn is_write_vectored(&self) -> bool { - self.lock().is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - self.lock().flush() + (&*self).flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) + (&*self).write_all(buf) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.lock().write_all_vectored(bufs) + (&*self).write_all_vectored(bufs) } fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - self.lock().write_fmt(args) + (&*self).write_fmt(args) } } @@ -787,26 +787,26 @@ impl fmt::Debug for Stderr { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.lock().write_vectored(bufs) + (&*self).write_vectored(bufs) } #[inline] fn is_write_vectored(&self) -> bool { - self.lock().is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - self.lock().flush() + (&*self).flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) + (&*self).write_all(buf) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.lock().write_all_vectored(bufs) + (&*self).write_all_vectored(bufs) } fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - self.lock().write_fmt(args) + (&*self).write_fmt(args) } } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 36521fdaec00f..d620a720be3ab 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -246,19 +246,19 @@ pub struct ChildStdin { #[stable(feature = "process", since = "1.0.0")] impl Write for ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.inner.write_vectored(bufs) + (&*self).write_vectored(bufs) } fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - Ok(()) + (&*self).flush() } } From 8f27e3cb1b4140d9124d60df0850ef734e73b884 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 13 Sep 2020 01:55:34 +0200 Subject: [PATCH 03/27] Make some methods of `Pin` unstable const Make the following methods unstable const under the `const_pin` feature: - `new` - `new_unchecked` - `into_inner` - `into_inner_unchecked` - `get_ref` - `into_ref` Also adds tests for these methods in a const context. Tracking issue: #76654 --- library/core/src/lib.rs | 1 + library/core/src/pin.rs | 27 ++++++++++++++++----------- library/core/tests/lib.rs | 2 ++ library/core/tests/pin.rs | 21 +++++++++++++++++++++ 4 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 library/core/tests/pin.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c3cadcbb01e31..696b6a64a9fec 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -80,6 +80,7 @@ #![feature(const_int_pow)] #![feature(constctlz)] #![feature(const_panic)] +#![feature(const_pin)] #![feature(const_fn_union)] #![feature(const_generics)] #![feature(const_option)] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 1cc1dfb014335..fa5b37edc36e6 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -471,9 +471,10 @@ impl> Pin

{ /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn new(pointer: P) -> Pin

{ + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn new(pointer: P) -> Pin

{ // SAFETY: the value pointed to is `Unpin`, and so has no requirements // around pinning. unsafe { Pin::new_unchecked(pointer) } @@ -483,9 +484,10 @@ impl> Pin

{ /// /// This requires that the data inside this `Pin` is [`Unpin`] so that we /// can ignore the pinning invariants when unwrapping it. - #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] - pub fn into_inner(pin: Pin

) -> P { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const fn into_inner(pin: Pin

) -> P { pin.pointer } } @@ -556,9 +558,10 @@ impl Pin

{ /// /// [`mem::swap`]: crate::mem::swap #[lang = "new_unchecked"] - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn new_unchecked(pointer: P) -> Pin

{ + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const unsafe fn new_unchecked(pointer: P) -> Pin

{ Pin { pointer } } @@ -589,9 +592,10 @@ impl Pin

{ /// /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. - #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] - pub unsafe fn into_inner_unchecked(pin: Pin

) -> P { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const unsafe fn into_inner_unchecked(pin: Pin

) -> P { pin.pointer } } @@ -693,17 +697,18 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// with the same lifetime as the original `Pin`. /// /// ["pinning projections"]: self#projections-and-structural-pinning - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_ref(self) -> &'a T { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn get_ref(self) -> &'a T { self.pointer } } impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] + #[stable(feature = "pin", since = "1.33.0")] pub fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a2e294ace1860..b8d67d7266543 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -39,6 +39,7 @@ #![feature(iter_order_by)] #![feature(cmp_min_max_by)] #![feature(iter_map_while)] +#![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] #![feature(never_type)] @@ -74,6 +75,7 @@ mod num; mod ops; mod option; mod pattern; +mod pin; mod ptr; mod result; mod slice; diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs new file mode 100644 index 0000000000000..1363353163829 --- /dev/null +++ b/library/core/tests/pin.rs @@ -0,0 +1,21 @@ +use core::pin::Pin; + +#[test] +fn pin_const() { + // test that the methods of `Pin` are usable in a const context + + const POINTER: &'static usize = &2; + + const PINNED: Pin<&'static usize> = Pin::new(POINTER); + const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) }; + assert_eq!(PINNED_UNCHECKED, PINNED); + + const INNER: &'static usize = Pin::into_inner(PINNED); + assert_eq!(INNER, POINTER); + + const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) }; + assert_eq!(INNER_UNCHECKED, POINTER); + + const REF: &'static usize = PINNED.get_ref(); + assert_eq!(REF, POINTER) +} From e5447a22222ecc6a650e75282cb9931b910854b2 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 13 Sep 2020 10:47:20 +0200 Subject: [PATCH 04/27] Fix #76432 Only insert StorageDeads if we actually removed one. Fixes an issue where we added StorageDead to a place with no StorageLive --- .../transform/simplify_comparison_integral.rs | 43 +++---- src/test/mir-opt/issue_76432.rs | 16 +++ ...76432.test.SimplifyComparisonIntegral.diff | 116 ++++++++++++++++++ 3 files changed, 154 insertions(+), 21 deletions(-) create mode 100644 src/test/mir-opt/issue_76432.rs create mode 100644 src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index a450a75d091ef..9b460c9ecb1be 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -61,26 +61,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { _ => unreachable!(), } - let terminator = bb.terminator_mut(); - - // add StorageDead for the place switched on at the top of each target - for bb_idx in new_targets.iter() { - storage_deads_to_insert.push(( - *bb_idx, - Statement { - source_info: terminator.source_info, - kind: StatementKind::StorageDead(opt.to_switch_on.local), - }, - )); - } - - terminator.kind = TerminatorKind::SwitchInt { - discr: Operand::Move(opt.to_switch_on), - switch_ty: opt.branch_value_ty, - values: vec![new_value].into(), - targets: new_targets, - }; - // delete comparison statement if it the value being switched on was moved, which means it can not be user later on if opt.can_remove_bin_op_stmt { bb.statements[opt.bin_op_stmt_idx].make_nop(); @@ -106,14 +86,35 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { } } + let terminator = bb.terminator(); + // remove StorageDead (if it exists) being used in the assign of the comparison for (stmt_idx, stmt) in bb.statements.iter().enumerate() { if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local) { continue; } - storage_deads_to_remove.push((stmt_idx, opt.bb_idx)) + storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); + // if we have StorageDeads to remove then make sure to insert them at the top of each target + for bb_idx in new_targets.iter() { + storage_deads_to_insert.push(( + *bb_idx, + Statement { + source_info: terminator.source_info, + kind: StatementKind::StorageDead(opt.to_switch_on.local), + }, + )); + } } + + let terminator = bb.terminator_mut(); + + terminator.kind = TerminatorKind::SwitchInt { + discr: Operand::Move(opt.to_switch_on), + switch_ty: opt.branch_value_ty, + values: vec![new_value].into(), + targets: new_targets, + }; } for (idx, bb_idx) in storage_deads_to_remove { diff --git a/src/test/mir-opt/issue_76432.rs b/src/test/mir-opt/issue_76432.rs new file mode 100644 index 0000000000000..c8b405ca8eaaf --- /dev/null +++ b/src/test/mir-opt/issue_76432.rs @@ -0,0 +1,16 @@ +// Check that we do not insert StorageDead at each target if StorageDead was never seen + +// EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff +use std::fmt::Debug; + +fn test(x: T) { + let v: &[T] = &[x, x, x]; + match v { + [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], + _ => unreachable!(), + }; +} + +fn main() { + test(0u32); +} diff --git a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000000..499134b69919f --- /dev/null +++ b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -0,0 +1,116 @@ +- // MIR for `test` before SimplifyComparisonIntegral ++ // MIR for `test` after SimplifyComparisonIntegral + + fn test(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/issue_76432.rs:6:38: 6:39 + let mut _0: (); // return place in scope 0 at $DIR/issue_76432.rs:6:44: 6:44 + let _2: &[T]; // in scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + let mut _3: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _4: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _5: [T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + let mut _6: T; // in scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + let mut _7: T; // in scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + let mut _8: T; // in scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + let _9: [*const T; 3]; // in scope 0 at $DIR/issue_76432.rs:8:5: 11:6 + let mut _10: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _11: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _12: bool; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _16: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _17: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _18: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + let mut _19: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 + let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 + let mut _22: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + scope 1 { + debug v => _2; // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10 + let _13: &T; // in scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + let _14: &T; // in scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + let _15: &T; // in scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + scope 2 { + debug v1 => _13; // in scope 2 at $DIR/issue_76432.rs:9:10: 9:16 + debug v2 => _14; // in scope 2 at $DIR/issue_76432.rs:9:18: 9:24 + debug v3 => _15; // in scope 2 at $DIR/issue_76432.rs:9:26: 9:32 + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + _6 = _1; // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + _7 = _1; // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _8 = _1; // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + _4 = &_5; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _3 = _4; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:7:29: 7:30 + StorageLive(_9); // scope 1 at $DIR/issue_76432.rs:8:5: 11:6 + _10 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _11 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 +- _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 +- switchInt(move _12) -> [false: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 ++ nop; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 ++ switchInt(move _10) -> [3_usize: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + } + + bb1: { + StorageLive(_22); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } + // ty::Const + // + ty: &str + // + val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) } + } + + bb2: { + StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + _13 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + _14 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + StorageLive(_15); // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + _15 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + StorageLive(_16); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_17); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + _17 = &raw const (*_13); // scope 2 at $DIR/issue_76432.rs:9:38: 9:40 + _16 = _17; // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_18); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_19); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + _19 = &raw const (*_14); // scope 2 at $DIR/issue_76432.rs:9:54: 9:56 + _18 = _19; // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_20); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + StorageLive(_21); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _21 = &raw const (*_15); // scope 2 at $DIR/issue_76432.rs:9:70: 9:72 + _20 = _21; // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:9:37: 9:85 + StorageDead(_21); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_20); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_19); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_18); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_17); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_16); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_15); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_14); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_13); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_9); // scope 1 at $DIR/issue_76432.rs:11:6: 11:7 + _0 = const (); // scope 0 at $DIR/issue_76432.rs:6:44: 12:2 + StorageDead(_5); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + StorageDead(_2); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + return; // scope 0 at $DIR/issue_76432.rs:12:2: 12:2 + } + } + From eede953c283c7bbe903a0e8abb44c923baf5cfac Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 10 Sep 2020 03:10:36 +0000 Subject: [PATCH 05/27] Only get ImplKind::Impl once --- src/librustdoc/clean/inline.rs | 41 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f8987c6beca33..931355b82f503 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -350,14 +350,22 @@ pub fn build_impl( } } - let for_ = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx), - _ => panic!("did given to build_impl was not an impl"), + let impl_item = match did.as_local() { + Some(did) => { + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + match tcx.hir().expect_item(hir_id).kind { + hir::ItemKind::Impl { self_ty, ref generics, ref items, .. } => { + Some((self_ty, generics, items)) + } + _ => panic!("`DefID` passed to `build_impl` is not an `impl"), + } } - } else { - tcx.type_of(did).clean(cx) + None => None, + }; + + let for_ = match impl_item { + Some((self_ty, _, _)) => self_ty.clean(cx), + None => tcx.type_of(did).clean(cx), }; // Only inline impl if the implementing type is @@ -377,17 +385,12 @@ pub fn build_impl( } let predicates = tcx.explicit_predicates_of(did); - let (trait_items, generics) = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { ref generics, ref items, .. } => ( - items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), - generics.clean(cx), - ), - _ => panic!("did given to build_impl was not an impl"), - } - } else { - ( + let (trait_items, generics) = match impl_item { + Some((_, generics, items)) => ( + items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), + generics.clean(cx), + ), + None => ( tcx.associated_items(did) .in_definition_order() .filter_map(|item| { @@ -399,7 +402,7 @@ pub fn build_impl( }) .collect::>(), clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)), - ) + ), }; let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| match bound { From 7e24136996fd412ba2890952d5f0ddffb3cb7370 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 16 Sep 2020 10:29:31 -0400 Subject: [PATCH 06/27] Pass --target to lint docs Otherwise, we may not have a standard library built for the native "host" target of the rustc being run. --- src/bootstrap/doc.rs | 4 +++- src/tools/lint-docs/src/groups.rs | 8 ++++---- src/tools/lint-docs/src/lib.rs | 25 ++++++++++++++++--------- src/tools/lint-docs/src/main.rs | 15 ++++++++++++++- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f90e76a4f4ea6..cf9211bc7ea86 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -752,6 +752,7 @@ impl Step for RustcBook { let out_listing = out_base.join("src/lints"); builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base); builder.info(&format!("Generating lint docs ({})", self.target)); + let rustc = builder.rustc(self.compiler); // The tool runs `rustc` for extracting output examples, so it needs a // functional sysroot. @@ -762,7 +763,8 @@ impl Step for RustcBook { cmd.arg("--out"); cmd.arg(&out_listing); cmd.arg("--rustc"); - cmd.arg(rustc); + cmd.arg(&rustc); + cmd.arg("--rustc-target").arg(&self.target.rustc_target_arg()); if builder.config.verbose() { cmd.arg("--verbose"); } diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index a212459bb4dc6..6b32ebdc284f4 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -18,10 +18,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ /// Updates the documentation of lint groups. pub(crate) fn generate_group_docs( lints: &[Lint], - rustc_path: &Path, + rustc: crate::Rustc<'_>, out_path: &Path, ) -> Result<(), Box> { - let groups = collect_groups(rustc_path)?; + let groups = collect_groups(rustc)?; let groups_path = out_path.join("groups.md"); let contents = fs::read_to_string(&groups_path) .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; @@ -36,9 +36,9 @@ pub(crate) fn generate_group_docs( type LintGroups = BTreeMap>; /// Collects the group names from rustc. -fn collect_groups(rustc: &Path) -> Result> { +fn collect_groups(rustc: crate::Rustc<'_>) -> Result> { let mut result = BTreeMap::new(); - let mut cmd = Command::new(rustc); + let mut cmd = Command::new(rustc.path); cmd.arg("-Whelp"); let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; if !output.status.success() { diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 92b3d186fa141..6ca71dcaf3cd0 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -45,16 +45,22 @@ impl Level { } } +#[derive(Copy, Clone)] +pub struct Rustc<'a> { + pub path: &'a Path, + pub target: &'a str, +} + /// Collects all lints, and writes the markdown documentation at the given directory. pub fn extract_lint_docs( src_path: &Path, out_path: &Path, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { let mut lints = gather_lints(src_path)?; for lint in &mut lints { - generate_output_example(lint, rustc_path, verbose).map_err(|e| { + generate_output_example(lint, rustc, verbose).map_err(|e| { format!( "failed to test example in lint docs for `{}` in {}:{}: {}", lint.name, @@ -65,7 +71,7 @@ pub fn extract_lint_docs( })?; } save_lints_markdown(&lints, &out_path.join("listing"))?; - groups::generate_group_docs(&lints, rustc_path, out_path)?; + groups::generate_group_docs(&lints, rustc, out_path)?; Ok(()) } @@ -208,7 +214,7 @@ fn lint_name(line: &str) -> Result { /// actual output from the compiler. fn generate_output_example( lint: &mut Lint, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { // Explicit list of lints that are allowed to not have an example. Please @@ -230,7 +236,7 @@ fn generate_output_example( // separate test suite, and use an include mechanism such as mdbook's // `{{#rustdoc_include}}`. if !lint.is_ignored() { - replace_produces(lint, rustc_path, verbose)?; + replace_produces(lint, rustc, verbose)?; } Ok(()) } @@ -261,7 +267,7 @@ fn check_style(lint: &Lint) -> Result<(), Box> { /// output from the compiler. fn replace_produces( lint: &mut Lint, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { let mut lines = lint.doc.iter_mut(); @@ -302,7 +308,7 @@ fn replace_produces( Some(line) if line.is_empty() => {} Some(line) if line == "{{produces}}" => { let output = - generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?; + generate_lint_output(&lint.name, &example, &options, rustc, verbose)?; line.replace_range( .., &format!( @@ -329,7 +335,7 @@ fn generate_lint_output( name: &str, example: &[&mut String], options: &[&str], - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result> { if verbose { @@ -364,13 +370,14 @@ fn generate_lint_output( } fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; - let mut cmd = Command::new(rustc_path); + let mut cmd = Command::new(rustc.path); if options.contains(&"edition2015") { cmd.arg("--edition=2015"); } else { cmd.arg("--edition=2018"); } cmd.arg("--error-format=json"); + cmd.arg("--target").arg(rustc.target); if options.contains(&"test") { cmd.arg("--test"); } diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 45d97bd431791..5db49007d375c 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -13,6 +13,7 @@ fn doit() -> Result<(), Box> { let mut src_path = None; let mut out_path = None; let mut rustc_path = None; + let mut rustc_target = None; let mut verbose = false; while let Some(arg) = args.next() { match arg.as_str() { @@ -34,6 +35,12 @@ fn doit() -> Result<(), Box> { None => return Err("--rustc requires a value".into()), }; } + "--rustc-target" => { + rustc_target = match args.next() { + Some(s) => Some(s), + None => return Err("--rustc-target requires a value".into()), + }; + } "-v" | "--verbose" => verbose = true, s => return Err(format!("unexpected argument `{}`", s).into()), } @@ -47,10 +54,16 @@ fn doit() -> Result<(), Box> { if rustc_path.is_none() { return Err("--rustc must be specified to the path of rustc".into()); } + if rustc_target.is_none() { + return Err("--rustc-target must be specified to the rustc target".into()); + } lint_docs::extract_lint_docs( &src_path.unwrap(), &out_path.unwrap(), - &rustc_path.unwrap(), + lint_docs::Rustc { + path: rustc_path.as_deref().unwrap(), + target: rustc_target.as_deref().unwrap(), + }, verbose, ) } From bd4e0af0b54afc91903c282740e25ee6135224c8 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 16 Sep 2020 12:47:26 -0400 Subject: [PATCH 07/27] Build rustdoc for cross-compiled targets This isn't an issue for most folks who use x.py dist, which will directly depend on this. But for x.py build, if we don't properly set target here rustdoc will not be built. Currently, there is not a default-on step for generating a rustc for a given target either, so we will fail to build a rustc as well. --- src/bootstrap/tool.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 99e33e3b006fe..d2346e40e51d2 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -471,7 +471,11 @@ impl Step for Rustdoc { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustdoc { - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + // Note: this is somewhat unique in that we actually want a *target* + // compiler here, because rustdoc *is* a compiler. We won't be using + // this as the compiler to build with, but rather this is "what + // compiler are we producing"? + compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } From 363aff0a9d0b85285b7501cb04dd8263d29d273a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 17 Sep 2020 16:03:42 -0400 Subject: [PATCH 08/27] Add test for x.py build cross-compilation --- src/bootstrap/builder/tests.rs | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index f96925f927086..77b39cbb87ed9 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -90,6 +90,54 @@ mod defaults { assert!(builder.cache.all::().is_empty()); } + #[test] + fn build_cross_compile() { + let config = Config { stage: 1, ..configure("build", &["B"], &["B"]) }; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + + // Ideally, this build wouldn't actually have `target: a` + // rustdoc/rustcc/std here (the user only requested a host=B build, so + // there's not really a need for us to build for target A in this case + // (since we're producing stage 1 libraries/binaries). But currently + // rustbuild is just a bit buggy here; this should be fixed though. + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, + compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, + tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, + ], + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b }, + ] + ); + } + #[test] fn doc_default() { let mut config = configure("doc", &[], &[]); From e3c6e46168758642f0bab64da374f93ed21b1cd0 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 18 Sep 2020 19:23:50 +0200 Subject: [PATCH 09/27] Make some methods of `Pin<&mut T>` unstable const Make the following methods unstable const under the `const_pin` feature: - `into_ref` - `get_mut` - `get_unchecked_mut` --- library/core/src/pin.rs | 13 ++++++++----- library/core/tests/lib.rs | 1 + library/core/tests/pin.rs | 12 +++++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index fa5b37edc36e6..9f0284d5d9542 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -708,8 +708,9 @@ impl<'a, T: ?Sized> Pin<&'a T> { impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. #[inline(always)] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] - pub fn into_ref(self) -> Pin<&'a T> { + pub const fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } @@ -722,9 +723,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_mut(self) -> &'a mut T + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn get_mut(self) -> &'a mut T where T: Unpin, { @@ -741,9 +743,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// If the underlying data is `Unpin`, `Pin::get_mut` should be used /// instead. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self) -> &'a mut T { + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { self.pointer } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index b8d67d7266543..490f016ab8b2e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -39,6 +39,7 @@ #![feature(iter_order_by)] #![feature(cmp_min_max_by)] #![feature(iter_map_while)] +#![feature(const_mut_refs)] #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs index 1363353163829..6f617c8d0c297 100644 --- a/library/core/tests/pin.rs +++ b/library/core/tests/pin.rs @@ -17,5 +17,15 @@ fn pin_const() { assert_eq!(INNER_UNCHECKED, POINTER); const REF: &'static usize = PINNED.get_ref(); - assert_eq!(REF, POINTER) + assert_eq!(REF, POINTER); + + // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context. + // A const fn is used because `&mut` is not (yet) usable in constants. + const fn pin_mut_const() { + let _ = Pin::new(&mut 2).into_ref(); + let _ = Pin::new(&mut 2).get_mut(); + let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() }; + } + + pin_mut_const(); } From 2a00dda90258576e3adf5ecae0437a8fe6fadbcf Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 10 Sep 2020 19:43:53 +0200 Subject: [PATCH 10/27] miri: correctly deal with `ConstKind::Bound` --- compiler/rustc_mir/src/interpret/operand.rs | 6 ++-- .../ui/const-generics/issues/issue-73260.rs | 20 +++++++++++++ .../const-generics/issues/issue-73260.stderr | 29 +++++++++++++++++++ .../ui/const-generics/issues/issue-74634.rs | 27 +++++++++++++++++ .../const-generics/issues/issue-74634.stderr | 10 +++++++ 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-73260.rs create mode 100644 src/test/ui/const-generics/issues/issue-73260.stderr create mode 100644 src/test/ui/const-generics/issues/issue-74634.rs create mode 100644 src/test/ui/const-generics/issues/issue-74634.stderr diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 57245696e576e..136a2699d20b2 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -549,7 +549,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Early-return cases. let val_val = match val.val { - ty::ConstKind::Param(_) => throw_inval!(TooGeneric), + ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { let instance = self.resolve(def.did, substs)?; @@ -561,9 +561,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // happening. return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); } - ty::ConstKind::Infer(..) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(..) => { + ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) } ty::ConstKind::Value(val_val) => val_val, diff --git a/src/test/ui/const-generics/issues/issue-73260.rs b/src/test/ui/const-generics/issues/issue-73260.rs new file mode 100644 index 0000000000000..351d6849af5db --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zsave-analysis + +#![feature(const_generics)] +#![allow(incomplete_features)] +struct Arr +where Assert::<{N < usize::max_value() / 2}>: IsTrue, //~ ERROR constant expression +{ +} + +enum Assert {} + +trait IsTrue {} + +impl IsTrue for Assert {} + +fn main() { + let x: Arr<{usize::max_value()}> = Arr {}; + //~^ ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/const-generics/issues/issue-73260.stderr b/src/test/ui/const-generics/issues/issue-73260.stderr new file mode 100644 index 0000000000000..e22612ed5ea63 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.stderr @@ -0,0 +1,29 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-73260.rs:6:47 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:12 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:40 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-74634.rs b/src/test/ui/const-generics/issues/issue-74634.rs new file mode 100644 index 0000000000000..0f23fa92c3679 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.rs @@ -0,0 +1,27 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait If {} +impl If for () {} + +trait IsZero { + type Answer; +} + +struct True; +struct False; + +impl IsZero for () +where (): If<{N == 0}> { //~ERROR constant expression + type Answer = True; +} + +trait Foobar {} + +impl Foobar for () +where (): IsZero {} + +impl Foobar for () +where (): IsZero {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74634.stderr b/src/test/ui/const-generics/issues/issue-74634.stderr new file mode 100644 index 0000000000000..091a1ac7b9981 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-74634.rs:15:11 + | +LL | where (): If<{N == 0}> { + | ^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + From 67342304253d8af47fe4453fbe2396b627620431 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 18:39:26 +0200 Subject: [PATCH 11/27] do not ICE on `ty::Bound` in Layout::compute --- compiler/rustc_middle/src/ty/layout.rs | 4 ++-- .../ui/const-generics/issues/issue-76595.rs | 18 ++++++++++++++++ .../const-generics/issues/issue-76595.stderr | 21 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-76595.rs create mode 100644 src/test/ui/const-generics/issues/issue-76595.stderr diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b0a1413a9d62f..cb79b089d94a0 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1259,11 +1259,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.layout_raw(param_env.and(normalized))? } - ty::Bound(..) | ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { bug!("Layout::compute: unexpected type `{}`", ty) } - ty::Param(_) | ty::Error(_) => { + ty::Bound(..) | ty::Param(_) | ty::Error(_) => { return Err(LayoutError::Unknown(ty)); } }) diff --git a/src/test/ui/const-generics/issues/issue-76595.rs b/src/test/ui/const-generics/issues/issue-76595.rs new file mode 100644 index 0000000000000..0a16ca181f557 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.rs @@ -0,0 +1,18 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Bool; + +trait True {} + +impl True for Bool {} + +fn test() where Bool<{core::mem::size_of::() > 4}>: True { + todo!() +} + +fn main() { + test::<2>(); + //~^ ERROR wrong number of type + //~| ERROR constant expression depends +} diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr new file mode 100644 index 0000000000000..4235bdc9b893c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -0,0 +1,21 @@ +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/issue-76595.rs:15:5 + | +LL | test::<2>(); + | ^^^^^^^^^ expected 1 type argument + +error: constant expression depends on a generic parameter + --> $DIR/issue-76595.rs:15:5 + | +LL | fn test() where Bool<{core::mem::size_of::() > 4}>: True { + | ---- required by a bound in this +... +LL | test::<2>(); + | ^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + = note: required by this bound in `test` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. From 65b3419ca04fdf921309e7fc03010d9d2cc9b8f0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 20 Sep 2020 09:32:59 +0200 Subject: [PATCH 12/27] update stderr file --- src/test/ui/const-generics/issues/issue-76595.stderr | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr index 4235bdc9b893c..2e457595393ca 100644 --- a/src/test/ui/const-generics/issues/issue-76595.stderr +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -8,13 +8,12 @@ error: constant expression depends on a generic parameter --> $DIR/issue-76595.rs:15:5 | LL | fn test() where Bool<{core::mem::size_of::() > 4}>: True { - | ---- required by a bound in this + | ---- required by this bound in `test` ... LL | test::<2>(); | ^^^^^^^^^ | = note: this may fail depending on what value the parameter takes - = note: required by this bound in `test` error: aborting due to 2 previous errors From c690c82ad42a15417996a087ef072fd2d8c2fe3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 18 Sep 2020 18:33:37 +0200 Subject: [PATCH 13/27] use if let instead of single match arm expressions to compact code and reduce nesting (clippy::single_match) --- .../nice_region_error/static_impl_trait.rs | 18 ++++++++---------- compiler/rustc_middle/src/ty/error.rs | 11 ++++------- compiler/rustc_middle/src/ty/print/pretty.rs | 9 +-------- .../rustc_mir/src/transform/promote_consts.rs | 16 +++++----------- compiler/rustc_parse/src/lexer/tokentrees.rs | 9 +++------ compiler/rustc_parse_format/src/lib.rs | 9 +++------ compiler/rustc_resolve/src/lib.rs | 7 ++----- compiler/rustc_symbol_mangling/src/v0.rs | 7 ++----- 8 files changed, 28 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 975b9d4f08631..441cfeea20a48 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -488,18 +488,16 @@ impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor { } fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { - match t.kind { - TyKind::TraitObject( - poly_trait_refs, - Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, - ) => { - for ptr in poly_trait_refs { - if Some(self.1) == ptr.trait_ref.trait_def_id() { - self.0.push(ptr.span); - } + if let TyKind::TraitObject( + poly_trait_refs, + Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) = t.kind + { + for ptr in poly_trait_refs { + if Some(self.1) == ptr.trait_ref.trait_def_id() { + self.0.push(ptr.span); } } - _ => {} } walk_ty(self, t); } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 7226a906e5c97..2a950dcdf23fe 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -832,14 +832,11 @@ fn foo(&self) -> Self::T { String::new() } kind: hir::ItemKind::Impl { items, .. }, .. })) => { for item in &items[..] { - match item.kind { - hir::AssocItemKind::Type => { - if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { - db.span_label(item.span, "expected this associated type"); - return true; - } + if let hir::AssocItemKind::Type = item.kind { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { + db.span_label(item.span, "expected this associated type"); + return true; } - _ => {} } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f0bae48cc1221..c9cc9bfc9fa26 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2125,17 +2125,10 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N // Iterate all local crate items no matter where they are defined. let hir = tcx.hir(); for item in hir.krate().items.values() { - if item.ident.name.as_str().is_empty() { + if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) { continue; } - match item.kind { - ItemKind::Use(_, _) => { - continue; - } - _ => {} - } - if let Some(local_def_id) = hir.definitions().opt_hir_id_to_local_def_id(item.hir_id) { let def_id = local_def_id.to_def_id(); let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS); diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 37202276161c7..7510c43243b1d 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -242,11 +242,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } TerminatorKind::InlineAsm { ref operands, .. } => { for (index, op) in operands.iter().enumerate() { - match op { - InlineAsmOperand::Const { .. } => { - self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) - } - _ => {} + if let InlineAsmOperand::Const { .. } = op { + self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) } } } @@ -612,12 +609,9 @@ impl<'tcx> Validator<'_, 'tcx> { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - match (cast_in, cast_out) { - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - // ptr-to-int casts are not possible in consts and thus not promotable - return Err(Unpromotable); - } - _ => {} + if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + // ptr-to-int casts are not possible in consts and thus not promotable + return Err(Unpromotable); } } diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 0f364bffb134e..6233549dc8579 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -149,12 +149,9 @@ impl<'a> TokenTreesReader<'a> { } } - match (open_brace, delim) { - //only add braces - (DelimToken::Brace, DelimToken::Brace) => { - self.matching_block_spans.push((open_brace_span, close_brace_span)); - } - _ => {} + //only add braces + if let (DelimToken::Brace, DelimToken::Brace) = (open_brace, delim) { + self.matching_block_spans.push((open_brace_span, close_brace_span)); } if self.open_braces.is_empty() { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e07b8b86aef8e..556bf69c9315e 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -527,12 +527,9 @@ impl<'a> Parser<'a> { // fill character if let Some(&(_, c)) = self.cur.peek() { - match self.cur.clone().nth(1) { - Some((_, '>' | '<' | '^')) => { - spec.fill = Some(c); - self.cur.next(); - } - _ => {} + if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) { + spec.fill = Some(c); + self.cur.next(); } } // Alignment diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 85ddc5f55d110..677cf27cde71c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -534,11 +534,8 @@ impl<'a> ModuleData<'a> { if ns != TypeNS { return; } - match binding.res() { - Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { - collected_traits.push((name, binding)) - } - _ => (), + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { + collected_traits.push((name, binding)) } }); *traits = Some(collected_traits.into_boxed_slice()); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 619edf06aa6e6..091d488138e46 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -152,11 +152,8 @@ impl SymbolMangler<'tcx> { let _ = write!(self.out, "{}", ident.len()); // Write a separating `_` if necessary (leading digit or `_`). - match ident.chars().next() { - Some('_' | '0'..='9') => { - self.push("_"); - } - _ => {} + if let Some('_' | '0'..='9') = ident.chars().next() { + self.push("_"); } self.push(ident); From 88a29e630c1ce05fa28ec927e26cbf8a19d6efc4 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Mon, 21 Sep 2020 08:52:59 +0200 Subject: [PATCH 14/27] Updates stability attributes to the current nightly version --- library/std/src/io/stdio.rs | 4 ++-- library/std/src/io/util.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index cccc0aadf9989..b1033636a4536 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -607,7 +607,7 @@ impl Write for Stdout { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) @@ -810,7 +810,7 @@ impl Write for Stderr { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index ce4dd1dcd493d..482378a6aba25 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -248,7 +248,7 @@ impl Write for Sink { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Sink { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { From 0acb0ed1841d362a1119ba2ad293683660bdfaaf Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Mon, 21 Sep 2020 08:12:40 +0100 Subject: [PATCH 15/27] Update library/std/src/process.rs Co-authored-by: David Tolnay --- library/std/src/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index d620a720be3ab..b2815ba32c4f4 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -262,7 +262,7 @@ impl Write for ChildStdin { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) From 60b102de06f52102aa6c343de1f1ef31ff08f8df Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 31 Aug 2020 12:32:37 +0200 Subject: [PATCH 16/27] Don't recommend ManuallyDrop to customize drop order See https://internals.rust-lang.org/t/need-for-controlling-drop-order-of-fields/12914/21 for the discussion. TL;DR: ManuallyDrop is unsafe and footguny, but you can just ask the compiler to do all the work for you by re-ordering declarations. --- library/core/src/mem/manually_drop.rs | 55 +++++++++------------------ 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index aab0e96d83ab9..d86939454be5b 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -15,50 +15,33 @@ use crate::ptr; /// be exposed through a public safe API. /// Correspondingly, `ManuallyDrop::drop` is unsafe. /// -/// # Examples +/// # `ManuallyDrop` and drop order. /// -/// This wrapper can be used to enforce a particular drop order on fields, regardless -/// of how they are defined in the struct: +/// Rust has a well-defined [drop order] of values. To make sure that fields or +/// locals are dropped in a specific order, reorder the declarations such that +/// the implicit drop order is the correct one. /// -/// ```rust -/// use std::mem::ManuallyDrop; -/// struct Peach; -/// struct Banana; -/// struct Melon; -/// struct FruitBox { -/// // Immediately clear there’s something non-trivial going on with these fields. -/// peach: ManuallyDrop, -/// melon: Melon, // Field that’s independent of the other two. -/// banana: ManuallyDrop, -/// } +/// It is possible to use `ManuallyDrop` to control the drop order, but this +/// requires unsafe code and is hard to do correctly in the presence of +/// unwinding. /// -/// impl Drop for FruitBox { -/// fn drop(&mut self) { -/// unsafe { -/// // Explicit ordering in which field destructors are run specified in the intuitive -/// // location – the destructor of the structure containing the fields. -/// // Moreover, one can now reorder fields within the struct however much they want. -/// ManuallyDrop::drop(&mut self.peach); -/// ManuallyDrop::drop(&mut self.banana); -/// } -/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets -/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. -/// } -/// } -/// ``` +/// For example, if you want to make sure that a specific field is dropped after +/// the others, make it the last field of a struct: /// -/// However, care should be taken when using this pattern as it can lead to *leak amplification*. -/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field -/// would also be leaked. +/// ``` +/// struct Context; /// -/// In contrast, the automatically-generated compiler drop implementation would have ensured -/// that all fields are dropped even in the presence of panics. This is especially important when -/// working with [pinned] data, where reusing the memory without calling the destructor could lead -/// to Undefined Behaviour. +/// struct Widget { +/// children: Vec, +/// // `context` will be dropped after `children`. +/// // Rust guarantees that fields are dropped in the order of declaration. +/// context: Context, +/// } +/// ``` /// +/// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed /// [`MaybeUninit`]: crate::mem::MaybeUninit -/// [pinned]: crate::pin #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] From fe6fc555acd51bd7ba8755d9fbc7060feb67be25 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 22:55:16 -0400 Subject: [PATCH 17/27] Add a changelog for x.py - Add a changelog and instructions for updating it - Use `changelog-seen` in `config.toml` and `VERSION` in bootstrap to determine whether the changelog has been read - Nag people if they haven't read the x.py changelog + Print message twice to make sure it's seen - Give different error messages depending on whether the version needs to be updated or added --- config.toml.example | 6 ++++++ src/bootstrap/CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ src/bootstrap/README.md | 14 ++++++++++++++ src/bootstrap/bin/main.rs | 35 +++++++++++++++++++++++++++++++++++ src/bootstrap/config.rs | 9 ++++++++- 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/bootstrap/CHANGELOG.md diff --git a/config.toml.example b/config.toml.example index 8bf1b48ce830e..fb62e1b4726bc 100644 --- a/config.toml.example +++ b/config.toml.example @@ -9,6 +9,12 @@ # a custom configuration file can also be specified with `--config` to the build # system. +# Keeps track of the last version of `x.py` used. +# If it does not match the version that is currently running, +# `x.py` will prompt you to update it and read the changelog. +# See `src/bootstrap/CHANGELOG.md` for more information. +changelog-seen = 1 + # ============================================================================= # Global Settings # ============================================================================= diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md new file mode 100644 index 0000000000000..5fcaafab959e9 --- /dev/null +++ b/src/bootstrap/CHANGELOG.md @@ -0,0 +1,33 @@ +# Changelog + +All notable changes to bootstrap will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Non-breaking changes since the last major version] + +- Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626) +- Optionally, download LLVM from CI on Linux and NixOS + + [#76439](https://github.com/rust-lang/rust/pull/76349) + + [#76667](https://github.com/rust-lang/rust/pull/76667) + + [#76708](https://github.com/rust-lang/rust/pull/76708) +- Distribute rustc sources as part of `rustc-dev` [#76856](https://github.com/rust-lang/rust/pull/76856) +- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625) +- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588) +- Add sample defaults for x.py [#76628](https://github.com/rust-lang/rust/pull/76628) + +## [Version 0] - 2020-09-11 + +This is the first changelog entry, and it does not attempt to be an exhaustive list of features in x.py. +Instead, this documents the changes to bootstrap in the past 2 months. + +- Improve defaults in `x.py` [#73964](https://github.com/rust-lang/rust/pull/73964) + (see [blog post] for details) +- Set `ninja = true` by default [#74922](https://github.com/rust-lang/rust/pull/74922) +- Avoid trying to inversely cross-compile for build triple from host triples [#76415](https://github.com/rust-lang/rust/pull/76415) +- Allow blessing expect-tests in tools [#75975](https://github.com/rust-lang/rust/pull/75975) +- `x.py check` checks tests/examples/benches [#76258](https://github.com/rust-lang/rust/pull/76258) +- Fix `rust.use-lld` when linker is not set [#76326](https://github.com/rust-lang/rust/pull/76326) +- Build tests with LLD if `use-lld = true` was passed [#76378](https://github.com/rust-lang/rust/pull/76378) + +[blog post]: https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index a69bd1cc3bc53..bc8bae14b210c 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -313,6 +313,20 @@ are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/sanity.rs`. +If you make a major change, please remember to: + ++ Update `VERSION` in `src/bootstrap/main.rs`. +* Update `changelog-seen = N` in `config.toml.example`. +* Add an entry in `src/bootstrap/CHANGELOG.md`. + +A 'major change' includes + +* A new option or +* A change in the default options. + +Changes that do not affect contributors to the compiler or users +building rustc from source don't need an update to `VERSION`. + If you have any questions feel free to reach out on the `#t-infra` channel in the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When you encounter bugs, please file issues on the rust-lang/rust issue tracker. diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index b67486c9628cd..f7512aa9fcebd 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -12,5 +12,40 @@ use bootstrap::{Build, Config}; fn main() { let args = env::args().skip(1).collect::>(); let config = Config::parse(&args); + + let changelog_suggestion = check_version(&config); + if let Some(suggestion) = &changelog_suggestion { + println!("{}", suggestion); + } + Build::new(config).build(); + + if let Some(suggestion) = changelog_suggestion { + println!("{}", suggestion); + println!("note: this message was printed twice to make it more likely to be seen"); + } +} + +fn check_version(config: &Config) -> Option { + const VERSION: usize = 1; + + let mut msg = String::new(); + + let suggestion = if let Some(seen) = config.changelog_seen { + if seen != VERSION { + msg.push_str("warning: there have been changes to x.py since you last updated.\n"); + format!("update `config.toml` to use `changelog-seen = {}` instead", VERSION) + } else { + return None; + } + } else { + msg.push_str("warning: x.py has made several changes recently you may want to look at\n"); + format!("add `changelog-seen = {}` to `config.toml`", VERSION) + }; + + msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n"); + msg.push_str("note: to silence this warning, "); + msg.push_str(&suggestion); + + Some(msg) } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 801ed5ac6eeea..c74501979f0ec 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -42,6 +42,7 @@ macro_rules! check_ci_llvm { /// `config.toml.example`. #[derive(Default)] pub struct Config { + pub changelog_seen: Option, pub ccache: Option, /// Call Build::ninja() instead of this. pub ninja_in_file: bool, @@ -273,6 +274,7 @@ impl Target { #[derive(Deserialize, Default)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct TomlConfig { + changelog_seen: Option, build: Option, install: Option, llvm: Option, @@ -283,7 +285,10 @@ struct TomlConfig { } impl Merge for TomlConfig { - fn merge(&mut self, TomlConfig { build, install, llvm, rust, dist, target, profile: _ }: Self) { + fn merge( + &mut self, + TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen: _ }: Self, + ) { fn do_merge(x: &mut Option, y: Option) { if let Some(new) = y { if let Some(original) = x { @@ -572,6 +577,8 @@ impl Config { toml.merge(included_toml); } + config.changelog_seen = toml.changelog_seen; + let build = toml.build.unwrap_or_default(); // If --target was specified but --host wasn't specified, don't run any host-only tests. From b4b4a2f0927d2d1d838da1e128472ff8bf64e98b Mon Sep 17 00:00:00 2001 From: James Whaley Date: Mon, 21 Sep 2020 18:27:43 +0100 Subject: [PATCH 18/27] Reduce boilerplate for BytePos and CharPos --- compiler/rustc_span/src/lib.rs | 137 +++++++++++++-------------------- 1 file changed, 55 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index a730c30378827..ad3a866463d45 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1558,58 +1558,71 @@ pub trait Pos { fn to_u32(&self) -> u32; } -/// A byte offset. Keep this small (currently 32-bits), as AST contains -/// a lot of them. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -pub struct BytePos(pub u32); - -/// A character offset. Because of multibyte UTF-8 characters, a byte offset -/// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` -/// values to `CharPos` values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct CharPos(pub usize); +macro_rules! impl_pos { + ( + $( + $(#[$attr:meta])* + $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty); + )* + ) => { + $( + $(#[$attr])* + $vis struct $ident($inner_vis $inner_ty); + + impl Pos for $ident { + #[inline(always)] + fn from_usize(n: usize) -> $ident { + $ident(n as $inner_ty) + } -// FIXME: lots of boilerplate in these impls, but so far my attempts to fix -// have been unsuccessful. + #[inline(always)] + fn to_usize(&self) -> usize { + self.0 as usize + } -impl Pos for BytePos { - #[inline(always)] - fn from_usize(n: usize) -> BytePos { - BytePos(n as u32) - } + #[inline(always)] + fn from_u32(n: u32) -> $ident { + $ident(n as $inner_ty) + } - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 as usize - } + #[inline(always)] + fn to_u32(&self) -> u32 { + self.0 as u32 + } + } - #[inline(always)] - fn from_u32(n: u32) -> BytePos { - BytePos(n) - } + impl Add for $ident { + type Output = $ident; - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 - } -} + #[inline(always)] + fn add(self, rhs: $ident) -> $ident { + $ident((self.to_usize() + rhs.to_usize()) as $inner_ty) + } + } -impl Add for BytePos { - type Output = BytePos; + impl Sub for $ident { + type Output = $ident; - #[inline(always)] - fn add(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() + rhs.to_usize()) as u32) - } + #[inline(always)] + fn sub(self, rhs: $ident) -> $ident { + $ident((self.to_usize() - rhs.to_usize()) as $inner_ty) + } + } + )* + }; } -impl Sub for BytePos { - type Output = BytePos; +impl_pos! { + /// A byte offset. Keep this small (currently 32-bits), as AST contains + /// a lot of them. + #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] + pub struct BytePos(pub u32); - #[inline(always)] - fn sub(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() - rhs.to_usize()) as u32) - } + /// A character offset. Because of multibyte UTF-8 characters, a byte offset + /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` + /// values to `CharPos` values as necessary. + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] + pub struct CharPos(pub usize); } impl Encodable for BytePos { @@ -1624,46 +1637,6 @@ impl Decodable for BytePos { } } -impl Pos for CharPos { - #[inline(always)] - fn from_usize(n: usize) -> CharPos { - CharPos(n) - } - - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 - } - - #[inline(always)] - fn from_u32(n: u32) -> CharPos { - CharPos(n as usize) - } - - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 as u32 - } -} - -impl Add for CharPos { - type Output = CharPos; - - #[inline(always)] - fn add(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() + rhs.to_usize()) - } -} - -impl Sub for CharPos { - type Output = CharPos; - - #[inline(always)] - fn sub(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() - rhs.to_usize()) - } -} - // _____________________________________________________________________________ // Loc, SourceFileAndLine, SourceFileAndBytePos // From 9a1f1777d3602b267c78229e1d5de68fe7eab57a Mon Sep 17 00:00:00 2001 From: James Whaley Date: Mon, 21 Sep 2020 19:42:43 +0100 Subject: [PATCH 19/27] Remove cast to usize for BytePos and CharPos The case shouldn't be necessary and implicitly truncating BytePos is not desirable. --- compiler/rustc_span/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ad3a866463d45..4b02a2d4076d7 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1596,7 +1596,7 @@ macro_rules! impl_pos { #[inline(always)] fn add(self, rhs: $ident) -> $ident { - $ident((self.to_usize() + rhs.to_usize()) as $inner_ty) + $ident(self.0 + rhs.0) } } @@ -1605,7 +1605,7 @@ macro_rules! impl_pos { #[inline(always)] fn sub(self, rhs: $ident) -> $ident { - $ident((self.to_usize() - rhs.to_usize()) as $inner_ty) + $ident(self.0 - rhs.0) } } )* From 63195ecb458bba01f36f407b6df69aa03828243e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Sep 2020 21:02:18 +0200 Subject: [PATCH 20/27] Add explanation for E0756 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0756.md | 29 +++++++++++++++++++ src/test/ui/ffi_const.stderr | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0756.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 23a7b08016e50..a202736ea6cbe 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -441,6 +441,7 @@ E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), E0755: include_str!("./error_codes/E0755.md"), +E0756: include_str!("./error_codes/E0756.md"), E0758: include_str!("./error_codes/E0758.md"), E0759: include_str!("./error_codes/E0759.md"), E0760: include_str!("./error_codes/E0760.md"), @@ -633,7 +634,6 @@ E0774: include_str!("./error_codes/E0774.md"), E0722, // Malformed `#[optimize]` attribute E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md new file mode 100644 index 0000000000000..ffdc421aab584 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -0,0 +1,29 @@ +The `ffi_const` attribute was used on something other than a foreign function +declaration. + +Erroneous code example: + +```compile_fail,E0756 +#![feature(ffi_const)] + +#[ffi_const] // error! +pub fn foo() {} +# fn main() {} +``` + +The `ffi_const` attribute can only be used on foreign function declarations +which have no side effects except for their return value: + +``` +#![feature(ffi_const)] + +extern "C" { + #[ffi_const] // ok! + pub fn strlen(s: *const i8) -> i32; +} +# fn main() {} +``` + +You can get more information about it in the [unstable Rust Book]. + +[unstable Rust Book]: https://doc.rust-lang.org/nightly/unstable-book/language-features/ffi-const.html diff --git a/src/test/ui/ffi_const.stderr b/src/test/ui/ffi_const.stderr index 623551cc07bbb..bc3c12eaf981b 100644 --- a/src/test/ui/ffi_const.stderr +++ b/src/test/ui/ffi_const.stderr @@ -6,3 +6,4 @@ LL | #[ffi_const] error: aborting due to previous error +For more information about this error, try `rustc --explain E0756`. From f5d71a9b3cf3018ec646acb6f8fa731fb8ca902e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 Aug 2020 18:08:16 -0400 Subject: [PATCH 21/27] Don't use `zip` to compare iterators during pretty-print hack If the right-hand iterator has exactly one more element than the left-hand iterator, then both iterators will be fully consumed, but the extra element will never be compared. --- compiler/rustc_parse/src/lib.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 72a34b86ae20b..21bbdc9ba8dce 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,6 +3,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] +#![feature(iter_order_by)] #![feature(or_patterns)] use rustc_ast as ast; @@ -459,14 +460,10 @@ pub fn tokenstream_probably_equal_for_proc_macro( // Break tokens after we expand any nonterminals, so that we break tokens // that are produced as a result of nonterminal expansion. - let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) { - return false; - } - } - t1.next().is_none() && t2.next().is_none() + let t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + let t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + + t1.eq_by(t2, |t1, t2| tokentree_probably_equal_for_proc_macro(&t1, &t2, sess)) } // See comments in `Nonterminal::to_tokenstream` for why we care about From 40a5dc8860dad243b56e75ca19a0863d5e0571b8 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 13 Sep 2020 16:04:45 +0200 Subject: [PATCH 22/27] MIR pass to remove unneeded drops on types not needing drop This is heavily dependent on MIR inlining running to actually see the drop statement --- compiler/rustc_mir/src/transform/mod.rs | 2 + .../src/transform/remove_unneeded_drops.rs | 57 +++++++++++++++++++ ...annot_opt_generic.RemoveUnneededDrops.diff | 32 +++++++++++ ...ed_drops.dont_opt.RemoveUnneededDrops.diff | 32 +++++++++++ ...nneeded_drops.opt.RemoveUnneededDrops.diff | 29 ++++++++++ ....opt_generic_copy.RemoveUnneededDrops.diff | 29 ++++++++++ src/test/mir-opt/remove_unneeded_drops.rs | 28 +++++++++ 7 files changed, 209 insertions(+) create mode 100644 compiler/rustc_mir/src/transform/remove_unneeded_drops.rs create mode 100644 src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.rs diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index abe2dc496a630..17ef98c176df2 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -38,6 +38,7 @@ pub mod nrvo; pub mod promote_consts; pub mod qualify_min_const_fn; pub mod remove_noop_landing_pads; +pub mod remove_unneeded_drops; pub mod required_consts; pub mod rustc_peek; pub mod simplify; @@ -461,6 +462,7 @@ fn run_optimization_passes<'tcx>( // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ + &remove_unneeded_drops::RemoveUnneededDrops::new(def_id), &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &instcombine::InstCombine, diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs new file mode 100644 index 0000000000000..0f023d71dd1da --- /dev/null +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -0,0 +1,57 @@ +//! This pass replaces a drop of a type that does not need dropping, with a goto + +use crate::transform::{MirPass, MirSource}; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct RemoveUnneededDrops { + def_id: LocalDefId, +} + +impl RemoveUnneededDrops { + pub fn new(def_id: LocalDefId) -> Self { + Self { def_id } + } +} + +impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + trace!("Running SimplifyComparisonIntegral on {:?}", source); + let mut opt_finder = RemoveUnneededDropsOptimizationFinder { + tcx, + body, + optimizations: vec![], + def_id: self.def_id, + }; + opt_finder.visit_body(body); + for (loc, target) in opt_finder.optimizations { + let terminator = body.basic_blocks_mut()[loc.block].terminator_mut(); + debug!("SUCCESS: replacing `drop` with goto({:?})", target); + terminator.kind = TerminatorKind::Goto { target }; + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + match terminator.kind { + TerminatorKind::Drop { place, target, .. } => { + let ty = place.ty(self.body, self.tcx); + let needs_drop = ty.ty.needs_drop(self.tcx, self.tcx.param_env(self.def_id)); + if !needs_drop { + self.optimizations.push((location, target)); + } + } + _ => {} + } + self.super_terminator(terminator, location); + } +} +pub struct RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + optimizations: Vec<(Location, BasicBlock)>, + def_id: LocalDefId, +} diff --git a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff new file mode 100644 index 0000000000000..545ad2794ee17 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -0,0 +1,32 @@ +- // MIR for `cannot_opt_generic` before RemoveUnneededDrops ++ // MIR for `cannot_opt_generic` after RemoveUnneededDrops + + fn cannot_opt_generic(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:19:26: 19:27 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:19:32: 19:32 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:20:5: 20:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:20:5: 20:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:19:1: 21:2 + } + + bb2: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:20:11: 20:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:20:12: 20:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:19:32: 21:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:21:2: 21:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff new file mode 100644 index 0000000000000..78d65d13bd1bf --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -0,0 +1,32 @@ +- // MIR for `dont_opt` before RemoveUnneededDrops ++ // MIR for `dont_opt` after RemoveUnneededDrops + + fn dont_opt(_1: Vec) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:7:13: 7:14 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:7:27: 7:27 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:8:5: 8:12 + let mut _3: std::vec::Vec; // in scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:8:5: 8:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:7:1: 9:2 + } + + bb2: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:8:11: 8:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:8:12: 8:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:7:27: 9:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:9:2: 9:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff new file mode 100644 index 0000000000000..34193ccc5c7e7 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -0,0 +1,29 @@ +- // MIR for `opt` before RemoveUnneededDrops ++ // MIR for `opt` after RemoveUnneededDrops + + fn opt(_1: bool) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:2:8: 2:9 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:2:17: 2:17 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:3:5: 3:12 + let mut _3: bool; // in scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:3:5: 3:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ goto -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:3:11: 3:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:3:12: 3:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:2:17: 4:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:4:2: 4:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff new file mode 100644 index 0000000000000..2e6c8c8a78a72 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -0,0 +1,29 @@ +- // MIR for `opt_generic_copy` before RemoveUnneededDrops ++ // MIR for `opt_generic_copy` after RemoveUnneededDrops + + fn opt_generic_copy(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:12:30: 12:31 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:12:36: 12:36 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:13:5: 13:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:13:5: 13:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ goto -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:13:11: 13:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:13:12: 13:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:12:36: 14:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:14:2: 14:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.rs b/src/test/mir-opt/remove_unneeded_drops.rs new file mode 100644 index 0000000000000..17d7e79a1eb0a --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.rs @@ -0,0 +1,28 @@ +// EMIT_MIR remove_unneeded_drops.opt.RemoveUnneededDrops.diff +fn opt(x: bool) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +fn dont_opt(x: Vec) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +fn opt_generic_copy(x: T) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff +// since the pass is not running on monomorphisized code, +// we can't (but probably should) optimize this +fn cannot_opt_generic(x: T) { + drop(x); +} + +fn main() { + opt(true); + opt_generic_copy(42); + cannot_opt_generic(42); + dont_opt(vec![true]); +} From e6942ae7515747b490bf1dd3fa292637fc6952e4 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Mon, 14 Sep 2020 22:56:39 +0200 Subject: [PATCH 23/27] Suggestion from review Co-authored-by: Andreas Jonson --- compiler/rustc_mir/src/transform/remove_unneeded_drops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 0f023d71dd1da..393b0f923b910 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -18,7 +18,7 @@ impl RemoveUnneededDrops { impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { - trace!("Running SimplifyComparisonIntegral on {:?}", source); + trace!("Running RemoveUnneededDrops on {:?}", source); let mut opt_finder = RemoveUnneededDropsOptimizationFinder { tcx, body, From 9b61fbcd5dd64441b27071ea19e8970af55e9126 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 13:52:55 +0200 Subject: [PATCH 24/27] Get LocalDefId from source instead of passing in --- compiler/rustc_mir/src/transform/mod.rs | 2 +- .../rustc_mir/src/transform/remove_unneeded_drops.rs | 12 ++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 17ef98c176df2..f48ad039b4ff9 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -462,7 +462,7 @@ fn run_optimization_passes<'tcx>( // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ - &remove_unneeded_drops::RemoveUnneededDrops::new(def_id), + &remove_unneeded_drops::RemoveUnneededDrops, &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &instcombine::InstCombine, diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 393b0f923b910..505133219b863 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -6,15 +6,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -pub struct RemoveUnneededDrops { - def_id: LocalDefId, -} - -impl RemoveUnneededDrops { - pub fn new(def_id: LocalDefId) -> Self { - Self { def_id } - } -} +pub struct RemoveUnneededDrops; impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { @@ -23,7 +15,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { tcx, body, optimizations: vec![], - def_id: self.def_id, + def_id: source.def_id().expect_local(), }; opt_finder.visit_body(body); for (loc, target) in opt_finder.optimizations { From d3724553adf988fadc548182573d80f4885a4e1c Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 14:25:53 +0200 Subject: [PATCH 25/27] The optimization should also apply for DropAndReplace --- compiler/rustc_mir/src/transform/remove_unneeded_drops.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 505133219b863..b8ad816f75831 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -29,7 +29,8 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { match terminator.kind { - TerminatorKind::Drop { place, target, .. } => { + TerminatorKind::Drop { place, target, .. } + | TerminatorKind::DropAndReplace { place, target, .. } => { let ty = place.ty(self.body, self.tcx); let needs_drop = ty.ty.needs_drop(self.tcx, self.tcx.param_env(self.def_id)); if !needs_drop { From 1b2da2efb2793e12200674814aca0880608f3ae1 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 15:21:39 +0200 Subject: [PATCH 26/27] cleanup cfg after optimization --- .../rustc_mir/src/transform/remove_unneeded_drops.rs | 9 +++++++++ .../remove_unneeded_drops.opt.RemoveUnneededDrops.diff | 7 +++---- ...eeded_drops.opt_generic_copy.RemoveUnneededDrops.diff | 7 +++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index b8ad816f75831..f027f5e33a187 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -6,6 +6,8 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use super::simplify::simplify_cfg; + pub struct RemoveUnneededDrops; impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { @@ -18,11 +20,18 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { def_id: source.def_id().expect_local(), }; opt_finder.visit_body(body); + let should_simplify = !opt_finder.optimizations.is_empty(); for (loc, target) in opt_finder.optimizations { let terminator = body.basic_blocks_mut()[loc.block].terminator_mut(); debug!("SUCCESS: replacing `drop` with goto({:?})", target); terminator.kind = TerminatorKind::Goto { target }; } + + // if we applied optimizations, we potentially have some cfg to cleanup to + // make it easier for further passes + if should_simplify { + simplify_cfg(body); + } } } diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff index 34193ccc5c7e7..eba839cf0a48b 100644 --- a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -16,10 +16,9 @@ _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL -+ goto -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb1: { +- } +- +- bb1: { StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:3:11: 3:12 StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:3:12: 3:13 _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:2:17: 4:2 diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff index 2e6c8c8a78a72..840b1ba30fb9b 100644 --- a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -16,10 +16,9 @@ _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL -+ goto -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb1: { +- } +- +- bb1: { StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:13:11: 13:12 StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:13:12: 13:13 _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:12:36: 14:2 From dfb9f3aa254ea7bdcaa8a0f1c9850674ad6198c9 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Mon, 21 Sep 2020 22:06:54 +0200 Subject: [PATCH 27/27] rebless after rebase --- .../mir-opt/dest-prop/cycle.main.DestinationPropagation.diff | 4 ---- .../mir-opt/dest-prop/union.main.DestinationPropagation.diff | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff index dd717c1b9c324..881c296cee77a 100644 --- a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff @@ -57,10 +57,6 @@ - _6 = _1; // scope 3 at $DIR/cycle.rs:14:10: 14:11 + _6 = _4; // scope 3 at $DIR/cycle.rs:14:10: 14:11 _5 = const (); // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_6) -> bb2; // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb2: { StorageDead(_6); // scope 3 at $DIR/cycle.rs:14:11: 14:12 StorageDead(_5); // scope 3 at $DIR/cycle.rs:14:12: 14:13 _0 = const (); // scope 0 at $DIR/cycle.rs:8:11: 15:2 diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff index 871f6e35043ec..f15e7bcb2fba6 100644 --- a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff @@ -32,10 +32,6 @@ StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26 _4 = (_1.0: u32); // scope 2 at $DIR/union.rs:15:19: 15:24 _3 = const (); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_4) -> bb2; // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb2: { StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27 StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28 _0 = const (); // scope 0 at $DIR/union.rs:8:11: 16:2