From e7c122c5b58d4db2262b1f4325d9fe82d1423ad8 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 Jun 2018 12:54:25 +0200 Subject: [PATCH 01/23] Revert "Remove TryFrom impls that might become conditionally-infallible with a portability lint" This reverts commit 837d6c70233715a0ae8e15c703d40e3046a2f36a. Fixes https://github.com/rust-lang/rust/issues/49415 --- src/libcore/iter/range.rs | 75 +-------------------- src/libcore/num/mod.rs | 70 ++++++++++++++++--- src/libcore/tests/num/mod.rs | 127 +++++++++++++++++++++++++++++++++++ src/libstd/io/cursor.rs | 20 +----- 4 files changed, 191 insertions(+), 101 deletions(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 5896322f111f8..0b279f66b88d6 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -91,7 +91,7 @@ macro_rules! step_impl_unsigned { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$t>::private_try_from(n) { + match <$t>::try_from(n) { Ok(n_as_t) => self.checked_add(n_as_t), Err(_) => None, } @@ -123,7 +123,7 @@ macro_rules! step_impl_signed { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$unsigned>::private_try_from(n) { + match <$unsigned>::try_from(n) { Ok(n_as_unsigned) => { // Wrapping in unsigned space handles cases like // `-120_i8.add_usize(200) == Some(80_i8)`, @@ -461,74 +461,3 @@ impl DoubleEndedIterator for ops::RangeInclusive { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} - -/// Compensate removal of some impls per -/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 -trait PrivateTryFromUsize: Sized { - fn private_try_from(n: usize) -> Result; -} - -impl PrivateTryFromUsize for T where T: TryFrom { - #[inline] - fn private_try_from(n: usize) -> Result { - T::try_from(n).map_err(|_| ()) - } -} - -// no possible bounds violation -macro_rules! try_from_unbounded { - ($($target:ty),*) => {$( - impl PrivateTryFromUsize for $target { - #[inline] - fn private_try_from(value: usize) -> Result { - Ok(value as $target) - } - } - )*} -} - -// unsigned to signed (only positive bound) -#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] -macro_rules! try_from_upper_bounded { - ($($target:ty),*) => {$( - impl PrivateTryFromUsize for $target { - #[inline] - fn private_try_from(u: usize) -> Result<$target, ()> { - if u > (<$target>::max_value() as usize) { - Err(()) - } else { - Ok(u as $target) - } - } - } - )*} -} - - -#[cfg(target_pointer_width = "16")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_unbounded!(u16, u32, u64, u128); - try_from_unbounded!(i32, i64, i128); -} - -#[cfg(target_pointer_width = "32")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_upper_bounded!(u16); - try_from_unbounded!(u32, u64, u128); - try_from_upper_bounded!(i32); - try_from_unbounded!(i64, i128); -} - -#[cfg(target_pointer_width = "64")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_upper_bounded!(u16, u32); - try_from_unbounded!(u64, u128); - try_from_upper_bounded!(i32, i64); - try_from_unbounded!(i128); -} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 26dd08b10b9b8..2389f6d4e1fd3 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4413,6 +4413,21 @@ impl From for TryFromIntError { } } +// no possible bounds violation +macro_rules! try_from_unbounded { + ($source:ty, $($target:ty),*) => {$( + #[unstable(feature = "try_from", issue = "33417")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + #[inline] + fn try_from(value: $source) -> Result { + Ok(value as $target) + } + } + )*} +} + // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( @@ -4511,20 +4526,27 @@ try_from_both_bounded!(i128, u64, u32, u16, u8); try_from_upper_bounded!(usize, isize); try_from_lower_bounded!(isize, usize); -try_from_upper_bounded!(usize, u8); -try_from_upper_bounded!(usize, i8, i16); -try_from_both_bounded!(isize, u8); -try_from_both_bounded!(isize, i8); - #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs + try_from_upper_bounded!(usize, u8); + try_from_unbounded!(usize, u16, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16); + try_from_unbounded!(usize, i32, i64, i128); + + try_from_both_bounded!(isize, u8); try_from_lower_bounded!(isize, u16, u32, u64, u128); + try_from_both_bounded!(isize, i8); + try_from_unbounded!(isize, i16, i32, i64, i128); + + rev!(try_from_upper_bounded, usize, u32, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16); rev!(try_from_both_bounded, usize, i32, i64, i128); + + rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); + rev!(try_from_both_bounded, isize, i32, i64, i128); } #[cfg(target_pointer_width = "32")] @@ -4532,11 +4554,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs - try_from_both_bounded!(isize, u16); + try_from_upper_bounded!(usize, u8, u16); + try_from_unbounded!(usize, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32); + try_from_unbounded!(usize, i64, i128); + + try_from_both_bounded!(isize, u8, u16); try_from_lower_bounded!(isize, u32, u64, u128); + try_from_both_bounded!(isize, i8, i16); + try_from_unbounded!(isize, i32, i64, i128); + + rev!(try_from_unbounded, usize, u32); + rev!(try_from_upper_bounded, usize, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32); rev!(try_from_both_bounded, usize, i64, i128); + + rev!(try_from_unbounded, isize, u16); + rev!(try_from_upper_bounded, isize, u32, u64, u128); + rev!(try_from_unbounded, isize, i32); + rev!(try_from_both_bounded, isize, i64, i128); } #[cfg(target_pointer_width = "64")] @@ -4544,11 +4580,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs - try_from_both_bounded!(isize, u16, u32); + try_from_upper_bounded!(usize, u8, u16, u32); + try_from_unbounded!(usize, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32, i64); + try_from_unbounded!(usize, i128); + + try_from_both_bounded!(isize, u8, u16, u32); try_from_lower_bounded!(isize, u64, u128); + try_from_both_bounded!(isize, i8, i16, i32); + try_from_unbounded!(isize, i64, i128); + + rev!(try_from_unbounded, usize, u32, u64); + rev!(try_from_upper_bounded, usize, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); rev!(try_from_both_bounded, usize, i128); + + rev!(try_from_unbounded, isize, u16, u32); + rev!(try_from_upper_bounded, isize, u64, u128); + rev!(try_from_unbounded, isize, i32, i64); + rev!(try_from_both_bounded, isize, i128); } #[doc(hidden)] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index b5e6a019a228c..00aed25aa1a02 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -37,6 +37,15 @@ mod flt2dec; mod dec2flt; mod bignum; + +/// Adds the attribute to all items in the block. +macro_rules! cfg_block { + ($(#[$attr:meta]{$($it:item)*})*) => {$($( + #[$attr] + $it + )*)*} +} + /// Groups items that assume the pointer width is either 16/32/64, and has to be altered if /// support for larger/smaller pointer widths are added in the future. macro_rules! assume_usize_width { @@ -330,6 +339,42 @@ assume_usize_width! { test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } + + test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } + test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } + test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } + + test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } + test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } + test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } + test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } + } + ); } /// Conversions where max of $source can be represented as $target, @@ -378,6 +423,24 @@ assume_usize_width! { test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } + } + ); } /// Conversions where max of $source can not be represented as $target, @@ -419,9 +482,29 @@ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } assume_usize_width! { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } + } + ); } /// Conversions where min/max of $source can not be represented as $target. @@ -481,6 +564,34 @@ test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } assume_usize_width! { test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } + test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } + test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + + test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } + + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } + } + ); } /// Conversions where neither the min nor the max of $source can be represented by @@ -525,6 +636,22 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } assume_usize_width! { test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } + + cfg_block! { + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + } + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + } + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } + } + } } macro_rules! test_float { diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 8ac52572810c6..aadd33b39542c 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -10,6 +10,7 @@ use io::prelude::*; +use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; @@ -259,26 +260,9 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result Result { - if n <= (::max_value() as u64) { - Ok(n as usize) - } else { - Err(()) - } -} - -#[cfg(any(target_pointer_width = "64"))] -fn try_into(n: u64) -> Result { - Ok(n as usize) -} - // Resizing write implementation fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result { - let pos: usize = try_into(*pos_mut).map_err(|_| { + let pos: usize = (*pos_mut).try_into().map_err(|_| { Error::new(ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length") })?; From b4d64b7b28038d7e4b0bc75f1d407d5382512996 Mon Sep 17 00:00:00 2001 From: Richard Diamond Date: Thu, 14 Jun 2018 01:13:44 -0500 Subject: [PATCH 02/23] Initialize LLVM's AMDGPU target machine, if available. Note this isn't useful, yet. More changes will be necessary to be able to actually codegen for this machine. As such, it is not enabled by default. This patch is on its own for the benefit of the reviewers. --- src/librustc_llvm/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 07830d54d0c9e..741758cb954ba 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -331,6 +331,12 @@ pub fn initialize_available_targets() { LLVMInitializeAArch64TargetMC, LLVMInitializeAArch64AsmPrinter, LLVMInitializeAArch64AsmParser); + init_target!(llvm_component = "amdgpu", + LLVMInitializeAMDGPUTargetInfo, + LLVMInitializeAMDGPUTarget, + LLVMInitializeAMDGPUTargetMC, + LLVMInitializeAMDGPUAsmPrinter, + LLVMInitializeAMDGPUAsmParser); init_target!(llvm_component = "mips", LLVMInitializeMipsTargetInfo, LLVMInitializeMipsTarget, From 7015dfd1b9cfc02cd1f6dc30cd88b106211a3921 Mon Sep 17 00:00:00 2001 From: Dror Levin Date: Tue, 26 Jun 2018 13:29:36 +0300 Subject: [PATCH 03/23] Add read_exact_at and write_all_at methods to FileExt on unix --- src/libstd/sys/unix/ext/fs.rs | 127 ++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 4e98101266903..4c2cea0d32c35 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -59,6 +59,78 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; + /// Reads the exact number of byte required to fill `buf` from the given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. + /// + /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact + /// [`read_at`]: #tymethod.read_at + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`ErrorKind::Interrupted`] then the error is ignored and the operation + /// will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// The contents of `buf` are unspecified in this case. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + /// + /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof + /// + /// # Examples + /// + /// ```no_run + /// #![feature(rw_exact_all_at)] + /// use std::io; + /// use std::fs::File; + /// use std::os::unix::prelude::FileExt; + /// + /// fn main() -> io::Result<()> { + /// let mut buf = [0u8; 8]; + /// let file = File::open("foo.txt")?; + /// + /// // We now read exactly 8 bytes from the offset 10. + /// file.read_exact_at(&mut buf, 10)?; + /// println!("read {} bytes: {:?}", buf.len(), buf); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "rw_exact_all_at", issue = "0")] + fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.read_at(buf, offset) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + offset += n as u64; + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { + Err(io::Error::new(io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer")) + } else { + Ok(()) + } + } + /// Writes a number of bytes starting from a given offset. /// /// Returns the number of bytes written. @@ -93,6 +165,61 @@ pub trait FileExt { /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; + + /// Attempts to write an entire buffer starting from a given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// This method will continuously call [`write_at`] until there is no more data + /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of [`ErrorKind::Interrupted`] kind generated from this method will be + /// returned. + /// + /// # Errors + /// + /// This function will return the first error of + /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. + /// + /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`write_at`]: #tymethod.write_at + /// + /// # Examples + /// + /// ```no_run + /// #![feature(rw_exact_all_at)] + /// use std::fs::File; + /// use std::io; + /// use std::os::unix::prelude::FileExt; + /// + /// fn main() -> io::Result<()> { + /// let file = File::open("foo.txt")?; + /// + /// // We now write at the offset 10. + /// file.write_all_at(b"sushi", 10)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "rw_exact_all_at", issue = "0")] + fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.write_at(buf, offset) { + Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero, + "failed to write whole buffer")), + Ok(n) => { + buf = &buf[n..]; + offset += n as u64 + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } } #[stable(feature = "file_offset", since = "1.15.0")] From 6cc78bf8d76383395e307cef5e601cfe561337e6 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Fri, 29 Jun 2018 22:02:52 -0700 Subject: [PATCH 04/23] in which we plug the crack where `?`-desugaring leaked into errors Most of the time, it's not a problem that the types of the arm bodies in a desugared-from-`?` match are different (that is, specifically: in `x?` where x is a `Result`, the `Ok` arm body is an `A`, whereas the `Err` arm diverges to return a `Result`), because they're being assigned to different places. But in tail position, the types do need to match, and our error message was explicitly referring to "match arms", which is confusing when there's no `match` in the sweetly sugared source. It is not without some misgivings that we pollute the clarity-of-purpose of `note_error_origin` with the suggestion to wrap with `Ok` (the other branches are pointing out the odd-arm-out in the HIR that is the origin of the error; the new branch that issues the `Ok` suggestion is serving a different purpose), but it's the natural place to do it given that we're already matching on `ObligationCauseCode::MatchExpressionArm { arm_span, source }` there. Resolves #51632. --- src/librustc/infer/error_reporting/mod.rs | 19 ++++++++++++-- ...51632-try-desugar-incompatible-types.fixed | 25 +++++++++++++++++++ ...ue-51632-try-desugar-incompatible-types.rs | 25 +++++++++++++++++++ ...1632-try-desugar-incompatible-types.stderr | 15 +++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/issue-51632-try-desugar-incompatible-types.fixed create mode 100644 src/test/ui/issue-51632-try-desugar-incompatible-types.rs create mode 100644 src/test/ui/issue-51632-try-desugar-incompatible-types.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 482af9c005f32..8f428c3e50595 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -500,7 +500,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } else { err.span_label(arm_span, msg); } - } + }, + hir::MatchSource::TryDesugar => { // Issue #51632 + if let Ok(try_snippet) = self.tcx.sess.codemap().span_to_snippet(arm_span) { + err.span_suggestion_with_applicability( + arm_span, + "try wrapping with a success variant", + format!("Ok({})", try_snippet), + Applicability::MachineApplicable + ); + } + }, _ => { let msg = "match arm with an incompatible type"; if self.tcx.sess.codemap().is_multiline(arm_span) { @@ -1294,7 +1304,12 @@ impl<'tcx> ObligationCause<'tcx> { match self.code { CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), MatchExpressionArm { source, .. } => Error0308(match source { - hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types", + hir::MatchSource::IfLetDesugar { .. } => { + "`if let` arms have incompatible types" + }, + hir::MatchSource::TryDesugar => { + "try expression alternatives have incompatible types" + }, _ => "match arms have incompatible types", }), IfExpression => Error0308("if and else have incompatible types"), diff --git a/src/test/ui/issue-51632-try-desugar-incompatible-types.fixed b/src/test/ui/issue-51632-try-desugar-incompatible-types.fixed new file mode 100644 index 0000000000000..016cff914bd2d --- /dev/null +++ b/src/test/ui/issue-51632-try-desugar-incompatible-types.fixed @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// run-rustfix + +#![allow(dead_code)] + +fn missing_discourses() -> Result { + Ok(1) +} + +fn forbidden_narratives() -> Result { + Ok(missing_discourses()?) + //~^ ERROR try expression alternatives have incompatible types + //~| HELP try wrapping with a success variant +} + +fn main() {} diff --git a/src/test/ui/issue-51632-try-desugar-incompatible-types.rs b/src/test/ui/issue-51632-try-desugar-incompatible-types.rs new file mode 100644 index 0000000000000..315773a85f004 --- /dev/null +++ b/src/test/ui/issue-51632-try-desugar-incompatible-types.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// run-rustfix + +#![allow(dead_code)] + +fn missing_discourses() -> Result { + Ok(1) +} + +fn forbidden_narratives() -> Result { + missing_discourses()? + //~^ ERROR try expression alternatives have incompatible types + //~| HELP try wrapping with a success variant +} + +fn main() {} diff --git a/src/test/ui/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issue-51632-try-desugar-incompatible-types.stderr new file mode 100644 index 0000000000000..a50af5624c0cf --- /dev/null +++ b/src/test/ui/issue-51632-try-desugar-incompatible-types.stderr @@ -0,0 +1,15 @@ +error[E0308]: try expression alternatives have incompatible types + --> $DIR/issue-51632-try-desugar-incompatible-types.rs:20:5 + | +LL | missing_discourses()? + | ^^^^^^^^^^^^^^^^^^^^^ + | | + | expected enum `std::result::Result`, found isize + | help: try wrapping with a success variant: `Ok(missing_discourses()?)` + | + = note: expected type `std::result::Result` + found type `isize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From c613aa5a95a83ec77b4b0af1e74019cb8aca75b4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 Jun 2018 11:02:38 +0100 Subject: [PATCH 05/23] Improve error messages when assigning to a local that starts initialized --- .../borrow_check/error_reporting.rs | 49 ++++++++++++------- .../compile-fail/immut-function-arguments.rs | 4 +- .../ui/command-line-diagnostics.nll.stderr | 3 +- .../ui/did_you_mean/issue-35937.nll.stderr | 14 +++--- 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 44fc67dfa4379..f903dbd97a814 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -10,8 +10,10 @@ use borrow_check::WriteKind; use rustc::middle::region::ScopeTree; -use rustc::mir::{BorrowKind, Field, Local, LocalKind, Location, Operand}; -use rustc::mir::{Place, ProjectionElem, Rvalue, Statement, StatementKind}; +use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local}; +use rustc::mir::{LocalDecl, LocalKind, Location, Operand, Place}; +use rustc::mir::{ProjectionElem, Rvalue, Statement, StatementKind}; +use rustc::mir::VarBindingForm; use rustc::ty::{self, RegionKind}; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::sync::Lrc; @@ -622,42 +624,55 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { assigned_span: Span, err_place: &Place<'tcx>, ) { - let is_arg = if let Place::Local(local) = place { - if let LocalKind::Arg = self.mir.local_kind(*local) { - true + let (from_arg, local_decl) = if let Place::Local(local) = *err_place { + if let LocalKind::Arg = self.mir.local_kind(local) { + (true, Some(&self.mir.local_decls[local])) } else { - false + (false, Some(&self.mir.local_decls[local])) } } else { - false + (false, None) + }; + + // If root local is initialized immediately (everything apart from let + // PATTERN;) then make the error refer to that local, rather than the + // place being assigned later. + let (place_description, assigned_span) = match local_decl { + Some(LocalDecl { is_user_variable: Some(ClearCrossCrate::Clear), .. }) + | Some(LocalDecl { is_user_variable: Some(ClearCrossCrate::Set( + BindingForm::Var(VarBindingForm { + opt_match_place: None, .. + }))), ..}) + | Some(LocalDecl { is_user_variable: None, .. }) + | None => (self.describe_place(place), assigned_span), + Some(decl) => (self.describe_place(err_place), decl.source_info.span), }; let mut err = self.tcx.cannot_reassign_immutable( span, - &self.describe_place(place).unwrap_or("_".to_owned()), - is_arg, + place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"), + from_arg, Origin::Mir, ); - let msg = if is_arg { + let msg = if from_arg { "cannot assign to immutable argument" } else { "cannot assign twice to immutable variable" }; if span != assigned_span { - if !is_arg { - let value_msg = match self.describe_place(place) { + if !from_arg { + let value_msg = match place_description { Some(name) => format!("`{}`", name), None => "value".to_owned(), }; err.span_label(assigned_span, format!("first assignment to {}", value_msg)); } } - if let Place::Local(local) = err_place { - let local_decl = &self.mir.local_decls[*local]; - if let Some(name) = local_decl.name { - if local_decl.can_be_made_mutable() { + if let Some(decl) = local_decl { + if let Some(name) = decl.name { + if decl.can_be_made_mutable() { err.span_label( - local_decl.source_info.span, + decl.source_info.span, format!("consider changing this to `mut {}`", name), ); } diff --git a/src/test/compile-fail/immut-function-arguments.rs b/src/test/compile-fail/immut-function-arguments.rs index b32056fcb915a..61a074952efd2 100644 --- a/src/test/compile-fail/immut-function-arguments.rs +++ b/src/test/compile-fail/immut-function-arguments.rs @@ -13,12 +13,12 @@ fn f(y: Box) { *y = 5; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign twice + //[mir]~^ ERROR cannot assign } fn g() { let _frob = |q: Box| { *q = 2; }; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign twice + //[mir]~^ ERROR cannot assign } fn main() {} diff --git a/src/test/ui/command-line-diagnostics.nll.stderr b/src/test/ui/command-line-diagnostics.nll.stderr index 10dcf7d0e657a..46bb7c5af5744 100644 --- a/src/test/ui/command-line-diagnostics.nll.stderr +++ b/src/test/ui/command-line-diagnostics.nll.stderr @@ -2,8 +2,9 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/command-line-diagnostics.rs:16:5 | LL | let x = 42; - | - -- first assignment to `x` + | - | | + | first assignment to `x` | consider changing this to `mut x` LL | x = 43; | ^^^^^^ cannot assign twice to immutable variable diff --git a/src/test/ui/did_you_mean/issue-35937.nll.stderr b/src/test/ui/did_you_mean/issue-35937.nll.stderr index 0c1dcb29d4d2c..7eaa4c7d5fea0 100644 --- a/src/test/ui/did_you_mean/issue-35937.nll.stderr +++ b/src/test/ui/did_you_mean/issue-35937.nll.stderr @@ -6,26 +6,24 @@ LL | let f = Foo { v: Vec::new() }; LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow | ^^^ cannot borrow as mutable -error[E0384]: cannot assign twice to immutable variable `s.x` +error[E0384]: cannot assign twice to immutable variable `s` --> $DIR/issue-35937.rs:26:5 | LL | let s = S { x: 42 }; - | - ----------- first assignment to `s.x` + | - | | + | first assignment to `s` | consider changing this to `mut s` LL | s.x += 1; //~ ERROR cannot assign | ^^^^^^^^ cannot assign twice to immutable variable -error[E0384]: cannot assign twice to immutable variable `s.x` +error[E0384]: cannot assign to immutable argument `s` --> $DIR/issue-35937.rs:30:5 | LL | fn bar(s: S) { - | - - | | - | first assignment to `s.x` - | consider changing this to `mut s` + | - consider changing this to `mut s` LL | s.x += 1; //~ ERROR cannot assign - | ^^^^^^^^ cannot assign twice to immutable variable + | ^^^^^^^^ cannot assign to immutable argument error: aborting due to 3 previous errors From de2ecea3592c81eae5c0ce4e3d26729f7d552c34 Mon Sep 17 00:00:00 2001 From: CrLF0710 Date: Sun, 1 Jul 2018 16:51:44 +0800 Subject: [PATCH 06/23] Provide llvm-strip in llvm-tools component Shipping this tool gives people reliable way to reduce the generated executable size. I'm not sure if this strip tool is available from the llvm version current rust is built on. But let's take a look. @japaric --- src/bootstrap/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b5d450b88392d..148f22bd0a5b6 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -204,7 +204,8 @@ const LLVM_TOOLS: &[&str] = &[ "llvm-objcopy", // used to transform ELFs into binary format which flashing tools consume "llvm-objdump", // used to disassemble programs "llvm-profdata", // used to inspect and merge files generated by profiles - "llvm-size", // prints the size of the linker sections of a program + "llvm-size", // used to prints the size of the linker sections of a program + "llvm-strip", // used to discard symbols from binary files to reduce their size ]; /// A structure representing a Rust compiler. From e89db3030d322ca7cb20d13df5578b60b0c8a942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 1 Jul 2018 20:03:35 -0700 Subject: [PATCH 07/23] Do not suggest changes to str literal if it isn't one --- src/librustc_typeck/check/demand.rs | 16 ++++++++++------ src/test/ui/suggestions/issue-48364.rs | 16 ++++++++++++++++ src/test/ui/suggestions/issue-48364.stderr | 12 ++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/suggestions/issue-48364.rs create mode 100644 src/test/ui/suggestions/issue-48364.stderr diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 08d8dd2e498b6..aee64ad3b550c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -264,9 +264,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (&ty::TyStr, &ty::TySlice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprLit(_) = expr.node { if let Ok(src) = cm.span_to_snippet(sp) { - return Some((sp, - "consider removing the leading `b`", - src[1..].to_string())); + if src.starts_with("b\"") { + return Some((sp, + "consider removing the leading `b`", + src[1..].to_string())); + } } } }, @@ -274,9 +276,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (&ty::TySlice(arr), &ty::TyStr) if arr == self.tcx.types.u8 => { if let hir::ExprLit(_) = expr.node { if let Ok(src) = cm.span_to_snippet(sp) { - return Some((sp, - "consider adding a leading `b`", - format!("b{}", src))); + if src.starts_with("\"") { + return Some((sp, + "consider adding a leading `b`", + format!("b{}", src))); + } } } } diff --git a/src/test/ui/suggestions/issue-48364.rs b/src/test/ui/suggestions/issue-48364.rs new file mode 100644 index 0000000000000..82cb722a65600 --- /dev/null +++ b/src/test/ui/suggestions/issue-48364.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() -> bool { + b"".starts_with(stringify!(foo)) + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-48364.stderr b/src/test/ui/suggestions/issue-48364.stderr new file mode 100644 index 0000000000000..b420654a32d8c --- /dev/null +++ b/src/test/ui/suggestions/issue-48364.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/issue-48364.rs:12:21 + | +LL | b"".starts_with(stringify!(foo)) + | ^^^^^^^^^^^^^^^ expected slice, found str + | + = note: expected type `&[u8]` + found type `&'static str` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 6e5b9c1472175c090700eaae71a7033bc33cd253 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 29 Jun 2018 10:58:17 +0200 Subject: [PATCH 08/23] Get rid of `TyImplTraitExistential` --- src/librustc/hir/intravisit.rs | 7 - src/librustc/hir/lowering.rs | 29 ++-- src/librustc/hir/mod.rs | 12 -- src/librustc/hir/print.rs | 9 -- src/librustc/ich/impls_hir.rs | 1 - src/librustc/middle/resolve_lifetime.rs | 191 +++++++++++++----------- src/librustc_privacy/lib.rs | 44 ++---- src/librustc_typeck/astconv.rs | 16 +- src/librustc_typeck/collect.rs | 4 - 9 files changed, 144 insertions(+), 169 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 60e944e5affc3..a7ed854d01649 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -607,13 +607,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } visitor.visit_lifetime(lifetime); } - TyImplTraitExistential(_, def_id, ref lifetimes) => { - // we are not recursing into the `existential` item, because it is already being visited - // as part of the surrounding module. The `NodeId` just exists so we don't have to look - // it up everywhere else in the compiler - visitor.visit_def_mention(Def::Existential(def_id)); - walk_list!(visitor, visit_lifetime, lifetimes); - } TyTypeof(ref expression) => { visitor.visit_anon_const(expression) } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e59e50ae9e698..5990340ae2955 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1306,13 +1306,20 @@ impl<'a> LoweringContext<'a> { lctx.items.insert(exist_ty_id.node_id, exist_ty_item); // `impl Trait` now just becomes `Foo<'a, 'b, ..>` - hir::TyImplTraitExistential( - hir::ItemId { - id: exist_ty_id.node_id - }, - DefId::local(exist_ty_def_index), - lifetimes, - ) + let path = P(hir::Path { + span: exist_ty_span, + def: Def::Existential(DefId::local(exist_ty_def_index)), + segments: hir_vec![hir::PathSegment { + infer_types: false, + ident: Ident::new(keywords::Invalid.name(), exist_ty_span), + args: Some(P(hir::GenericArgs { + parenthesized: false, + bindings: HirVec::new(), + args: lifetimes, + })) + }], + }); + hir::TyPath(hir::QPath::Resolved(None, path)) }) } @@ -1321,7 +1328,7 @@ impl<'a> LoweringContext<'a> { exist_ty_id: NodeId, parent_index: DefIndex, bounds: &hir::GenericBounds, - ) -> (HirVec, HirVec) { + ) -> (HirVec, HirVec) { // This visitor walks over impl trait bounds and creates defs for all lifetimes which // appear in the bounds, excluding lifetimes that are created within the bounds. // e.g. 'a, 'b, but not 'c in `impl for<'c> SomeTrait<'a, 'b, 'c>` @@ -1332,7 +1339,7 @@ impl<'a> LoweringContext<'a> { collect_elided_lifetimes: bool, currently_bound_lifetimes: Vec, already_defined_lifetimes: HashSet, - output_lifetimes: Vec, + output_lifetimes: Vec, output_lifetime_params: Vec, } @@ -1416,11 +1423,11 @@ impl<'a> LoweringContext<'a> { && !self.already_defined_lifetimes.contains(&name) { self.already_defined_lifetimes.insert(name); - self.output_lifetimes.push(hir::Lifetime { + self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime { id: self.context.next_id().node_id, span: lifetime.span, name, - }); + })); // We need to manually create the ids here, because the // definitions will go into the explicit `existential type` diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index b0b81316148ea..8d83dd3279c64 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1692,18 +1692,6 @@ pub enum Ty_ { /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TyTraitObject(HirVec, Lifetime), - /// An existentially quantified (there exists a type satisfying) `impl - /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime. - /// - /// The `Item` is the generated - /// `existential type Foo<'a, 'b>: MyTrait<'a, 'b>;`. - /// - /// The `HirVec` is the list of lifetimes applied as parameters - /// to the `abstract type`, e.g. the `'c` and `'d` in `-> Foo<'c, 'd>`. - /// This list is only a list of lifetimes and not type parameters - /// because all in-scope type parameters are captured by `impl Trait`, - /// so they are resolved directly through the parent `Generics`. - TyImplTraitExistential(ItemId, DefId, HirVec), /// Unused for now TyTypeof(AnonConst), /// TyInfer means the type should be inferred instead of it having been diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 255009c94c6ab..4d0969d898e91 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -420,15 +420,6 @@ impl<'a> State<'a> { self.print_lifetime(lifetime)?; } } - hir::TyImplTraitExistential(hir_id, _def_id, ref _lifetimes) => { - match self.ann.try_fetch_item(hir_id.id).map(|it| &it.node) { - None => self.word_space("impl {{Trait}}")?, - Some(&hir::ItemExistential(ref exist_ty)) => { - self.print_bounds("impl", &exist_ty.bounds)?; - }, - other => bug!("impl Trait pointed to {:#?}", other), - } - } hir::TyArray(ref ty, ref length) => { self.s.word("[")?; self.print_type(&ty)?; diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 0c7baea85ad8f..dd19d59578fc1 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -340,7 +340,6 @@ impl_stable_hash_for!(enum hir::Ty_ { TyTup(ts), TyPath(qpath), TyTraitObject(trait_refs, lifetime), - TyImplTraitExistential(existty, def_id, lifetimes), TyTypeof(body_id), TyErr, TyInfer diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ed2b9c5068929..369f65c214aa1 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -625,122 +625,131 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |_, this| this.visit_ty(&mt.ty)); } - hir::TyImplTraitExistential(item_id, _, ref lifetimes) => { - // Resolve the lifetimes that are applied to the existential type. - // These are resolved in the current scope. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `fn foo<'a>() -> MyAnonTy<'a> { ... }` - // ^ ^this gets resolved in the current scope - for lifetime in lifetimes { - self.visit_lifetime(lifetime); - - // Check for predicates like `impl for<'a> SomeTrait>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.id).cloned(); - if let Some(Region::LateBound(_, def_id, _)) = def { - if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { - // Ensure that the parent of the def is an item, not HRTB - let parent_id = self.tcx.hir.get_parent_node(node_id); - let parent_impl_id = hir::ImplItemId { node_id: parent_id }; - let parent_trait_id = hir::TraitItemId { node_id: parent_id }; - let krate = self.tcx.hir.forest.krate(); - if !(krate.items.contains_key(&parent_id) - || krate.impl_items.contains_key(&parent_impl_id) - || krate.trait_items.contains_key(&parent_trait_id)) - { - span_err!( - self.tcx.sess, - lifetime.span, - E0657, - "`impl Trait` can only capture lifetimes \ - bound at the fn or impl level" - ); - self.uninsert_lifetime_on_error(lifetime, def.unwrap()); + hir::TyPath(hir::QPath::Resolved(None, ref path)) => { + if let Def::Existential(exist_ty_did) = path.def { + assert!(exist_ty_did.is_local()); + // Resolve the lifetimes that are applied to the existential type. + // These are resolved in the current scope. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `fn foo<'a>() -> MyAnonTy<'a> { ... }` + // ^ ^this gets resolved in the current scope + for lifetime in &path.segments[0].args.as_ref().unwrap().args { + if let hir::GenericArg::Lifetime(lifetime) = lifetime { + self.visit_lifetime(lifetime); + + // Check for predicates like `impl for<'a> Trait>` + // and ban them. Type variables instantiated inside binders aren't + // well-supported at the moment, so this doesn't work. + // In the future, this should be fixed and this error should be removed. + let def = self.map.defs.get(&lifetime.id).cloned(); + if let Some(Region::LateBound(_, def_id, _)) = def { + if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { + // Ensure that the parent of the def is an item, not HRTB + let parent_id = self.tcx.hir.get_parent_node(node_id); + let parent_impl_id = hir::ImplItemId { node_id: parent_id }; + let parent_trait_id = hir::TraitItemId { node_id: parent_id }; + let krate = self.tcx.hir.forest.krate(); + if !(krate.items.contains_key(&parent_id) + || krate.impl_items.contains_key(&parent_impl_id) + || krate.trait_items.contains_key(&parent_trait_id)) + { + span_err!( + self.tcx.sess, + lifetime.span, + E0657, + "`impl Trait` can only capture lifetimes \ + bound at the fn or impl level" + ); + self.uninsert_lifetime_on_error(lifetime, def.unwrap()); + } + } } } } - } - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `abstract type MyAnonTy<'b>: MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the exist_ty generics - let (generics, bounds) = match self.tcx.hir.expect_item(item_id.id).node { - hir::ItemExistential(hir::ExistTy{ ref generics, ref bounds, .. }) => ( - generics, - bounds, - ), - ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i), - }; + let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap(); + + // Resolve the lifetimes in the bounds to the lifetime defs in the generics. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `abstract type MyAnonTy<'b>: MyTrait<'b>;` + // ^ ^ this gets resolved in the scope of + // the exist_ty generics + let (generics, bounds) = match self.tcx.hir.expect_item(id).node { + hir::ItemExistential(hir::ExistTy{ ref generics, ref bounds, .. }) => ( + generics, + bounds, + ), + ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i), + }; - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut index = self.next_early_index_for_abstract_type(); - debug!("visit_ty: index = {}", index); + // We want to start our early-bound indices at the end of the parent scope, + // not including any parent `impl Trait`s. + let mut index = self.next_early_index_for_abstract_type(); + debug!("visit_ty: index = {}", index); - let mut elision = None; - let mut lifetimes = FxHashMap(); - let mut type_count = 0; - for param in &generics.params { - match param.kind { - GenericParamKind::Lifetime { .. } => { - let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m); - if let hir::ParamName::Plain(param_name) = name { - if param_name.name == keywords::UnderscoreLifetime.name() { - // Pick the elided lifetime "definition" if one exists - // and use it to make an elision scope. - elision = Some(reg); + let mut elision = None; + let mut lifetimes = FxHashMap(); + let mut type_count = 0; + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => { + let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m); + if let hir::ParamName::Plain(param_name) = name { + if param_name.name == keywords::UnderscoreLifetime.name() { + // Pick the elided lifetime "definition" if one exists + // and use it to make an elision scope. + elision = Some(reg); + } else { + lifetimes.insert(name, reg); + } } else { lifetimes.insert(name, reg); } - } else { - lifetimes.insert(name, reg); } - } - GenericParamKind::Type { .. } => { - type_count += 1; + GenericParamKind::Type { .. } => { + type_count += 1; + } } } - } - let next_early_index = index + type_count; + let next_early_index = index + type_count; - if let Some(elision_region) = elision { - let scope = Scope::Elision { - elide: Elide::Exact(elision_region), - s: self.scope, - }; - self.with(scope, |_old_scope, this| { + if let Some(elision_region) = elision { + let scope = Scope::Elision { + elide: Elide::Exact(elision_region), + s: self.scope, + }; + self.with(scope, |_old_scope, this| { + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: this.scope, + track_lifetime_uses: true, + abstract_type_parent: false, + }; + this.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + }); + } else { let scope = Scope::Binder { lifetimes, next_early_index, - s: this.scope, + s: self.scope, track_lifetime_uses: true, abstract_type_parent: false, }; - this.with(scope, |_old_scope, this| { + self.with(scope, |_old_scope, this| { this.visit_generics(generics); for bound in bounds { this.visit_param_bound(bound); } }); - }); + } } else { - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - track_lifetime_uses: true, - abstract_type_parent: false, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); + intravisit::walk_ty(self, ty) } } _ => intravisit::walk_ty(self, ty), diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index c55d57cb91631..3919ba13076f6 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -229,8 +229,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemUse(..) => {} // The interface is empty hir::ItemGlobalAsm(..) => {} - // Checked by visit_ty - hir::ItemExistential(..) => {} + hir::ItemExistential(..) => { + if item_level.is_some() { + // Reach the (potentially private) type and the API being exposed + self.reach(item.id).ty().predicates(); + } + } // Visit everything hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { @@ -390,17 +394,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { module_id = self.tcx.hir.get_parent_node(module_id); } } - - fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyImplTraitExistential(item_id, _, _) = ty.node { - if self.get(item_id.id).is_some() { - // Reach the (potentially private) type and the API being exposed - self.reach(item_id.id).ty().predicates(); - } - } - - intravisit::walk_ty(self, ty); - } } impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { @@ -1568,8 +1561,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> hir::ItemUse(..) => {} // No subitems hir::ItemGlobalAsm(..) => {} - // Checked in visit_ty - hir::ItemExistential(..) => {} + hir::ItemExistential(..) => { + // Check the traits being exposed, as they're separate, + // e.g. `impl Iterator` has two predicates, + // `X: Iterator` and `::Item == T`, + // where `X` is the `impl Iterator` itself, + // stored in `predicates_of`, not in the `Ty` itself. + + self.check(item.id, self.inner_visibility).predicates(); + } // Subitems of these items have inherited publicity hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { @@ -1667,20 +1667,6 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> // handled in `visit_item` above } - fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyImplTraitExistential(ref exist_item, _, _) = ty.node { - // Check the traits being exposed, as they're separate, - // e.g. `impl Iterator` has two predicates, - // `X: Iterator` and `::Item == T`, - // where `X` is the `impl Iterator` itself, - // stored in `predicates_of`, not in the `Ty` itself. - - self.check(exist_item.id, self.inner_visibility).predicates(); - } - - intravisit::walk_ty(self, ty); - } - // Don't recurse into expressions in array sizes or const initializers fn visit_expr(&mut self, _: &'tcx hir::Expr) {} // Don't recurse into patterns in function arguments diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 762dc5d26f5a4..2e467d315bedd 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1095,6 +1095,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyStr => tcx.mk_str() } } + Def::Existential(exist_ty_did) => { + assert!(exist_ty_did.is_local()); + let lifetimes = &path.segments[0].args.as_ref().unwrap().args; + self.impl_trait_ty_to_ty(exist_ty_did, lifetimes) + } Def::Err => { self.set_tainted_by_errors(); return self.tcx().types.err; @@ -1140,9 +1145,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyTraitObject(ref bounds, ref lifetime) => { self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) } - hir::TyImplTraitExistential(_, def_id, ref lifetimes) => { - self.impl_trait_ty_to_ty(def_id, lifetimes) - } hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); let opt_self_ty = maybe_qself.as_ref().map(|qself| { @@ -1195,7 +1197,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn impl_trait_ty_to_ty( &self, def_id: DefId, - lifetimes: &[hir::Lifetime], + lifetimes: &[hir::GenericArg], ) -> Ty<'tcx> { debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); let tcx = self.tcx(); @@ -1208,7 +1210,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Our own parameters are the resolved lifetimes. match param.kind { GenericParamDefKind::Lifetime => { - self.ast_region_to_region(&lifetimes[i], None).into() + if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { + self.ast_region_to_region(lifetime, None).into() + } else { + bug!() + } } _ => bug!() } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 852603ac51c35..4931cbfa5acc3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -875,10 +875,6 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(..), .. }) => { - bug!("impl Trait is desugared to existential type items"); - } - _ => &no_generics, }; From 75a6fde6a49b7e497163c9a415b147cec26cbc56 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 Jul 2018 10:37:49 +0200 Subject: [PATCH 09/23] Update rustdoc --- src/librustdoc/clean/mod.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b8abb98edec48..f71d62d5a04e1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2987,14 +2987,6 @@ impl Clean for hir::Ty { } } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), - TyImplTraitExistential(hir_id, _, _) => { - match cx.tcx.hir.expect_item(hir_id.id).node { - hir::ItemExistential(ref exist_ty) => { - ImplTrait(exist_ty.bounds.clean(cx)) - }, - ref other => panic!("impl Trait pointed to {:#?}", other), - } - }, TyInfer | TyErr => Infer, TyTypeof(..) => panic!("Unimplemented type {:?}", self.node), } From ea806e78155864e5e19c6b78e40810d3ce9a7719 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Fri, 8 Jun 2018 03:47:26 +0100 Subject: [PATCH 10/23] Removed `uninitialized_statics` field from `Memory` struct in miri. Refactored code accordingly. --- src/librustc_mir/interpret/const_eval.rs | 12 +- src/librustc_mir/interpret/eval_context.rs | 14 +-- src/librustc_mir/interpret/memory.rs | 124 ++++++++------------- src/librustc_mir/interpret/traits.rs | 7 +- 4 files changed, 64 insertions(+), 93 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 749c0d04ae91f..ea09bab5d1411 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -1,3 +1,6 @@ +use std::fmt; +use std::error::Error; + use rustc::hir; use rustc::mir::interpret::{ConstEvalErr}; use rustc::mir; @@ -15,9 +18,6 @@ use rustc::mir::interpret::{ }; use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind}; -use std::fmt; -use std::error::Error; - pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, @@ -152,7 +152,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>( let ptr = ecx.memory.allocate( layout.size, layout.align, - None, + MemoryKind::Stack, )?; let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); let is_static = tcx.is_static(cid.instance.def_id()); @@ -486,7 +486,7 @@ pub fn const_variant_index<'a, 'tcx>( let (ptr, align) = match value { Value::ScalarPair(..) | Value::Scalar(_) => { let layout = ecx.layout_of(val.ty)?; - let ptr = ecx.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))?.into(); + let ptr = ecx.memory.allocate(layout.size, layout.align, MemoryKind::Stack)?.into(); ecx.write_value_to_ptr(value, ptr, layout.align, val.ty)?; (ptr, layout.align) }, @@ -515,7 +515,7 @@ pub fn const_value_to_allocation_provider<'a, 'tcx>( ()); let value = ecx.const_to_value(val.val)?; let layout = ecx.layout_of(val.ty)?; - let ptr = ecx.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))?; + let ptr = ecx.memory.allocate(layout.size, layout.align, MemoryKind::Stack)?; ecx.write_value_to_ptr(value, ptr.into(), layout.align, val.ty)?; let alloc = ecx.memory.get(ptr.alloc_id)?; Ok(tcx.intern_const_alloc(alloc.clone())) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 15d8b9c36215a..031c75013a27b 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1,4 +1,5 @@ use std::fmt::Write; +use std::mem; use rustc::hir::def_id::DefId; use rustc::hir::def::Def; @@ -9,14 +10,13 @@ use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt, TypeAndMut}; use rustc::ty::query::TyCtxtAt; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use rustc::mir::interpret::FrameInfo; -use syntax::codemap::{self, Span}; -use syntax::ast::Mutability; use rustc::mir::interpret::{ - GlobalId, Value, Scalar, + FrameInfo, GlobalId, Value, Scalar, EvalResult, EvalErrorKind, Pointer, ConstValue, }; -use std::mem; + +use syntax::codemap::{self, Span}; +use syntax::ast::Mutability; use super::{Place, PlaceExtra, Memory, HasMemory, MemoryKind, @@ -206,7 +206,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "cannot alloc memory for unsized type"); - self.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack)) + self.memory.allocate(layout.size, layout.align, MemoryKind::Stack) } pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> { @@ -246,7 +246,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } ConstValue::ByRef(alloc, offset) => { // FIXME: Allocate new AllocId for all constants inside - let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?; + let id = self.memory.allocate_value(alloc.clone(), MemoryKind::Stack)?; Ok(Value::ByRef(Pointer::new(id, offset).into(), alloc.align)) }, ConstValue::ScalarPair(a, b) => Ok(Value::ScalarPair(a, b)), diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index f5da65ae44db7..5cf734cce8a3f 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -6,12 +6,12 @@ use rustc::ty::Instance; use rustc::ty::ParamEnv; use rustc::ty::query::TyCtxtAt; use rustc::ty::layout::{self, Align, TargetDataLayout, Size}; -use syntax::ast::Mutability; - -use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc::mir::interpret::{Pointer, AllocId, Allocation, AccessKind, Value, EvalResult, Scalar, EvalErrorKind, GlobalId, AllocType}; pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint}; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; + +use syntax::ast::Mutability; use super::{EvalContext, Machine}; @@ -41,11 +41,6 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations). alloc_map: FxHashMap, - /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations). - /// - /// Stores statics while they are being processed, before they are interned and thus frozen - uninitialized_statics: FxHashMap, - /// The current stack frame. Used to check accesses against locks. pub cur_frame: usize, @@ -58,7 +53,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { data, alloc_kind: FxHashMap::default(), alloc_map: FxHashMap::default(), - uninitialized_statics: FxHashMap::default(), tcx, cur_frame: usize::max_value(), } @@ -82,20 +76,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn allocate_value( &mut self, alloc: Allocation, - kind: Option>, + kind: MemoryKind, ) -> EvalResult<'tcx, AllocId> { let id = self.tcx.alloc_map.lock().reserve(); M::add_lock(self, id); - match kind { - Some(kind @ MemoryKind::Stack) | - Some(kind @ MemoryKind::Machine(_)) => { - self.alloc_map.insert(id, alloc); - self.alloc_kind.insert(id, kind); - }, - None => { - self.uninitialized_statics.insert(id, alloc); - }, - } + self.alloc_map.insert(id, alloc); + self.alloc_kind.insert(id, kind); Ok(id) } @@ -104,7 +90,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { &mut self, size: Size, align: Align, - kind: Option>, + kind: MemoryKind, ) -> EvalResult<'tcx, Pointer> { self.allocate_value(Allocation::undef(size, align), kind).map(Pointer::from) } @@ -132,7 +118,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc" - let new_ptr = self.allocate(new_size, new_align, Some(kind))?; + let new_ptr = self.allocate(new_size, new_align, kind)?; self.copy( ptr.into(), old_align, @@ -168,12 +154,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { let alloc = match self.alloc_map.remove(&ptr.alloc_id) { Some(alloc) => alloc, - None => if self.uninitialized_statics.contains_key(&ptr.alloc_id) { - return err!(DeallocatedWrongMemoryKind( - "uninitializedstatic".to_string(), - format!("{:?}", kind), - )) - } else { + None => { return match self.tcx.alloc_map.lock().get(ptr.alloc_id) { Some(AllocType::Function(..)) => err!(DeallocatedWrongMemoryKind( "function".to_string(), @@ -299,24 +280,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> { // normal alloc? match self.alloc_map.get(&id) { - Some(alloc) => Ok(alloc), + Some(alloc) => Ok(alloc), // uninitialized static alloc? - None => match self.uninitialized_statics.get(&id) { - Some(alloc) => Ok(alloc), - None => { - // static alloc? - let alloc = self.tcx.alloc_map.lock().get(id); - match alloc { - Some(AllocType::Memory(mem)) => Ok(mem), - Some(AllocType::Function(..)) => { - Err(EvalErrorKind::DerefFunctionPointer.into()) - } - Some(AllocType::Static(did)) => { - self.const_eval_static(did) - } - None => Err(EvalErrorKind::DanglingPointerDeref.into()), + None => { + // static alloc? + let alloc = self.tcx.alloc_map.lock().get(id); + match alloc { + Some(AllocType::Memory(mem)) => Ok(mem), + Some(AllocType::Function(..)) => { + Err(EvalErrorKind::DerefFunctionPointer.into()) + } + Some(AllocType::Static(did)) => { + self.const_eval_static(did) } - }, + None => Err(EvalErrorKind::DanglingPointerDeref.into()), + } }, } } @@ -329,17 +307,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { match self.alloc_map.get_mut(&id) { Some(alloc) => Ok(alloc), // uninitialized static alloc? - None => match self.uninitialized_statics.get_mut(&id) { - Some(alloc) => Ok(alloc), - None => { - // no alloc or immutable alloc? produce an error - match self.tcx.alloc_map.lock().get(id) { - Some(AllocType::Memory(..)) | - Some(AllocType::Static(..)) => err!(ModifiedConstantMemory), - Some(AllocType::Function(..)) => err!(DerefFunctionPointer), - None => err!(DanglingPointerDeref), - } - }, + None => { + // no alloc or immutable alloc? produce an error + match self.tcx.alloc_map.lock().get(id) { + Some(AllocType::Memory(..)) | + Some(AllocType::Static(..)) => err!(ModifiedConstantMemory), + Some(AllocType::Function(..)) => err!(DerefFunctionPointer), + None => err!(DanglingPointerDeref), + } }, } } @@ -390,27 +365,23 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { MemoryKind::Stack => " (stack)".to_owned(), MemoryKind::Machine(m) => format!(" ({:?})", m), }), - // uninitialized static alloc? - None => match self.uninitialized_statics.get(&id) { - Some(a) => (a, " (static in the process of initialization)".to_owned()), - None => { - // static alloc? - match self.tcx.alloc_map.lock().get(id) { - Some(AllocType::Memory(a)) => (a, "(immutable)".to_owned()), - Some(AllocType::Function(func)) => { - trace!("{} {}", msg, func); - continue; - } - Some(AllocType::Static(did)) => { - trace!("{} {:?}", msg, did); - continue; - } - None => { - trace!("{} (deallocated)", msg); - continue; - } + None => { + // static alloc? + match self.tcx.alloc_map.lock().get(id) { + Some(AllocType::Memory(a)) => (a, "(immutable)".to_owned()), + Some(AllocType::Function(func)) => { + trace!("{} {}", msg, func); + continue; } - }, + Some(AllocType::Static(did)) => { + trace!("{} {:?}", msg, did); + continue; + } + None => { + trace!("{} (deallocated)", msg); + continue; + } + } }, }; @@ -569,8 +540,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { Some(MemoryKind::Machine(_)) => bug!("machine didn't handle machine alloc"), Some(MemoryKind::Stack) => {}, } - let uninit = self.uninitialized_statics.remove(&alloc_id); - if let Some(mut alloc) = alloc.or(uninit) { + if let Some(mut alloc) = alloc { // ensure llvm knows not to put this into immutable memroy alloc.runtime_mutability = mutability; let alloc = self.tcx.intern_const_alloc(alloc); diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 373a0b0d0bfed..b6c7feda19fa8 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,9 +1,10 @@ use rustc::ty::{self, Ty}; use rustc::ty::layout::{Size, Align, LayoutOf}; +use rustc::mir::interpret::{Scalar, Value, Pointer, EvalResult}; + use syntax::ast::Mutability; -use rustc::mir::interpret::{Scalar, Value, Pointer, EvalResult}; -use super::{EvalContext, Machine}; +use super::{EvalContext, Machine, MemoryKind}; impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -30,7 +31,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let vtable = self.memory.allocate( ptr_size * (3 + methods.len() as u64), ptr_align, - None, + MemoryKind::Stack, )?; let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty); From 73166f751b7509dd95ce903ecdeab2dd5d89aa90 Mon Sep 17 00:00:00 2001 From: Dror Levin Date: Mon, 2 Jul 2018 17:38:15 +0300 Subject: [PATCH 11/23] Fill in tracking issue number for read_exact_at/write_all_at --- src/libstd/sys/unix/ext/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 4c2cea0d32c35..507e9d881717b 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -109,7 +109,7 @@ pub trait FileExt { /// Ok(()) /// } /// ``` - #[unstable(feature = "rw_exact_all_at", issue = "0")] + #[unstable(feature = "rw_exact_all_at", issue = "51984")] fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { match self.read_at(buf, offset) { @@ -204,7 +204,7 @@ pub trait FileExt { /// Ok(()) /// } /// ``` - #[unstable(feature = "rw_exact_all_at", issue = "0")] + #[unstable(feature = "rw_exact_all_at", issue = "51984")] fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { match self.write_at(buf, offset) { From 59f2edbf1adfea256216cb7fb65d291d324ea857 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Feb 2018 10:26:48 -0500 Subject: [PATCH 12/23] add outlives annotations to `BTreeMap` nll requires these annotations, I believe because of https://github.com/rust-lang/rust/issues/29149 --- src/liballoc/collections/btree/map.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 2aad3149bb211..8c950cd06d9e3 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -149,12 +149,11 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for BTreeMap { fn clone(&self) -> BTreeMap { - fn clone_subtree(node: node::NodeRef) - -> BTreeMap { - + fn clone_subtree<'a, K: Clone, V: Clone>( + node: node::NodeRef, K, V, marker::LeafOrInternal> + ) -> BTreeMap + where K: 'a, V: 'a, + { match node.force() { Leaf(leaf) => { let mut out_tree = BTreeMap { @@ -1080,7 +1079,11 @@ impl BTreeMap { /// Calculates the number of elements if it is incorrect. fn recalc_length(&mut self) { - fn dfs(node: NodeRef) -> usize { + fn dfs<'a, K, V>( + node: NodeRef, K, V, marker::LeafOrInternal> + ) -> usize + where K: 'a, V: 'a + { let mut res = node.len(); if let Internal(node) = node.force() { From 6660c25045ec198d80ada12e621634e22d1da619 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 2 Jul 2018 17:18:38 +0100 Subject: [PATCH 13/23] Updated miri submodule. --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 9143a69f4b3ef..5b7bb32b0e46d 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 9143a69f4b3ef4bda77afddefe934be363e39f31 +Subproject commit 5b7bb32b0e46d195b80c4da09b560ac7fc92015d From ddc1d294429e39cbc0b2b9e883b46592f896f412 Mon Sep 17 00:00:00 2001 From: Nikolai Merinov Date: Mon, 2 Jul 2018 01:45:35 +0500 Subject: [PATCH 14/23] bootstrap: tests should use rustc from config.toml Tests should always use "rustc" and "cargo" from config.toml instead of assuming that stage0 binaries was downloaded to build directory. --- src/bootstrap/bootstrap.py | 2 ++ src/bootstrap/config.rs | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index a94792a2f9f59..512d4d8c5b792 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -816,6 +816,8 @@ def bootstrap(help_triggered): env["BOOTSTRAP_PYTHON"] = sys.executable env["BUILD_DIR"] = build.build_dir env["RUSTC_BOOTSTRAP"] = '1' + env["CARGO"] = build.cargo() + env["RUSTC"] = build.rustc() run(args, env=env, verbose=build.verbose) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e4d467c927245..b3ed10257bdac 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,7 +23,6 @@ use std::cmp; use num_cpus; use toml; -use util::exe; use cache::{INTERNER, Interned}; use flags::Flags; pub use flags::Subcommand; @@ -367,9 +366,8 @@ impl Config { config.src = Config::path_from_python("SRC"); config.out = Config::path_from_python("BUILD_DIR"); - let stage0_root = config.out.join(&config.build).join("stage0/bin"); - config.initial_rustc = stage0_root.join(exe("rustc", &config.build)); - config.initial_cargo = stage0_root.join(exe("cargo", &config.build)); + config.initial_rustc = Config::path_from_python("RUSTC"); + config.initial_cargo = Config::path_from_python("CARGO"); config } From c6bbee802abb174243fac490782baa680e4f67b4 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 17:23:48 +0100 Subject: [PATCH 15/23] Fix a bug with return in anonymous consts --- src/librustc_typeck/check/writeback.rs | 12 +++++------- src/test/ui/issue-51714.rs | 5 +++++ src/test/ui/issue-51714.stderr | 8 +++++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f7d1e40794580..2445cae98607a 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -257,13 +257,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { fn visit_pat(&mut self, p: &'gcx hir::Pat) { match p.node { hir::PatKind::Binding(..) => { - let bm = *self.fcx - .tables - .borrow() - .pat_binding_modes() - .get(p.hir_id) - .expect("missing binding mode"); - self.tables.pat_binding_modes_mut().insert(p.hir_id, bm); + if let Some(&bm) = self.fcx.tables.borrow().pat_binding_modes().get(p.hir_id) { + self.tables.pat_binding_modes_mut().insert(p.hir_id, bm); + } else { + self.tcx().sess.delay_span_bug(p.span, "missing binding mode"); + } } hir::PatKind::Struct(_, ref fields, _) => { for field in fields { diff --git a/src/test/ui/issue-51714.rs b/src/test/ui/issue-51714.rs index 96c5b92ddfdcc..c0e62dcc9cefe 100644 --- a/src/test/ui/issue-51714.rs +++ b/src/test/ui/issue-51714.rs @@ -17,3 +17,8 @@ fn foo() { [(); return || {}]; //~^ ERROR return statement outside of function body } + +fn bar() { + [(); return |ice| {}]; + //~^ ERROR return statement outside of function body +} diff --git a/src/test/ui/issue-51714.stderr b/src/test/ui/issue-51714.stderr index 746adea6b7ed7..3e61df8062d1d 100644 --- a/src/test/ui/issue-51714.stderr +++ b/src/test/ui/issue-51714.stderr @@ -10,6 +10,12 @@ error[E0572]: return statement outside of function body LL | [(); return || {}]; | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0572]: return statement outside of function body + --> $DIR/issue-51714.rs:22:10 + | +LL | [(); return |ice| {}]; + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0572`. From 7ad1c62d38294e145aa65425a08b5accac121cd3 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 17:24:07 +0100 Subject: [PATCH 16/23] Fix an ICE using break and continue as array lengths --- src/librustc_driver/driver.rs | 1 + src/librustc_mir/build/scope.rs | 6 +++--- src/librustc_passes/loops.rs | 7 ++++++- src/test/ui/array-break-length.rs | 19 +++++++++++++++++++ src/test/ui/array-break-length.stderr | 15 +++++++++++++++ src/test/ui/closure-array-break-length.rs | 2 ++ src/test/ui/closure-array-break-length.stderr | 16 ++++++++++++++-- 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/array-break-length.rs create mode 100644 src/test/ui/array-break-length.stderr diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index feeac9d938b6a..c4e196628915b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1211,6 +1211,7 @@ where .set(derive_registrar::find(&hir_map)); time(sess, "loop checking", || loops::check_crate(sess, &hir_map)); + sess.abort_if_errors(); let mut local_providers = ty::query::Providers::default(); default_provide(&mut local_providers); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index b9d6486d9174a..502091e519201 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -541,9 +541,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Finds the breakable scope for a given label. This is used for /// resolving `break` and `continue`. pub fn find_breakable_scope(&self, - span: Span, - label: region::Scope) - -> &BreakableScope<'tcx> { + span: Span, + label: region::Scope) + -> &BreakableScope<'tcx> { // find the loop-scope with the correct id self.breakable_scopes.iter() .rev() diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index c99f1e9da439f..898acf48d3df8 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -40,6 +40,7 @@ enum Context { Loop(LoopKind), Closure, LabeledBlock, + AnonConst, } #[derive(Copy, Clone)] @@ -71,6 +72,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Normal, |v| intravisit::walk_impl_item(v, i)); } + fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) { + self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c)); + } + fn visit_expr(&mut self, e: &'hir hir::Expr) { match e.node { hir::ExprWhile(ref e, ref b, _) => { @@ -194,7 +199,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { .span_label(span, "cannot break inside of a closure") .emit(); } - Normal => { + Normal | AnonConst => { struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name) .span_label(span, "cannot break outside of a loop") .emit(); diff --git a/src/test/ui/array-break-length.rs b/src/test/ui/array-break-length.rs new file mode 100644 index 0000000000000..c3cfff0e1f642 --- /dev/null +++ b/src/test/ui/array-break-length.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + loop { + |_: [_; break]| {} //~ ERROR: `break` outside of loop + } + + loop { + |_: [_; continue]| {} //~ ERROR: `continue` outside of loop + } +} diff --git a/src/test/ui/array-break-length.stderr b/src/test/ui/array-break-length.stderr new file mode 100644 index 0000000000000..114245b9cc77b --- /dev/null +++ b/src/test/ui/array-break-length.stderr @@ -0,0 +1,15 @@ +error[E0268]: `break` outside of loop + --> $DIR/array-break-length.rs:13:17 + | +LL | |_: [_; break]| {} //~ ERROR: `break` outside of loop + | ^^^^^ cannot break outside of a loop + +error[E0268]: `continue` outside of loop + --> $DIR/array-break-length.rs:17:17 + | +LL | |_: [_; continue]| {} //~ ERROR: `continue` outside of loop + | ^^^^^^^^ cannot break outside of a loop + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0268`. diff --git a/src/test/ui/closure-array-break-length.rs b/src/test/ui/closure-array-break-length.rs index 2e99921956ab2..727113e328fef 100644 --- a/src/test/ui/closure-array-break-length.rs +++ b/src/test/ui/closure-array-break-length.rs @@ -12,6 +12,8 @@ fn main() { |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label + //~^ ERROR: `continue` outside of loop while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label + //~^ ERROR: `break` outside of loop } diff --git a/src/test/ui/closure-array-break-length.stderr b/src/test/ui/closure-array-break-length.stderr index 139153992e274..a337645fb7e8f 100644 --- a/src/test/ui/closure-array-break-length.stderr +++ b/src/test/ui/closure-array-break-length.stderr @@ -10,13 +10,25 @@ error[E0590]: `break` or `continue` with no label in the condition of a `while` LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop +error[E0268]: `continue` outside of loop + --> $DIR/closure-array-break-length.rs:14:19 + | +LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label + | ^^^^^^^^ cannot break outside of a loop + error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/closure-array-break-length.rs:16:19 + --> $DIR/closure-array-break-length.rs:17:19 | LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label | ^^^^^ unlabeled `break` in the condition of a `while` loop -error: aborting due to 3 previous errors +error[E0268]: `break` outside of loop + --> $DIR/closure-array-break-length.rs:17:19 + | +LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label + | ^^^^^ cannot break outside of a loop + +error: aborting due to 5 previous errors Some errors occurred: E0268, E0590. For more information about an error, try `rustc --explain E0268`. From 998141f8ef8225704f8641ef0372c686bcbd2c5f Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 17:40:36 +0100 Subject: [PATCH 17/23] Fix another return-const ICE --- src/librustc_mir/hair/pattern/check_match.rs | 51 ++++++++++---------- src/test/ui/issue-51714.rs | 9 ++-- src/test/ui/issue-51714.stderr | 14 ++++-- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index e04cdcfa02773..a7806131f2c89 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -309,33 +309,32 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) { pat.walk(|p| { if let PatKind::Binding(_, _, ident, None) = p.node { - let bm = *cx.tables - .pat_binding_modes() - .get(p.hir_id) - .expect("missing binding mode"); - - if bm != ty::BindByValue(hir::MutImmutable) { - // Nothing to check. - return true; - } - let pat_ty = cx.tables.pat_ty(p); - if let ty::TyAdt(edef, _) = pat_ty.sty { - if edef.is_enum() && edef.variants.iter().any(|variant| { - variant.name == ident.name && variant.ctor_kind == CtorKind::Const - }) { - let ty_path = cx.tcx.item_path_str(edef.did); - let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, - "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", - ident, ty_path); - err.span_suggestion_with_applicability( - p.span, - "to match on the variant, qualify the path", - format!("{}::{}", ty_path, ident), - Applicability::MachineApplicable - ); - err.emit(); + if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { + if bm != ty::BindByValue(hir::MutImmutable) { + // Nothing to check. + return true; + } + let pat_ty = cx.tables.pat_ty(p); + if let ty::TyAdt(edef, _) = pat_ty.sty { + if edef.is_enum() && edef.variants.iter().any(|variant| { + variant.name == ident.name && variant.ctor_kind == CtorKind::Const + }) { + let ty_path = cx.tcx.item_path_str(edef.did); + let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, + "pattern binding `{}` is named the same as one \ + of the variants of the type `{}`", + ident, ty_path); + err.span_suggestion_with_applicability( + p.span, + "to match on the variant, qualify the path", + format!("{}::{}", ty_path, ident), + Applicability::MachineApplicable + ); + err.emit(); + } } + } else { + cx.tcx.sess.delay_span_bug(p.span, "missing binding mode"); } } true diff --git a/src/test/ui/issue-51714.rs b/src/test/ui/issue-51714.rs index c0e62dcc9cefe..f8d12b991eaef 100644 --- a/src/test/ui/issue-51714.rs +++ b/src/test/ui/issue-51714.rs @@ -9,16 +9,15 @@ // except according to those terms. fn main() { - |_: [_; return || {}] | {} + |_: [_; return || {}] | {}; //~^ ERROR return statement outside of function body -} -fn foo() { [(); return || {}]; //~^ ERROR return statement outside of function body -} -fn bar() { [(); return |ice| {}]; //~^ ERROR return statement outside of function body + + [(); return while let Some(n) = Some(0) {}]; + //~^ ERROR return statement outside of function body } diff --git a/src/test/ui/issue-51714.stderr b/src/test/ui/issue-51714.stderr index 3e61df8062d1d..c8764564dca38 100644 --- a/src/test/ui/issue-51714.stderr +++ b/src/test/ui/issue-51714.stderr @@ -1,21 +1,27 @@ error[E0572]: return statement outside of function body --> $DIR/issue-51714.rs:12:14 | -LL | |_: [_; return || {}] | {} +LL | |_: [_; return || {}] | {}; | ^^^^^^^^^^^^ error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:17:10 + --> $DIR/issue-51714.rs:15:10 | LL | [(); return || {}]; | ^^^^^^^^^^^^ error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:22:10 + --> $DIR/issue-51714.rs:18:10 | LL | [(); return |ice| {}]; | ^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0572]: return statement outside of function body + --> $DIR/issue-51714.rs:21:10 + | +LL | [(); return while let Some(n) = Some(0) {}]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0572`. From b00050f4cf7d602566afd511b66ae6645f92987d Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 17:56:06 +0100 Subject: [PATCH 18/23] Add more safeguards to "missing binding mode" errors --- src/librustc/middle/expr_use_visitor.rs | 53 +++++++++++--------- src/librustc_borrowck/borrowck/unused.rs | 18 +++---- src/librustc_mir/build/mod.rs | 13 ++--- src/librustc_mir/hair/pattern/check_match.rs | 32 ++++++------ src/librustc_typeck/check/regionck.rs | 12 +++-- 5 files changed, 67 insertions(+), 61 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 6ccf09f4dfc4f..a83aa47fd4f13 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -840,6 +840,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) { debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat); + let tcx = self.tcx(); let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.node { @@ -849,34 +850,36 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pat, match_mode, ); - let bm = *mc.tables.pat_binding_modes().get(pat.hir_id) - .expect("missing binding mode"); - debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); - - // pat_ty: the type of the binding being produced. - let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); - debug!("walk_pat: pat_ty={:?}", pat_ty); - - // Each match binding is effectively an assignment to the - // binding being produced. - let def = Def::Local(canonical_id); - if let Ok(ref binding_cmt) = mc.cat_def(pat.hir_id, pat.span, pat_ty, def) { - delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); - } + if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) { + debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); + + // pat_ty: the type of the binding being produced. + let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); + debug!("walk_pat: pat_ty={:?}", pat_ty); + + // Each match binding is effectively an assignment to the + // binding being produced. + let def = Def::Local(canonical_id); + if let Ok(ref binding_cmt) = mc.cat_def(pat.hir_id, pat.span, pat_ty, def) { + delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); + } - // It is also a borrow or copy/move of the value being matched. - match bm { - ty::BindByReference(m) => { - if let ty::TyRef(r, _, _) = pat_ty.sty { - let bk = ty::BorrowKind::from_mutbl(m); - delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding); + // It is also a borrow or copy/move of the value being matched. + match bm { + ty::BindByReference(m) => { + if let ty::TyRef(r, _, _) = pat_ty.sty { + let bk = ty::BorrowKind::from_mutbl(m); + delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding); + } + } + ty::BindByValue(..) => { + let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); + debug!("walk_pat binding consuming pat"); + delegate.consume_pat(pat, &cmt_pat, mode); } } - ty::BindByValue(..) => { - let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); - debug!("walk_pat binding consuming pat"); - delegate.consume_pat(pat, &cmt_pat, mode); - } + } else { + tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } } })); diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs index 294ae1e63a9ee..475ff0b744349 100644 --- a/src/librustc_borrowck/borrowck/unused.rs +++ b/src/librustc_borrowck/borrowck/unused.rs @@ -54,16 +54,16 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { // Skip anything that looks like `&foo` or `&mut foo`, only look // for by-value bindings - let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) { - Some(&bm) => bm, - None => span_bug!(span, "missing binding mode"), - }; - match bm { - ty::BindByValue(hir::MutMutable) => {} - _ => return, + if let Some(&bm) = self.bccx.tables.pat_binding_modes().get(hir_id) { + match bm { + ty::BindByValue(hir::MutMutable) => {} + _ => return, + } + + mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span)); + } else { + tcx.sess.delay_span_bug(span, "missing binding mode"); } - - mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span)); }); } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 4db5c8e9278e5..cdf0079e2ae83 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -541,13 +541,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, if let hir::PatKind::Binding(_, _, ident, _) = pat.node { decl.debug_name = ident.name; - let bm = *hir.tables.pat_binding_modes() - .get(pat.hir_id) - .expect("missing binding mode"); - if bm == ty::BindByValue(hir::MutMutable) { - decl.mutability = Mutability::Mut; + if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) { + if bm == ty::BindByValue(hir::MutMutable) { + decl.mutability = Mutability::Mut; + } else { + decl.mutability = Mutability::Not; + } } else { - decl.mutability = Mutability::Not; + tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } } } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index a7806131f2c89..18ae7c7745915 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -516,12 +516,12 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, let mut by_ref_span = None; for pat in pats { pat.each_binding(|_, hir_id, span, _path| { - let bm = *cx.tables - .pat_binding_modes() - .get(hir_id) - .expect("missing binding mode"); - if let ty::BindByReference(..) = bm { - by_ref_span = Some(span); + if let Some(&bm) = cx.tables.pat_binding_modes().get(hir_id) { + if let ty::BindByReference(..) = bm { + by_ref_span = Some(span); + } + } else { + cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } }) } @@ -552,18 +552,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, for pat in pats { pat.walk(|p| { if let PatKind::Binding(_, _, _, ref sub) = p.node { - let bm = *cx.tables - .pat_binding_modes() - .get(p.hir_id) - .expect("missing binding mode"); - match bm { - ty::BindByValue(..) => { - let pat_ty = cx.tables.node_id_to_type(p.hir_id); - if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) { - check_move(p, sub.as_ref().map(|p| &**p)); + if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { + match bm { + ty::BindByValue(..) => { + let pat_ty = cx.tables.node_id_to_type(p.hir_id); + if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) { + check_move(p, sub.as_ref().map(|p| &**p)); + } } + _ => {} } - _ => {} + } else { + cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } } true diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e489c4d4a46be..68fcde0b1657a 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1039,11 +1039,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { match sub_pat.node { // `ref x` pattern PatKind::Binding(..) => { - let bm = *mc.tables.pat_binding_modes().get(sub_pat.hir_id) - .expect("missing binding mode"); - if let ty::BindByReference(mutbl) = bm { - self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id, - mutbl, &sub_cmt); + if let Some(&bm) = mc.tables.pat_binding_modes().get(sub_pat.hir_id) { + if let ty::BindByReference(mutbl) = bm { + self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id, + mutbl, &sub_cmt); + } + } else { + self.tcx.sess.delay_span_bug(sub_pat.span, "missing binding mode"); } } _ => {} From 30fde047804b6555ad982e7d55fea9e54815ea39 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 18:31:07 +0100 Subject: [PATCH 19/23] Clean up error messages regarding break/continue inside consts --- src/librustc/hir/lowering.rs | 60 +++++++++++-------- src/test/ui/closure-array-break-length.rs | 6 +- src/test/ui/closure-array-break-length.stderr | 23 ++----- 3 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e59e50ae9e698..2365bdda932fb 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -103,6 +103,7 @@ pub struct LoweringContext<'a> { loop_scopes: Vec, is_in_loop_condition: bool, is_in_trait_impl: bool, + is_in_anon_const: bool, /// What to do when we encounter either an "anonymous lifetime /// reference". The term "anonymous" is meant to encompass both @@ -230,6 +231,7 @@ pub fn lower_crate( node_id_to_hir_id: IndexVec::new(), is_generator: false, is_in_trait_impl: false, + is_in_anon_const: false, lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, in_scope_lifetimes: Vec::new(), @@ -968,31 +970,30 @@ impl<'a> LoweringContext<'a> { } fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination { - match destination { - Some((id, label)) => { - let target_id = if let Def::Label(loop_id) = self.expect_full_def(id) { - Ok(self.lower_node_id(loop_id).node_id) - } else { - Err(hir::LoopIdError::UnresolvedLabel) - }; - hir::Destination { - label: self.lower_label(Some(label)), - target_id, + let target_id = if self.is_in_anon_const { + Err(hir::LoopIdError::OutsideLoopScope) + } else { + match destination { + Some((id, _)) => { + if let Def::Label(loop_id) = self.expect_full_def(id) { + Ok(self.lower_node_id(loop_id).node_id) + } else { + Err(hir::LoopIdError::UnresolvedLabel) + } } - } - None => { - let target_id = self.loop_scopes - .last() - .map(|innermost_loop_id| *innermost_loop_id) - .map(|id| Ok(self.lower_node_id(id).node_id)) - .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) - .into(); - - hir::Destination { - label: None, - target_id, + None => { + self.loop_scopes + .last() + .map(|innermost_loop_id| *innermost_loop_id) + .map(|id| Ok(self.lower_node_id(id).node_id)) + .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) + .into() } } + }; + hir::Destination { + label: self.lower_label(destination.map(|(_, label)| label)), + target_id, } } @@ -3440,13 +3441,22 @@ impl<'a> LoweringContext<'a> { } fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst { - let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id); + let was_in_loop_condition = self.is_in_loop_condition; + self.is_in_loop_condition = false; + let was_in_anon_const = self.is_in_anon_const; + self.is_in_anon_const = true; - hir::AnonConst { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id); + let anon_const = hir::AnonConst { id: node_id, hir_id, body: self.lower_body(None, |this| this.lower_expr(&c.value)), - } + }; + + self.is_in_anon_const = was_in_anon_const; + self.is_in_loop_condition = was_in_loop_condition; + + anon_const } fn lower_expr(&mut self, e: &Expr) -> hir::Expr { diff --git a/src/test/ui/closure-array-break-length.rs b/src/test/ui/closure-array-break-length.rs index 727113e328fef..8be5b925a399e 100644 --- a/src/test/ui/closure-array-break-length.rs +++ b/src/test/ui/closure-array-break-length.rs @@ -11,9 +11,7 @@ fn main() { |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop - while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label - //~^ ERROR: `continue` outside of loop + while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop - while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label - //~^ ERROR: `break` outside of loop + while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop } diff --git a/src/test/ui/closure-array-break-length.stderr b/src/test/ui/closure-array-break-length.stderr index a337645fb7e8f..f62b135437092 100644 --- a/src/test/ui/closure-array-break-length.stderr +++ b/src/test/ui/closure-array-break-length.stderr @@ -4,31 +4,18 @@ error[E0268]: `continue` outside of loop LL | |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop | ^^^^^^^^ cannot break outside of a loop -error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/closure-array-break-length.rs:14:19 - | -LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label - | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop - error[E0268]: `continue` outside of loop --> $DIR/closure-array-break-length.rs:14:19 | -LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label +LL | while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop | ^^^^^^^^ cannot break outside of a loop -error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/closure-array-break-length.rs:17:19 - | -LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label - | ^^^^^ unlabeled `break` in the condition of a `while` loop - error[E0268]: `break` outside of loop - --> $DIR/closure-array-break-length.rs:17:19 + --> $DIR/closure-array-break-length.rs:16:19 | -LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label +LL | while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop | ^^^^^ cannot break outside of a loop -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0268, E0590. -For more information about an error, try `rustc --explain E0268`. +For more information about this error, try `rustc --explain E0268`. From 0195714836d1b2fb754452ad5fc400c7bfa3c9bc Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 20:57:23 +0100 Subject: [PATCH 20/23] Fix ICEs with match/return expressions inside array lengths --- src/librustc/ty/layout.rs | 5 ++++- src/librustc_mir/hair/pattern/mod.rs | 24 ++++++++++++++------- src/test/ui/return-match-array-const.rs | 17 +++++++++++++++ src/test/ui/return-match-array-const.stderr | 21 ++++++++++++++++++ 4 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/return-match-array-const.rs create mode 100644 src/test/ui/return-match-array-const.stderr diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index f5c2a0c3f9f05..0763c8af5d037 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1118,9 +1118,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyParam(_) => { return Err(LayoutError::Unknown(ty)); } - ty::TyGeneratorWitness(..) | ty::TyInfer(_) | ty::TyError => { + ty::TyGeneratorWitness(..) | ty::TyInfer(_) => { bug!("LayoutDetails::compute: unexpected type `{}`", ty) } + ty::TyError => { + return Err(LayoutError::Unknown(ty)); + } }) } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 4d0e3e826e878..2291387792b0e 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -743,8 +743,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, - Err(()) => { - self.errors.push(PatternError::FloatBug); + Err(float_bug) => { + if float_bug { + self.errors.push(PatternError::FloatBug); + } PatternKind::Wild }, } @@ -764,8 +766,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, - Err(()) => { - self.errors.push(PatternError::FloatBug); + Err(float_bug) => { + if float_bug { + self.errors.push(PatternError::FloatBug); + } PatternKind::Wild }, } @@ -1123,7 +1127,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, neg: bool) - -> Result<&'tcx ty::Const<'tcx>, ()> { + -> Result<&'tcx ty::Const<'tcx>, bool> { use syntax::ast::*; use rustc::mir::interpret::*; @@ -1152,7 +1156,11 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, ty::TyInt(other) => Int::Signed(other), ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty), ty::TyUint(other) => Int::Unsigned(other), - _ => bug!(), + ty::TyError => { + // Avoid ICE + return Err(false); + } + _ => bug!("{:?}", ty.sty), }; // This converts from LitKind::Int (which is sign extended) to // Scalar::Bytes (which is zero extended) @@ -1182,14 +1190,14 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, }) }, LitKind::Float(n, fty) => { - parse_float(n, fty, neg)? + parse_float(n, fty, neg).map_err(|_| true)? } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - parse_float(n, fty, neg)? + parse_float(n, fty, neg).map_err(|_| true)? } LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits { bits: b as u128, diff --git a/src/test/ui/return-match-array-const.rs b/src/test/ui/return-match-array-const.rs new file mode 100644 index 0000000000000..45fc571d79d56 --- /dev/null +++ b/src/test/ui/return-match-array-const.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + [(); return match 0 { n => n }]; //~ ERROR: return statement outside of function body + + [(); return match 0 { 0 => 0 }]; //~ ERROR: return statement outside of function body + + [(); return match () { 'a' => 0, _ => 0 }]; //~ ERROR: return statement outside of function body +} diff --git a/src/test/ui/return-match-array-const.stderr b/src/test/ui/return-match-array-const.stderr new file mode 100644 index 0000000000000..044dc8f51455f --- /dev/null +++ b/src/test/ui/return-match-array-const.stderr @@ -0,0 +1,21 @@ +error[E0572]: return statement outside of function body + --> $DIR/return-match-array-const.rs:12:10 + | +LL | [(); return match 0 { n => n }]; //~ ERROR: return statement outside of function body + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0572]: return statement outside of function body + --> $DIR/return-match-array-const.rs:14:10 + | +LL | [(); return match 0 { 0 => 0 }]; //~ ERROR: return statement outside of function body + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0572]: return statement outside of function body + --> $DIR/return-match-array-const.rs:16:10 + | +LL | [(); return match () { 'a' => 0, _ => 0 }]; //~ ERROR: return statement outside of function body + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0572`. From 90eee7dff21e6fa7be553cc3863aaeb8a73db442 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 21:07:21 +0100 Subject: [PATCH 21/23] Remove early error abort --- src/librustc_driver/driver.rs | 1 - src/test/ui/issue-51714.rs | 1 + src/test/ui/issue-51714.stderr | 11 +++++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c4e196628915b..feeac9d938b6a 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1211,7 +1211,6 @@ where .set(derive_registrar::find(&hir_map)); time(sess, "loop checking", || loops::check_crate(sess, &hir_map)); - sess.abort_if_errors(); let mut local_providers = ty::query::Providers::default(); default_provide(&mut local_providers); diff --git a/src/test/ui/issue-51714.rs b/src/test/ui/issue-51714.rs index f8d12b991eaef..2b9d51f81b988 100644 --- a/src/test/ui/issue-51714.rs +++ b/src/test/ui/issue-51714.rs @@ -20,4 +20,5 @@ fn main() { [(); return while let Some(n) = Some(0) {}]; //~^ ERROR return statement outside of function body + //~^^ ERROR irrefutable while-let pattern } diff --git a/src/test/ui/issue-51714.stderr b/src/test/ui/issue-51714.stderr index c8764564dca38..ddc70bfb38e01 100644 --- a/src/test/ui/issue-51714.stderr +++ b/src/test/ui/issue-51714.stderr @@ -22,6 +22,13 @@ error[E0572]: return statement outside of function body LL | [(); return while let Some(n) = Some(0) {}]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error[E0165]: irrefutable while-let pattern + --> $DIR/issue-51714.rs:21:27 + | +LL | [(); return while let Some(n) = Some(0) {}]; + | ^^^^^^^ irrefutable pattern + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0572`. +Some errors occurred: E0165, E0572. +For more information about an error, try `rustc --explain E0165`. From 4d66b65850cba7302c79c031f9fa61e7162aca43 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 23:40:03 +0100 Subject: [PATCH 22/23] Fix issue-50585 test --- src/librustc_passes/loops.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 898acf48d3df8..eff0dbe1235ff 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -17,7 +17,7 @@ use rustc::hir::{self, Destination}; use syntax::ast; use syntax_pos::Span; -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] enum LoopKind { Loop(hir::LoopSource), WhileLoop, @@ -34,7 +34,7 @@ impl LoopKind { } } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] enum Context { Normal, Loop(LoopKind), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fa78b38dbb7a8..646c4f17568f0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3827,7 +3827,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // this can only happen if the `break` was not // inside a loop at all, which is caught by the // loop-checking pass. - assert!(self.tcx.sess.err_count() > 0); + if self.tcx.sess.err_count() == 0 { + self.tcx.sess.delay_span_bug(expr.span, + "break was outside loop, but no error was emitted"); + } // We still need to assign a type to the inner expression to // prevent the ICE in #43162. @@ -3960,7 +3963,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // is nil. This makes sense because infinite loops // (which would have type !) are only possible iff we // permit break with a value [1]. - assert!(ctxt.coerce.is_some() || ctxt.may_break); // [1] + if ctxt.coerce.is_none() && !ctxt.may_break { + // [1] + self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break"); + } ctxt.coerce.map(|c| c.complete(self)).unwrap_or(self.tcx.mk_nil()) } hir::ExprMatch(ref discrim, ref arms, match_src) => { From adf4ef7b98212e1295e7cbc68a7133e67f9af846 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 2 Jul 2018 02:12:19 +0100 Subject: [PATCH 23/23] Use LitToConstError rather than bool for errors --- src/librustc/ty/layout.rs | 5 +---- src/librustc_mir/hair/pattern/mod.rs | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 0763c8af5d037..a32fdbb285d12 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1115,13 +1115,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } tcx.layout_raw(param_env.and(normalized))? } - ty::TyParam(_) => { - return Err(LayoutError::Unknown(ty)); - } ty::TyGeneratorWitness(..) | ty::TyInfer(_) => { bug!("LayoutDetails::compute: unexpected type `{}`", ty) } - ty::TyError => { + ty::TyParam(_) | ty::TyError => { return Err(LayoutError::Unknown(ty)); } }) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 2291387792b0e..636969e263222 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -743,8 +743,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, - Err(float_bug) => { - if float_bug { + Err(e) => { + if e == LitToConstError::UnparseableFloat { self.errors.push(PatternError::FloatBug); } PatternKind::Wild @@ -766,8 +766,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, - Err(float_bug) => { - if float_bug { + Err(e) => { + if e == LitToConstError::UnparseableFloat { self.errors.push(PatternError::FloatBug); } PatternKind::Wild @@ -1122,12 +1122,18 @@ pub fn compare_const_vals<'a, 'tcx>( fallback() } +#[derive(PartialEq)] +enum LitToConstError { + UnparseableFloat, + Propagated, +} + // FIXME: Combine with rustc_mir::hair::cx::const_eval_literal fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, neg: bool) - -> Result<&'tcx ty::Const<'tcx>, bool> { + -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { use syntax::ast::*; use rustc::mir::interpret::*; @@ -1156,11 +1162,10 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, ty::TyInt(other) => Int::Signed(other), ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty), ty::TyUint(other) => Int::Unsigned(other), - ty::TyError => { - // Avoid ICE - return Err(false); + ty::TyError => { // Avoid ICE (#51963) + return Err(LitToConstError::Propagated); } - _ => bug!("{:?}", ty.sty), + _ => bug!("literal integer type with bad type ({:?})", ty.sty), }; // This converts from LitKind::Int (which is sign extended) to // Scalar::Bytes (which is zero extended) @@ -1190,14 +1195,14 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, }) }, LitKind::Float(n, fty) => { - parse_float(n, fty, neg).map_err(|_| true)? + parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)? } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - parse_float(n, fty, neg).map_err(|_| true)? + parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)? } LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits { bits: b as u128,