diff --git a/RELEASES.md b/RELEASES.md index 83c44774da283..841467b69c986 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,151 @@ +Version 1.33.0 (2019-02-28) +========================== + +Language +-------- +- [You can now use the `cfg(target_vendor)` attribute.][57465] E.g. + `#[cfg(target_vendor="linux")] fn main() { println!("Hello Linux!"); }` +- [Integer patterns such as in a match expression can now be exhaustive.][56362] + E.g. You can have match statement on a `u8` that covers `0..=255` and + you would no longer be required to have a `_ => unreachable!()` case. +- [You can now have multiple patterns in `if let` and `while let` + expressions.][57532] You can do this with the same syntax as a `match` + expression. E.g. + ```rust + enum Creature { + Crab(String), + Lobster(String), + Person(String), + } + + fn main() { + let state = Creature::Crab("Ferris"); + + if let Creature::Crab(name) | Creature::Person(name) = state { + println!("This creature's name is: {}", name); + } + } + ``` +- [You can now have irrefutable `if let` and `while let` patterns.][57535] Using + this feature will by default produce a warning as this behaviour can be + unintuitive. E.g. `if let _ = 5 {}` +- [You can now use `let` bindings, assignments, expression statements, + and irrefutable pattern destructuring in const functions.][57175] +- [You can now call unsafe const functions.][57067] E.g. + ```rust + const unsafe fn foo() -> i32 { 5 } + const fn bar() -> i32 { + unsafe { foo() } + } + ``` +- [You can now specify multiple attributes in a `cfg_attr` attribute.][57332] + E.g. `#[cfg_attr(all(), must_use, optimize)]` +- [You can now specify a specific alignment with the `#[repr(packed)]` + attribute.][57049] E.g. `#[repr(packed(2))] struct Foo(i16, i32);` is a struct + with an alignment of 2 bytes and a size of 6 bytes. +- [You can now import an item from a module as an `_`.][56303] This allows you to + import a trait's impls, and not have the name in the namespace. E.g. + ```rust + use std::io::Read as _; + + // Allowed as there is only one `Read` in the module. + pub trait Read {} + ``` +- [`extern` functions will now abort by default when panicking.][55982] + This was previously undefined behaviour. + +Compiler +-------- +- [You can now set a linker flavor for `rustc` with the `-Clinker-flavor` + command line argument.][56351] +- [The mininum required LLVM version has been bumped to 6.0.][56642] +- [Added support for the PowerPC64 architecture on FreeBSD.][57615] +- [The `x86_64-fortanix-unknown-sgx` target support has been upgraded to + tier 2 support.][57130] Visit the [platform support][platform-support] page for + information on Rust's platform support. +- [Added support for the `thumbv7neon-linux-androideabi` and + `thumbv7neon-unknown-linux-gnueabihf` targets.][56947] +- [Added support for the `x86_64-unknown-uefi` target.][56769] + +Libraries +--------- +- [The methods `overflowing_{add, sub, mul, shl, shr}` are now `const` + functions for all numeric types.][57566] +- [The methods `rotate_left`, `rotate_right`, and `wrapping_{add, sub, mul, shl, shr}` + are now `const` functions for all numeric types.][57105] +- [The methods `is_positive` and `is_negative` are now `const` functions for + all signed numeric types.][57105] +- [The `get` method for all `NonZero` types is now `const`.][57167] +- [The methods `count_ones`, `count_zeros`, `leading_zeros`, `trailing_zeros`, + `swap_bytes`, `from_be`, `from_le`, `to_be`, `to_le` are now `const` for all + numeric types.][57234] +- [`Ipv4Addr::new` is now a `const` function][57234] + +Stabilized APIs +--------------- +- [`unix::FileExt::read_exact_at`] +- [`unix::FileExt::write_all_at`] +- [`Option::transpose`] +- [`Result::transpose`] +- [`convert::identity`] +- [`pin::Pin`] +- [`marker::Unpin`] +- [`marker::PhantomPinned`] +- [`Vec::resize_with`] +- [`VecDeque::resize_with`] +- [`Duration::as_millis`] +- [`Duration::as_micros`] +- [`Duration::as_nanos`] + + +Cargo +----- +- [Cargo should now rebuild a crate if a file was modified during the initial + build.][cargo/6484] + +Compatibility Notes +------------------- +- The methods `str::{trim_left, trim_right, trim_left_matches, trim_right_matches}` + are now deprecated in the standard library, and their usage will now produce a warning. + Please use the `str::{trim_start, trim_end, trim_start_matches, trim_end_matches}` + methods instead. + +[57615]: https://github.com/rust-lang/rust/pull/57615/ +[57465]: https://github.com/rust-lang/rust/pull/57465/ +[57532]: https://github.com/rust-lang/rust/pull/57532/ +[57535]: https://github.com/rust-lang/rust/pull/57535/ +[57566]: https://github.com/rust-lang/rust/pull/57566/ +[57130]: https://github.com/rust-lang/rust/pull/57130/ +[57167]: https://github.com/rust-lang/rust/pull/57167/ +[57175]: https://github.com/rust-lang/rust/pull/57175/ +[57234]: https://github.com/rust-lang/rust/pull/57234/ +[57332]: https://github.com/rust-lang/rust/pull/57332/ +[56947]: https://github.com/rust-lang/rust/pull/56947/ +[57049]: https://github.com/rust-lang/rust/pull/57049/ +[57067]: https://github.com/rust-lang/rust/pull/57067/ +[56769]: https://github.com/rust-lang/rust/pull/56769/ +[56642]: https://github.com/rust-lang/rust/pull/56642/ +[56303]: https://github.com/rust-lang/rust/pull/56303/ +[56351]: https://github.com/rust-lang/rust/pull/56351/ +[55982]: https://github.com/rust-lang/rust/pull/55982/ +[56362]: https://github.com/rust-lang/rust/pull/56362 +[57105]: https://github.com/rust-lang/rust/pull/57105 +[cargo/6484]: https://github.com/rust-lang/cargo/pull/6484/ +[`unix::FileExt::read_exact_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.read_exact_at +[`unix::FileExt::write_all_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.write_all_at +[`Option::transpose`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.transpose +[`Result::transpose`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.transpose +[`convert::identity`]: https://doc.rust-lang.org/std/convert/fn.identity.html +[`pin::Pin`]: https://doc.rust-lang.org/std/pin/struct.Pin.html +[`marker::Unpin`]: https://doc.rust-lang.org/stable/std/marker/trait.Unpin.html +[`marker::PhantomPinned`]: https://doc.rust-lang.org/nightly/std/marker/struct.PhantomPinned.html +[`Vec::resize_with`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.resize_with +[`VecDeque::resize_with`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.resize_with +[`Duration::as_millis`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_millis +[`Duration::as_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_micros +[`Duration::as_nanos`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_nanos +[platform-support]: https://forge.rust-lang.org/platform-support.html + Version 1.32.0 (2019-01-17) ========================== diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index dddfa3f158e71..229dafc5fdc3a 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1610,6 +1610,7 @@ impl_is_zero!(u64, |x| x == 0); impl_is_zero!(u128, |x| x == 0); impl_is_zero!(usize, |x| x == 0); +impl_is_zero!(bool, |x| x == false); impl_is_zero!(char, |x| x == '\0'); impl_is_zero!(f32, |x: f32| x.to_bits() == 0); diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index a3e9cfa949312..e7efd9728b94a 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -1,6 +1,6 @@ use convert::TryFrom; use mem; -use ops::{self, Add, Sub}; +use ops::{self, Add, Sub, Try}; use usize; use super::{FusedIterator, TrustedLen}; @@ -368,11 +368,11 @@ impl Iterator for ops::RangeInclusive { Some(Less) => { self.is_empty = Some(false); self.start = plus_n.add_one(); - return Some(plus_n) + return Some(plus_n); } Some(Equal) => { self.is_empty = Some(true); - return Some(plus_n) + return Some(plus_n); } _ => {} } @@ -382,6 +382,34 @@ impl Iterator for ops::RangeInclusive { None } + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.compute_is_empty(); + + if self.is_empty() { + return Try::from_ok(init); + } + + let mut accum = init; + + while self.start < self.end { + let n = self.start.add_one(); + let n = mem::replace(&mut self.start, n); + accum = f(accum, n)?; + } + + self.is_empty = Some(true); + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + Try::from_ok(accum) + } + #[inline] fn last(mut self) -> Option { self.next_back() @@ -415,6 +443,33 @@ impl DoubleEndedIterator for ops::RangeInclusive { self.end.clone() }) } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.compute_is_empty(); + + if self.is_empty() { + return Try::from_ok(init); + } + + let mut accum = init; + + while self.start < self.end { + let n = self.end.sub_one(); + let n = mem::replace(&mut self.end, n); + accum = f(accum, n)?; + } + + self.is_empty = Some(true); + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + Try::from_ok(accum) + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index b3dd5d20299c1..998b597d5e113 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -334,12 +334,14 @@ pub struct RangeInclusive { trait RangeInclusiveEquality: Sized { fn canonicalized_is_empty(range: &RangeInclusive) -> bool; } + impl RangeInclusiveEquality for T { #[inline] default fn canonicalized_is_empty(range: &RangeInclusive) -> bool { range.is_empty.unwrap_or_default() } } + impl RangeInclusiveEquality for T { #[inline] fn canonicalized_is_empty(range: &RangeInclusive) -> bool { diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 9b76a4af98824..d880abb181c20 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1741,19 +1741,37 @@ fn test_range_inclusive_folds() { assert_eq!((1..=10).sum::(), 55); assert_eq!((1..=10).rev().sum::(), 55); - let mut it = 40..=50; + let mut it = 44..=50; assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it, 44..=50); + assert_eq!(it, 47..=50); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it, 50..=50); + assert_eq!(it.try_fold(0, i8::checked_add), Some(50)); + assert!(it.is_empty()); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); + assert!(it.is_empty()); + + let mut it = 40..=47; + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it, 40..=44); assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it, 44..=47); + assert_eq!(it, 40..=41); + assert_eq!(it.try_rfold(0, i8::checked_add), Some(81)); + assert!(it.is_empty()); + assert_eq!(it.try_rfold(0, i8::checked_add), Some(0)); + assert!(it.is_empty()); let mut it = 10..=20; assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165)); assert!(it.is_empty()); + assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(0)); + assert!(it.is_empty()); let mut it = 10..=20; assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165)); assert!(it.is_empty()); + assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(0)); + assert!(it.is_empty()); } #[test] diff --git a/src/libcore/time.rs b/src/libcore/time.rs index ac7e11754aa3a..91161ca477e39 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -23,22 +23,6 @@ const MILLIS_PER_SEC: u64 = 1_000; const MICROS_PER_SEC: u64 = 1_000_000; const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64; -/// The duration of one second. -#[unstable(feature = "duration_constants", issue = "57391")] -pub const SECOND: Duration = Duration::from_secs(1); - -/// The duration of one millisecond. -#[unstable(feature = "duration_constants", issue = "57391")] -pub const MILLISECOND: Duration = Duration::from_millis(1); - -/// The duration of one microsecond. -#[unstable(feature = "duration_constants", issue = "57391")] -pub const MICROSECOND: Duration = Duration::from_micros(1); - -/// The duration of one nanosecond. -#[unstable(feature = "duration_constants", issue = "57391")] -pub const NANOSECOND: Duration = Duration::from_nanos(1); - /// A `Duration` type to represent a span of time, typically used for system /// timeouts. /// @@ -75,6 +59,58 @@ pub struct Duration { } impl Duration { + /// The duration of one second. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::SECOND, Duration::from_secs(1)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const SECOND: Duration = Duration::from_secs(1); + + /// The duration of one millisecond. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MILLISECOND, Duration::from_millis(1)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MILLISECOND: Duration = Duration::from_millis(1); + + /// The duration of one microsecond. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MICROSECOND, Duration::from_micros(1)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MICROSECOND: Duration = Duration::from_micros(1); + + /// The duration of one nanosecond. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::NANOSECOND, Duration::from_nanos(1)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const NANOSECOND: Duration = Duration::from_nanos(1); + /// Creates a new `Duration` from the specified number of whole seconds and /// additional nanoseconds. /// diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index edc97cd28a52a..8c20a6ea55ad0 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -58,8 +58,9 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 { #[cfg(all(target_vendor="fortanix", target_env="sgx"))] unsafe fn abort() -> ! { - extern "C" { pub fn panic_exit() -> !; } - panic_exit(); + // call std::sys::abort_internal + extern "C" { pub fn __rust_abort() -> !; } + __rust_abort(); } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 9f48a628274db..f6b68682886e7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1124,19 +1124,19 @@ impl<'a> LoweringContext<'a> { TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited( span, delim, - self.lower_token_stream(tts.into()).into(), + self.lower_token_stream(tts), ).into(), } } fn lower_token(&mut self, token: Token, span: Span) -> TokenStream { match token { - Token::Interpolated(_) => {} - other => return TokenTree::Token(span, other).into(), + Token::Interpolated(nt) => { + let tts = nt.to_tokenstream(&self.sess.parse_sess, span); + self.lower_token_stream(tts) + } + other => TokenTree::Token(span, other).into(), } - - let tts = token.interpolated_to_tokenstream(&self.sess.parse_sess, span); - self.lower_token_stream(tts) } fn lower_arm(&mut self, arm: &Arm) -> hir::Arm { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 8fe10a85ef380..72aa9570cc2ff 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -339,7 +339,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_token(&mut self, t: Token) { if let Token::Interpolated(nt) = t { - if let token::NtExpr(ref expr) = nt.0 { + if let token::NtExpr(ref expr) = *nt { if let ExprKind::Mac(..) = expr.node { self.visit_macro_invoc(expr.id); } diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs index 7430cd3f70961..9787b07ef8cc2 100644 --- a/src/librustc_codegen_llvm/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -9,7 +9,7 @@ use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; use crate::ModuleLlvm; use crate::llvm::{self, False, True}; -pub(crate) unsafe fn codegen(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) { +pub(crate) unsafe fn codegen(tcx: TyCtxt, mods: &mut ModuleLlvm, kind: AllocatorKind) { let llcx = &*mods.llcx; let llmod = mods.llmod(); let usize = match &tcx.sess.target.target.target_pointer_width[..] { diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 33531bb69485b..7b2e8ec3df6bb 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -46,7 +46,7 @@ use crate::value::Value; pub fn write_metadata<'a, 'gcx>( tcx: TyCtxt<'a, 'gcx, 'gcx>, - llvm_module: &ModuleLlvm + llvm_module: &mut ModuleLlvm ) -> EncodedMetadata { use std::io::Write; use flate2::Compression; diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 9219f42d69235..9a75b8495ded3 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -120,11 +120,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend { fn write_metadata<'b, 'gcx>( &self, tcx: TyCtxt<'b, 'gcx, 'gcx>, - metadata: &ModuleLlvm + metadata: &mut ModuleLlvm ) -> EncodedMetadata { base::write_metadata(tcx, metadata) } - fn codegen_allocator(&self, tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) { + fn codegen_allocator(&self, tcx: TyCtxt, mods: &mut ModuleLlvm, kind: AllocatorKind) { unsafe { allocator::codegen(tcx, mods, kind) } } fn compile_codegen_unit<'a, 'tcx: 'a>( diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 7aa75f139d2ae..92f5c39fe5a18 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -551,9 +551,9 @@ pub fn codegen_crate( &["crate"], Some("metadata")).as_str() .to_string(); - let metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name); + let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name); let metadata = time(tcx.sess, "write metadata", || { - backend.write_metadata(tcx, &metadata_llvm_module) + backend.write_metadata(tcx, &mut metadata_llvm_module) }); tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen)); @@ -636,9 +636,9 @@ pub fn codegen_crate( &["crate"], Some("allocator")).as_str() .to_string(); - let modules = backend.new_metadata(tcx, &llmod_id); + let mut modules = backend.new_metadata(tcx, &llmod_id); time(tcx.sess, "write allocator module", || { - backend.codegen_allocator(tcx, &modules, kind) + backend.codegen_allocator(tcx, &mut modules, kind) }); Some(ModuleCodegen { diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs index 73c7614d91393..6f92024ea8af3 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/src/librustc_codegen_ssa/traits/backend.rs @@ -36,9 +36,9 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se fn write_metadata<'b, 'gcx>( &self, tcx: TyCtxt<'b, 'gcx, 'gcx>, - metadata: &Self::Module, + metadata: &mut Self::Module, ) -> EncodedMetadata; - fn codegen_allocator(&self, tcx: TyCtxt, mods: &Self::Module, kind: AllocatorKind); + fn codegen_allocator(&self, tcx: TyCtxt, mods: &mut Self::Module, kind: AllocatorKind); fn compile_codegen_unit<'a, 'tcx: 'a>( &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 4d65862375a96..739125729d41a 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -130,6 +130,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); let mut is_loop_move = false; + let is_partial_move = move_site_vec.iter().any(|move_site| { + let move_out = self.move_data.moves[(*move_site).moi]; + let moved_place = &self.move_data.move_paths[move_out.path].place; + used_place != moved_place && used_place.is_prefix_of(moved_place) + }); for move_site in &move_site_vec { let move_out = self.move_data.moves[(*move_site).moi]; let moved_place = &self.move_data.move_paths[move_out.path].place; @@ -175,8 +180,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err.span_label( span, format!( - "value {} here after move", - desired_action.as_verb_in_past_tense() + "value {} here {}", + desired_action.as_verb_in_past_tense(), + if is_partial_move { "after partial move" } else { "after move" }, ), ); } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index ec701a939f225..06b44c26e5ae8 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -7,6 +7,7 @@ use std::hash::Hash; use rustc::hir; use rustc::mir; +use rustc::mir::interpret::truncate; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx}; use rustc::ty::TypeFoldable; @@ -965,8 +966,7 @@ where // their computation, but the in-memory tag is the smallest possible // representation let size = tag.value.size(self); - let shift = 128 - size.bits(); - let discr_val = (discr_val << shift) >> shift; + let discr_val = truncate(discr_val, size); let discr_dest = self.place_field(dest, 0)?; self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?; diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 8b97d9ded7449..6b932b17524c9 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -357,8 +357,10 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> match err.kind { EvalErrorKind::InvalidNullPointerUsage => return validation_failure!("NULL reference", self.path), - EvalErrorKind::AlignmentCheckFailed { .. } => - return validation_failure!("unaligned reference", self.path), + EvalErrorKind::AlignmentCheckFailed { required, has } => + return validation_failure!(format!("unaligned reference \ + (required {} byte alignment but found {})", + required.bytes(), has.bytes()), self.path), _ => return validation_failure!( "dangling (out-of-bounds) reference (might be NULL at \ diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a82f8df154725..29de5308a3cdb 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1025,7 +1025,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { fn visit_token(&mut self, t: Token) { if let Token::Interpolated(nt) = t { - if let token::NtExpr(ref expr) = nt.0 { + if let token::NtExpr(ref expr) = *nt { if let ast::ExprKind::Mac(..) = expr.node { self.visit_invoc(expr.id); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 10f234fd3ca6a..fe13be0b12664 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2234,7 +2234,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir_id, def_id, substs, user_self_ty, self.tag(), ); - if !substs.is_noop() { + if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { let canonicalized = self.infcx.canonicalize_user_type_annotation( &UserType::TypeOf(def_id, UserSubsts { substs, @@ -2429,15 +2429,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.to_ty(ast_ty); debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); - // If the type given by the user has free regions, save it for - // later, since NLL would like to enforce those. Also pass in - // types that involve projections, since those can resolve to - // `'static` bounds (modulo #54940, which hopefully will be - // fixed by the time you see this comment, dear reader, - // although I have my doubts). Also pass in types with inference - // types, because they may be repeated. Other sorts of things - // are already sufficiently enforced with erased regions. =) - if ty.has_free_regions() || ty.has_projections() || ty.has_infer_types() { + if Self::can_contain_user_lifetime_bounds(ty) { let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); @@ -2446,6 +2438,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } + // If the type given by the user has free regions, save it for later, since + // NLL would like to enforce those. Also pass in types that involve + // projections, since those can resolve to `'static` bounds (modulo #54940, + // which hopefully will be fixed by the time you see this comment, dear + // reader, although I have my doubts). Also pass in types with inference + // types, because they may be repeated. Other sorts of things are already + // sufficiently enforced with erased regions. =) + fn can_contain_user_lifetime_bounds(t: T) -> bool + where + T: TypeFoldable<'tcx> + { + t.has_free_regions() || t.has_projections() || t.has_infer_types() + } + pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { match self.tables.borrow().node_types().get(id) { Some(&t) => t, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ea9034ae3a1e0..1bc2d9fc87e4b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -974,11 +974,13 @@ impl Attributes { "https://doc.rust-lang.org/nightly", }; // This is a primitive so the url is done "by hand". + let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); Some((s.clone(), - format!("{}{}std/primitive.{}.html", + format!("{}{}std/primitive.{}.html{}", url, if !url.ends_with('/') { "/" } else { "" }, - fragment))) + &fragment[..tail], + &fragment[tail..]))) } else { panic!("This isn't a primitive?!"); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d037154272db6..418289f98ea2e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1117,7 +1117,11 @@ themePicker.onblur = handleThemeButtonsBlur; // with rustdoc running in parallel. all_indexes.sort(); let mut w = try_err!(File::create(&dst), &dst); - try_err!(writeln!(&mut w, "var N=null,E=\"\",T=\"t\",U=\"u\",searchIndex={{}};"), &dst); + if options.enable_minification { + try_err!(writeln!(&mut w, "var N=null,E=\"\",T=\"t\",U=\"u\",searchIndex={{}};"), &dst); + } else { + try_err!(writeln!(&mut w, "var searchIndex={{}};"), &dst); + } try_err!(write_minify_replacer(&mut w, &format!("{}\n{}", variables.join(""), all_indexes.join("\n")), options.enable_minification), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7f7fffbba100e..979d2bf271241 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,6 +1,7 @@ use rustc::lint as lint; use rustc::hir; use rustc::hir::def::Def; +use rustc::hir::def_id::DefId; use rustc::ty; use syntax; use syntax::ast::{self, Ident, NodeId}; @@ -126,6 +127,17 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { path = name.clone(); } } + if let Some(prim) = is_primitive(&path, false) { + let did = primitive_impl(cx, &path).ok_or(())?; + return cx.tcx.associated_items(did) + .find(|item| item.ident.name == item_name) + .and_then(|item| match item.kind { + ty::AssociatedKind::Method => Some("method"), + _ => None, + }) + .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name)))) + .ok_or(()); + } // FIXME: `with_scope` requires the `NodeId` of a module. let ty = cx.resolver.borrow_mut() @@ -589,3 +601,26 @@ fn is_primitive(path_str: &str, is_val: bool) -> Option { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) } } + +fn primitive_impl(cx: &DocContext, path_str: &str) -> Option { + let tcx = cx.tcx; + match path_str { + "u8" => tcx.lang_items().u8_impl(), + "u16" => tcx.lang_items().u16_impl(), + "u32" => tcx.lang_items().u32_impl(), + "u64" => tcx.lang_items().u64_impl(), + "u128" => tcx.lang_items().u128_impl(), + "usize" => tcx.lang_items().usize_impl(), + "i8" => tcx.lang_items().i8_impl(), + "i16" => tcx.lang_items().i16_impl(), + "i32" => tcx.lang_items().i32_impl(), + "i64" => tcx.lang_items().i64_impl(), + "i128" => tcx.lang_items().i128_impl(), + "isize" => tcx.lang_items().isize_impl(), + "f32" => tcx.lang_items().f32_impl(), + "f64" => tcx.lang_items().f64_impl(), + "str" => tcx.lang_items().str_impl(), + "char" => tcx.lang_items().char_impl(), + _ => None, + } +} diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 33163a556c16d..4dfbe86d14f4d 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -204,6 +204,7 @@ pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { } #[no_mangle] +// NB. used by both libunwind and libpanic_abort pub unsafe extern "C" fn __rust_abort() { ::sys::abort_internal(); } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index e1c2b2b1d4f30..e1f5e1fcb938d 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -23,9 +23,6 @@ use sys_common::mutex::Mutex; #[stable(feature = "time", since = "1.3.0")] pub use core::time::Duration; -#[unstable(feature = "duration_constants", issue = "57391")] -pub use core::time::{SECOND, MILLISECOND, MICROSECOND, NANOSECOND}; - /// A measurement of a monotonically nondecreasing clock. /// Opaque and useful only with `Duration`. /// diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 420f7426ad786..b5fc850731404 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -517,7 +517,7 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments } } - Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match nt.0 { + Some(TokenTree::Token(_, Token::Interpolated(nt))) => match *nt { token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident), token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), token::Nonterminal::NtPath(ref path) => path.clone(), @@ -682,7 +682,7 @@ impl LitKind { match token { Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)), Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)), - Token::Interpolated(ref nt) => match nt.0 { + Token::Interpolated(nt) => match *nt { token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { ExprKind::Lit(ref lit) => Some(lit.node.clone()), _ => None, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 5980261593dbf..452cc2f2c65cc 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -266,7 +266,7 @@ impl TTMacroExpander for F impl MutVisitor for AvoidInterpolatedIdents { fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) { if let tokenstream::TokenTree::Token(_, token::Interpolated(nt)) = tt { - if let token::NtIdent(ident, is_raw) = nt.0 { + if let token::NtIdent(ident, is_raw) = **nt { *tt = tokenstream::TokenTree::Token(ident.span, token::Ident(ident, is_raw)); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f50663f97853f..b805213bb1a4c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -25,6 +25,7 @@ use syntax_pos::{Span, DUMMY_SP, FileName}; use syntax_pos::hygiene::ExpnFormat; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lrc; use std::fs; use std::io::ErrorKind; use std::{iter, mem}; @@ -584,14 +585,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } AttrProcMacro(ref mac, ..) => { self.gate_proc_macro_attr_item(attr.span, &item); - let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item { + let item_tok = TokenTree::Token(DUMMY_SP, Token::Interpolated(Lrc::new(match item { Annotatable::Item(item) => token::NtItem(item), Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()), Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()), Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()), Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), Annotatable::Expr(expr) => token::NtExpr(expr), - })).into(); + }))).into(); let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span); let tok_result = mac.expand(self.cx, attr.span, input, item_tok); let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind, diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 5de1ccec8609e..fe1cffb092b1c 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -88,6 +88,7 @@ use smallvec::{smallvec, SmallVec}; use syntax_pos::Span; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lrc; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::mem; use std::ops::{Deref, DerefMut}; @@ -179,7 +180,7 @@ struct MatcherPos<'root, 'tt: 'root> { /// all bound matches from the submatcher into the shared top-level `matches` vector. If `sep` /// and `up` are `Some`, then `matches` is _not_ the shared top-level list. Instead, if one /// wants the shared `matches`, one should use `up.matches`. - matches: Box<[Rc]>, + matches: Box<[Lrc]>, /// The position in `matches` corresponding to the first metavar in this matcher's sequence of /// token trees. In other words, the first metavar in the first token of `top_elts` corresponds /// to `matches[match_lo]`. @@ -218,7 +219,7 @@ struct MatcherPos<'root, 'tt: 'root> { impl<'root, 'tt> MatcherPos<'root, 'tt> { /// Adds `m` as a named match for the `idx`-th metavar. fn push_match(&mut self, idx: usize, m: NamedMatch) { - let matches = Rc::make_mut(&mut self.matches[idx]); + let matches = Lrc::make_mut(&mut self.matches[idx]); matches.push(m); } } @@ -295,11 +296,11 @@ pub fn count_names(ms: &[TokenTree]) -> usize { } /// `len` `Vec`s (initially shared and empty) that will store matches of metavars. -fn create_matches(len: usize) -> Box<[Rc]> { +fn create_matches(len: usize) -> Box<[Lrc]> { if len == 0 { vec![] } else { - let empty_matches = Rc::new(SmallVec::new()); + let empty_matches = Lrc::new(SmallVec::new()); vec![empty_matches; len] }.into_boxed_slice() } @@ -353,8 +354,8 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP /// token tree it was derived from. #[derive(Debug, Clone)] pub enum NamedMatch { - MatchedSeq(Rc, DelimSpan), - MatchedNonterminal(Rc), + MatchedSeq(Lrc, DelimSpan), + MatchedNonterminal(Lrc), } /// Takes a sequence of token trees `ms` representing a matcher which successfully matched input @@ -561,7 +562,7 @@ fn inner_parse_loop<'root, 'tt>( new_item.match_cur += seq.num_captures; new_item.idx += 1; for idx in item.match_cur..item.match_cur + seq.num_captures { - new_item.push_match(idx, MatchedSeq(Rc::new(smallvec![]), sp)); + new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![]), sp)); } cur_items.push(new_item); } @@ -707,7 +708,7 @@ pub fn parse( let matches = eof_items[0] .matches .iter_mut() - .map(|dv| Rc::make_mut(dv).pop().unwrap()); + .map(|dv| Lrc::make_mut(dv).pop().unwrap()); return nameize(sess, ms, matches); } else if eof_items.len() > 1 { return Error( @@ -780,7 +781,7 @@ pub fn parse( let match_cur = item.match_cur; item.push_match( match_cur, - MatchedNonterminal(Rc::new(parse_nt(&mut parser, span, &ident.as_str()))), + MatchedNonterminal(Lrc::new(parse_nt(&mut parser, span, &ident.as_str()))), ); item.idx += 1; item.match_cur += 1; @@ -829,7 +830,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool { }, "block" => match *token { Token::OpenDelim(token::Brace) => true, - Token::Interpolated(ref nt) => match nt.0 { + Token::Interpolated(ref nt) => match **nt { token::NtItem(_) | token::NtPat(_) | token::NtTy(_) @@ -843,9 +844,9 @@ fn may_begin_with(name: &str, token: &Token) -> bool { }, "path" | "meta" => match *token { Token::ModSep | Token::Ident(..) => true, - Token::Interpolated(ref nt) => match nt.0 { + Token::Interpolated(ref nt) => match **nt { token::NtPath(_) | token::NtMeta(_) => true, - _ => may_be_ident(&nt.0), + _ => may_be_ident(&nt), }, _ => false, }, @@ -862,12 +863,12 @@ fn may_begin_with(name: &str, token: &Token) -> bool { Token::ModSep | // path Token::Lt | // path (UFCS constant) Token::BinOp(token::Shl) => true, // path (double UFCS) - Token::Interpolated(ref nt) => may_be_ident(&nt.0), + Token::Interpolated(ref nt) => may_be_ident(nt), _ => false, }, "lifetime" => match *token { Token::Lifetime(_) => true, - Token::Interpolated(ref nt) => match nt.0 { + Token::Interpolated(ref nt) => match **nt { token::NtLifetime(_) | token::NtTT(_) => true, _ => false, }, diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index b9a50cc6488dd..bd2adb5ac13ba 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -149,7 +149,7 @@ pub fn transcribe(cx: &ExtCtxt<'_>, result.push(tt.clone().into()); } else { sp = sp.apply_mark(cx.current_expansion.mark); - let token = TokenTree::Token(sp, Token::interpolated((**nt).clone())); + let token = TokenTree::Token(sp, Token::Interpolated(nt.clone())); result.push(token.into()); } } else { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index fd7003d30a1dc..86849f580d081 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -581,9 +581,8 @@ pub fn noop_visit_token(t: &mut Token, vis: &mut T) { token::Ident(id, _is_raw) => vis.visit_ident(id), token::Lifetime(id) => vis.visit_ident(id), token::Interpolated(nt) => { - let nt = Lrc::make_mut(nt); - vis.visit_interpolated(&mut nt.0); - nt.1 = token::LazyTokenStream::new(); + let mut nt = Lrc::make_mut(nt); + vis.visit_interpolated(&mut nt); } _ => {} } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index b36ca0574cb8d..9020c8c6a2dc6 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -141,7 +141,7 @@ impl<'a> Parser<'a> { /// The delimiters or `=` are still put into the resulting token stream. crate fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { let meta = match self.token { - token::Interpolated(ref nt) => match nt.0 { + token::Interpolated(ref nt) => match **nt { Nonterminal::NtMeta(ref meta) => Some(meta.clone()), _ => None, }, @@ -227,7 +227,7 @@ impl<'a> Parser<'a> { /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { let nt_meta = match self.token { - token::Interpolated(ref nt) => match nt.0 { + token::Interpolated(ref nt) => match **nt { token::NtMeta(ref e) => Some(e.clone()), _ => None, }, diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index babe0eef20f8c..a7cde5fbb92cd 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -125,6 +125,28 @@ impl<'a> StringReader<'a> { Ok(ret_val) } + /// Immutably extract string if found at current position with given delimiters + pub fn peek_delimited(&self, from_ch: char, to_ch: char) -> Option { + let mut pos = self.pos; + let mut idx = self.src_index(pos); + let mut ch = char_at(&self.src, idx); + if ch != from_ch { + return None; + } + pos = pos + Pos::from_usize(ch.len_utf8()); + let start_pos = pos; + idx = self.src_index(pos); + while idx < self.end_src_index { + ch = char_at(&self.src, idx); + if ch == to_ch { + return Some(self.src[self.src_index(start_pos)..self.src_index(pos)].to_string()); + } + pos = pos + Pos::from_usize(ch.len_utf8()); + idx = self.src_index(pos); + } + return None; + } + fn try_real_token(&mut self) -> Result { let mut t = self.try_next_token()?; loop { diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index 7da4284c0e4aa..94ce6297fbefb 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -1,7 +1,7 @@ // Characters and their corresponding confusables were collected from // http://www.unicode.org/Public/security/10.0.0/confusables.txt -use syntax_pos::{Span, NO_EXPANSION}; +use syntax_pos::{Span, Pos, NO_EXPANSION}; use errors::{Applicability, DiagnosticBuilder}; use super::StringReader; @@ -333,14 +333,27 @@ crate fn check_for_substitution<'a>(reader: &StringReader<'a>, let span = Span::new(reader.pos, reader.next_pos, NO_EXPANSION); match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) { Some(&(ascii_char, ascii_name)) => { - let msg = - format!("Unicode character '{}' ({}) looks like '{}' ({}), but it is not", - ch, u_name, ascii_char, ascii_name); - err.span_suggestion( - span, - &msg, - ascii_char.to_string(), - Applicability::MaybeIncorrect); + // special help suggestion for "directed" double quotes + if let Some(s) = reader.peek_delimited('“', '”') { + let msg = format!("Unicode characters '“' (Left Double Quotation Mark) and \ + '”' (Right Double Quotation Mark) look like '{}' ({}), but are not", + ascii_char, ascii_name); + err.span_suggestion( + Span::new(reader.pos, reader.next_pos + Pos::from_usize(s.len()) + + Pos::from_usize('”'.len_utf8()), NO_EXPANSION), + &msg, + format!("\"{}\"", s), + Applicability::MaybeIncorrect); + } else { + let msg = + format!("Unicode character '{}' ({}) looks like '{}' ({}), but it is not", + ch, u_name, ascii_char, ascii_name); + err.span_suggestion( + span, + &msg, + ascii_char.to_string(), + Applicability::MaybeIncorrect); + } true }, None => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e6a48912c48b4..5a753e1f8c8a5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -119,7 +119,7 @@ enum BlockMode { macro_rules! maybe_whole_expr { ($p:expr) => { if let token::Interpolated(nt) = $p.token.clone() { - match nt.0 { + match *nt { token::NtExpr(ref e) | token::NtLiteral(ref e) => { $p.bump(); return Ok((*e).clone()); @@ -146,7 +146,7 @@ macro_rules! maybe_whole_expr { macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { if let token::Interpolated(nt) = $p.token.clone() { - if let token::$constructor($x) = nt.0.clone() { + if let token::$constructor($x) = (*nt).clone() { $p.bump(); return Ok($e); } @@ -1184,8 +1184,10 @@ impl<'a> Parser<'a> { match ate { Some(_) => { // See doc comment for `unmatched_angle_bracket_count`. - self.unmatched_angle_bracket_count -= 1; - debug!("expect_gt: (decrement) count={:?}", self.unmatched_angle_bracket_count); + if self.unmatched_angle_bracket_count > 0 { + self.unmatched_angle_bracket_count -= 1; + debug!("expect_gt: (decrement) count={:?}", self.unmatched_angle_bracket_count); + } Ok(()) }, @@ -1570,7 +1572,7 @@ impl<'a> Parser<'a> { Some(body) } token::Interpolated(ref nt) => { - match &nt.0 { + match **nt { token::NtBlock(..) => { *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; @@ -1913,7 +1915,7 @@ impl<'a> Parser<'a> { fn is_named_argument(&mut self) -> bool { let offset = match self.token { - token::Interpolated(ref nt) => match nt.0 { + token::Interpolated(ref nt) => match **nt { token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), _ => 0, } @@ -2099,7 +2101,7 @@ impl<'a> Parser<'a> { /// Matches `token_lit = LIT_INTEGER | ...`. fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { let out = match self.token { - token::Interpolated(ref nt) => match nt.0 { + token::Interpolated(ref nt) => match **nt { token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { ExprKind::Lit(ref lit) => { lit.node.clone() } _ => { return self.unexpected_last(&self.token); } @@ -2248,8 +2250,10 @@ impl<'a> Parser<'a> { // See doc comment for `unmatched_angle_bracket_count`. self.expect(&token::Gt)?; - self.unmatched_angle_bracket_count -= 1; - debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); + if self.unmatched_angle_bracket_count > 0 { + self.unmatched_angle_bracket_count -= 1; + debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); + } self.expect(&token::ModSep)?; @@ -2299,7 +2303,7 @@ impl<'a> Parser<'a> { /// attributes. pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { let meta_ident = match self.token { - token::Interpolated(ref nt) => match nt.0 { + token::Interpolated(ref nt) => match **nt { token::NtMeta(ref meta) => match meta.node { ast::MetaItemKind::Word => Some(meta.ident.clone()), _ => None, @@ -3271,7 +3275,7 @@ impl<'a> Parser<'a> { self.meta_var_span = Some(self.span); // Interpolated identifier and lifetime tokens are replaced with usual identifier // and lifetime tokens, so the former are never encountered during normal parsing. - match nt.0 { + match **nt { token::NtIdent(ident, is_raw) => (token::Ident(ident, is_raw), ident.span), token::NtLifetime(ident) => (token::Lifetime(ident), ident.span), _ => return, @@ -3403,7 +3407,7 @@ impl<'a> Parser<'a> { // can't continue an expression after an ident token::Ident(ident, is_raw) => token::ident_can_begin_expr(ident, is_raw), token::Literal(..) | token::Pound => true, - token::Interpolated(ref nt) => match nt.0 { + token::Interpolated(ref nt) => match **nt { token::NtIdent(..) | token::NtExpr(..) | token::NtBlock(..) | token::NtPath(..) => true, _ => false, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index ff7f3e0bfaef3..eec422d6266c3 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -13,16 +13,15 @@ use crate::syntax::parse::parse_stream_from_source_str; use crate::syntax::parse::parser::emit_unclosed_delims; use crate::tokenstream::{self, DelimSpan, TokenStream, TokenTree}; -use serialize::{Decodable, Decoder, Encodable, Encoder}; use syntax_pos::symbol::{self, Symbol}; use syntax_pos::{self, Span, FileName}; use log::info; -use std::{cmp, fmt}; +use std::fmt; use std::mem; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert; -use rustc_data_structures::sync::{Lrc, Lock}; +use rustc_data_structures::sync::Lrc; #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum BinOpToken { @@ -87,7 +86,7 @@ impl Lit { } } - // See comments in `interpolated_to_tokenstream` for why we care about + // See comments in `Nonterminal::to_tokenstream` for why we care about // *probably* equal here rather than actual equality fn probably_equal_for_proc_macro(&self, other: &Lit) -> bool { mem::discriminant(self) == mem::discriminant(other) @@ -184,9 +183,8 @@ pub enum Token { Ident(ast::Ident, /* is_raw */ bool), Lifetime(ast::Ident), - // The `LazyTokenStream` is a pure function of the `Nonterminal`, - // and so the `LazyTokenStream` can be ignored by Eq, Hash, etc. - Interpolated(Lrc<(Nonterminal, LazyTokenStream)>), + Interpolated(Lrc), + // Can be expanded into several tokens. /// A doc comment. DocComment(ast::Name), @@ -209,10 +207,6 @@ pub enum Token { static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::() == 16); impl Token { - pub fn interpolated(nt: Nonterminal) -> Token { - Token::Interpolated(Lrc::new((nt, LazyTokenStream::new()))) - } - /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary. pub fn from_ast_ident(ident: ast::Ident) -> Token { Ident(ident, ident.is_raw_guess()) @@ -244,7 +238,7 @@ impl Token { ModSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => match nt.0 { + Interpolated(ref nt) => match **nt { NtLiteral(..) | NtIdent(..) | NtExpr(..) | @@ -272,7 +266,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path ModSep => true, // global path - Interpolated(ref nt) => match nt.0 { + Interpolated(ref nt) => match **nt { NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true, _ => false, }, @@ -284,7 +278,7 @@ impl Token { pub fn can_begin_const_arg(&self) -> bool { match self { OpenDelim(Brace) => true, - Interpolated(ref nt) => match nt.0 { + Interpolated(ref nt) => match **nt { NtExpr(..) => true, NtBlock(..) => true, NtLiteral(..) => true, @@ -316,7 +310,7 @@ impl Token { BinOp(Minus) => true, Ident(ident, false) if ident.name == keywords::True.name() => true, Ident(ident, false) if ident.name == keywords::False.name() => true, - Interpolated(ref nt) => match nt.0 { + Interpolated(ref nt) => match **nt { NtLiteral(..) => true, _ => false, }, @@ -328,7 +322,7 @@ impl Token { pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> { match *self { Ident(ident, is_raw) => Some((ident, is_raw)), - Interpolated(ref nt) => match nt.0 { + Interpolated(ref nt) => match **nt { NtIdent(ident, is_raw) => Some((ident, is_raw)), _ => None, }, @@ -339,7 +333,7 @@ impl Token { pub fn lifetime(&self) -> Option { match *self { Lifetime(ident) => Some(ident), - Interpolated(ref nt) => match nt.0 { + Interpolated(ref nt) => match **nt { NtLifetime(ident) => Some(ident), _ => None, }, @@ -367,7 +361,7 @@ impl Token { /// Returns `true` if the token is an interpolated path. fn is_path(&self) -> bool { if let Interpolated(ref nt) = *self { - if let NtPath(..) = nt.0 { + if let NtPath(..) = **nt { return true; } } @@ -508,98 +502,7 @@ impl Token { } } - pub fn interpolated_to_tokenstream(&self, sess: &ParseSess, span: Span) - -> TokenStream - { - let nt = match *self { - Token::Interpolated(ref nt) => nt, - _ => panic!("only works on interpolated tokens"), - }; - - // An `Interpolated` token means that we have a `Nonterminal` - // which is often a parsed AST item. At this point we now need - // to convert the parsed AST to an actual token stream, e.g. - // un-parse it basically. - // - // Unfortunately there's not really a great way to do that in a - // guaranteed lossless fashion right now. The fallback here is - // to just stringify the AST node and reparse it, but this loses - // all span information. - // - // As a result, some AST nodes are annotated with the token - // stream they came from. Here we attempt to extract these - // lossless token streams before we fall back to the - // stringification. - let mut tokens = None; - - match nt.0 { - Nonterminal::NtItem(ref item) => { - tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span); - } - Nonterminal::NtTraitItem(ref item) => { - tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span); - } - Nonterminal::NtImplItem(ref item) => { - tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span); - } - Nonterminal::NtIdent(ident, is_raw) => { - let token = Token::Ident(ident, is_raw); - tokens = Some(TokenTree::Token(ident.span, token).into()); - } - Nonterminal::NtLifetime(ident) => { - let token = Token::Lifetime(ident); - tokens = Some(TokenTree::Token(ident.span, token).into()); - } - Nonterminal::NtTT(ref tt) => { - tokens = Some(tt.clone().into()); - } - _ => {} - } - - let tokens_for_real = nt.1.force(|| { - // FIXME(#43081): Avoid this pretty-print + reparse hack - let source = pprust::token_to_string(self); - let filename = FileName::macro_expansion_source_code(&source); - let (tokens, errors) = parse_stream_from_source_str( - filename, source, sess, Some(span)); - emit_unclosed_delims(&errors, &sess.span_diagnostic); - tokens - }); - - // During early phases of the compiler the AST could get modified - // directly (e.g., attributes added or removed) and the internal cache - // of tokens my not be invalidated or updated. Consequently if the - // "lossless" token stream disagrees with our actual stringification - // (which has historically been much more battle-tested) then we go - // with the lossy stream anyway (losing span information). - // - // Note that the comparison isn't `==` here to avoid comparing spans, - // but it *also* is a "probable" equality which is a pretty weird - // definition. We mostly want to catch actual changes to the AST - // like a `#[cfg]` being processed or some weird `macro_rules!` - // expansion. - // - // What we *don't* want to catch is the fact that a user-defined - // literal like `0xf` is stringified as `15`, causing the cached token - // stream to not be literal `==` token-wise (ignoring spans) to the - // token stream we got from stringification. - // - // Instead the "probably equal" check here is "does each token - // recursively have the same discriminant?" We basically don't look at - // the token values here and assume that such fine grained token stream - // modifications, including adding/removing typically non-semantic - // tokens such as extra braces and commas, don't happen. - if let Some(tokens) = tokens { - if tokens.probably_equal_for_proc_macro(&tokens_for_real) { - return tokens - } - info!("cached tokens found, but they're not \"probably equal\", \ - going with stringified version"); - } - return tokens_for_real - } - - // See comments in `interpolated_to_tokenstream` for why we care about + // See comments in `Nonterminal::to_tokenstream` for why we care about // *probably* equal here rather than actual equality crate fn probably_equal_for_proc_macro(&self, other: &Token) -> bool { if mem::discriminant(self) != mem::discriminant(other) { @@ -731,61 +634,94 @@ impl fmt::Debug for Nonterminal { } } -crate fn is_op(tok: &Token) -> bool { - match *tok { - OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | - Ident(..) | Lifetime(..) | Interpolated(..) | - Whitespace | Comment | Shebang(..) | Eof => false, - _ => true, - } -} - -#[derive(Clone)] -pub struct LazyTokenStream(Lock>); - -impl cmp::Eq for LazyTokenStream {} -impl PartialEq for LazyTokenStream { - fn eq(&self, _other: &LazyTokenStream) -> bool { - true - } -} - -impl fmt::Debug for LazyTokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.clone().0.into_inner(), f) - } -} +impl Nonterminal { + pub fn to_tokenstream(&self, sess: &ParseSess, span: Span) -> TokenStream { + // A `Nonterminal` is often a parsed AST item. At this point we now + // need to convert the parsed AST to an actual token stream, e.g. + // un-parse it basically. + // + // Unfortunately there's not really a great way to do that in a + // guaranteed lossless fashion right now. The fallback here is to just + // stringify the AST node and reparse it, but this loses all span + // information. + // + // As a result, some AST nodes are annotated with the token stream they + // came from. Here we attempt to extract these lossless token streams + // before we fall back to the stringification. + let tokens = match *self { + Nonterminal::NtItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtTraitItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtImplItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtIdent(ident, is_raw) => { + let token = Token::Ident(ident, is_raw); + Some(TokenTree::Token(ident.span, token).into()) + } + Nonterminal::NtLifetime(ident) => { + let token = Token::Lifetime(ident); + Some(TokenTree::Token(ident.span, token).into()) + } + Nonterminal::NtTT(ref tt) => { + Some(tt.clone().into()) + } + _ => None, + }; -impl LazyTokenStream { - pub fn new() -> Self { - LazyTokenStream(Lock::new(None)) - } + // FIXME(#43081): Avoid this pretty-print + reparse hack + let source = pprust::nonterminal_to_string(self); + let filename = FileName::macro_expansion_source_code(&source); + let (tokens_for_real, errors) = + parse_stream_from_source_str(filename, source, sess, Some(span)); + emit_unclosed_delims(&errors, &sess.span_diagnostic); - fn force TokenStream>(&self, f: F) -> TokenStream { - let mut opt_stream = self.0.lock(); - if opt_stream.is_none() { - *opt_stream = Some(f()); + // During early phases of the compiler the AST could get modified + // directly (e.g., attributes added or removed) and the internal cache + // of tokens my not be invalidated or updated. Consequently if the + // "lossless" token stream disagrees with our actual stringification + // (which has historically been much more battle-tested) then we go + // with the lossy stream anyway (losing span information). + // + // Note that the comparison isn't `==` here to avoid comparing spans, + // but it *also* is a "probable" equality which is a pretty weird + // definition. We mostly want to catch actual changes to the AST + // like a `#[cfg]` being processed or some weird `macro_rules!` + // expansion. + // + // What we *don't* want to catch is the fact that a user-defined + // literal like `0xf` is stringified as `15`, causing the cached token + // stream to not be literal `==` token-wise (ignoring spans) to the + // token stream we got from stringification. + // + // Instead the "probably equal" check here is "does each token + // recursively have the same discriminant?" We basically don't look at + // the token values here and assume that such fine grained token stream + // modifications, including adding/removing typically non-semantic + // tokens such as extra braces and commas, don't happen. + if let Some(tokens) = tokens { + if tokens.probably_equal_for_proc_macro(&tokens_for_real) { + return tokens + } + info!("cached tokens found, but they're not \"probably equal\", \ + going with stringified version"); } - opt_stream.clone().unwrap() - } -} - -impl Encodable for LazyTokenStream { - fn encode(&self, _: &mut S) -> Result<(), S::Error> { - Ok(()) + return tokens_for_real } } -impl Decodable for LazyTokenStream { - fn decode(_: &mut D) -> Result { - Ok(LazyTokenStream::new()) +crate fn is_op(tok: &Token) -> bool { + match *tok { + OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | + Ident(..) | Lifetime(..) | Interpolated(..) | + Whitespace | Comment | Shebang(..) | Eof => false, + _ => true, } } -impl ::std::hash::Hash for LazyTokenStream { - fn hash(&self, _hasher: &mut H) {} -} - fn prepend_attrs(sess: &ParseSess, attrs: &[ast::Attribute], tokens: Option<&tokenstream::TokenStream>, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index cdf805176a293..dcf9815f6d1ba 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -4,7 +4,7 @@ use crate::ast::{Attribute, MacDelimiter, GenericArg}; use crate::util::parser::{self, AssocOp, Fixity}; use crate::attr; use crate::source_map::{self, SourceMap, Spanned}; -use crate::parse::token::{self, BinOpToken, Token}; +use crate::parse::token::{self, BinOpToken, Nonterminal, Token}; use crate::parse::lexer::comments; use crate::parse::{self, ParseSess}; use crate::print::pp::{self, Breaks}; @@ -257,29 +257,33 @@ pub fn token_to_string(tok: &Token) -> String { token::Comment => "/* */".to_string(), token::Shebang(s) => format!("/* shebang: {}*/", s), - token::Interpolated(ref nt) => match nt.0 { - token::NtExpr(ref e) => expr_to_string(e), - token::NtMeta(ref e) => meta_item_to_string(e), - token::NtTy(ref e) => ty_to_string(e), - token::NtPath(ref e) => path_to_string(e), - token::NtItem(ref e) => item_to_string(e), - token::NtBlock(ref e) => block_to_string(e), - token::NtStmt(ref e) => stmt_to_string(e), - token::NtPat(ref e) => pat_to_string(e), - token::NtIdent(e, false) => ident_to_string(e), - token::NtIdent(e, true) => format!("r#{}", ident_to_string(e)), - token::NtLifetime(e) => ident_to_string(e), - token::NtLiteral(ref e) => expr_to_string(e), - token::NtTT(ref tree) => tt_to_string(tree.clone()), - token::NtArm(ref e) => arm_to_string(e), - token::NtImplItem(ref e) => impl_item_to_string(e), - token::NtTraitItem(ref e) => trait_item_to_string(e), - token::NtGenerics(ref e) => generic_params_to_string(&e.params), - token::NtWhereClause(ref e) => where_clause_to_string(e), - token::NtArg(ref e) => arg_to_string(e), - token::NtVis(ref e) => vis_to_string(e), - token::NtForeignItem(ref e) => foreign_item_to_string(e), - } + token::Interpolated(ref nt) => nonterminal_to_string(nt), + } +} + +pub fn nonterminal_to_string(nt: &Nonterminal) -> String { + match *nt { + token::NtExpr(ref e) => expr_to_string(e), + token::NtMeta(ref e) => meta_item_to_string(e), + token::NtTy(ref e) => ty_to_string(e), + token::NtPath(ref e) => path_to_string(e), + token::NtItem(ref e) => item_to_string(e), + token::NtBlock(ref e) => block_to_string(e), + token::NtStmt(ref e) => stmt_to_string(e), + token::NtPat(ref e) => pat_to_string(e), + token::NtIdent(e, false) => ident_to_string(e), + token::NtIdent(e, true) => format!("r#{}", ident_to_string(e)), + token::NtLifetime(e) => ident_to_string(e), + token::NtLiteral(ref e) => expr_to_string(e), + token::NtTT(ref tree) => tt_to_string(tree.clone()), + token::NtArm(ref e) => arm_to_string(e), + token::NtImplItem(ref e) => impl_item_to_string(e), + token::NtTraitItem(ref e) => trait_item_to_string(e), + token::NtGenerics(ref e) => generic_params_to_string(&e.params), + token::NtWhereClause(ref e) => where_clause_to_string(e), + token::NtArg(ref e) => arg_to_string(e), + token::NtVis(ref e) => vis_to_string(e), + token::NtForeignItem(ref e) => foreign_item_to_string(e), } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index c4f2cffb09708..283679e758b54 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -72,7 +72,7 @@ impl TokenTree { } } - // See comments in `interpolated_to_tokenstream` for why we care about + // See comments in `Nonterminal::to_tokenstream` for why we care about // *probably* equal here rather than actual equality // // This is otherwise the same as `eq_unspanned`, only recursing with a @@ -310,7 +310,7 @@ impl TokenStream { t1.next().is_none() && t2.next().is_none() } - // See comments in `interpolated_to_tokenstream` for why we care about + // See comments in `Nonterminal::to_tokenstream` for why we care about // *probably* equal here rather than actual equality // // This is otherwise the same as `eq_unspanned`, only recursing with a diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 6aba4d83cd27c..cfc3c931598a1 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -2,6 +2,7 @@ use crate::proc_macro_impl::EXEC_STRATEGY; use crate::proc_macro_server; use errors::FatalError; +use rustc_data_structures::sync::Lrc; use syntax::ast::{self, ItemKind, Attribute, Mac}; use syntax::attr::{mark_used, mark_known}; use syntax::source_map::Span; @@ -65,7 +66,7 @@ impl MultiItemModifier for ProcMacroDerive { // Mark attributes as known, and used. MarkAttrs(&self.attrs).visit_item(&item); - let token = Token::interpolated(token::NtItem(item)); + let token = Token::Interpolated(Lrc::new(token::NtItem(item))); let input = tokenstream::TokenTree::Token(DUMMY_SP, token).into(); let server = proc_macro_server::Rustc::new(ecx); diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index fd82dac5ab6d8..699539b62f515 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -178,8 +178,8 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> tt!(Punct::new('#', false)) } - Interpolated(_) => { - let stream = token.interpolated_to_tokenstream(sess, span); + Interpolated(nt) => { + let stream = nt.to_tokenstream(sess, span); TokenTree::Group(Group { delimiter: Delimiter::None, stream, diff --git a/src/test/rustdoc/intra-link-prim-methods.rs b/src/test/rustdoc/intra-link-prim-methods.rs new file mode 100644 index 0000000000000..af0426b22c557 --- /dev/null +++ b/src/test/rustdoc/intra-link-prim-methods.rs @@ -0,0 +1,3 @@ +#![deny(intra_doc_link_resolution_failure)] + +//! A [`char`] and its [`char::len_utf8`]. diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.ast.nll.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.ast.nll.stderr index bdec94b4f84b0..99cbf64fd5d46 100644 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.ast.nll.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.ast.nll.stderr @@ -20,7 +20,7 @@ error[E0382]: use of moved value: `line2` LL | let _moved = (line2.origin, line2.middle); | ------------ value moved here LL | line2.consume(); //[ast]~ ERROR use of partially moved value: `line2` [E0382] - | ^^^^^ value used here after move + | ^^^^^ value used here after partial move | = note: move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.mir.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.mir.stderr index bdec94b4f84b0..99cbf64fd5d46 100644 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.mir.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.mir.stderr @@ -20,7 +20,7 @@ error[E0382]: use of moved value: `line2` LL | let _moved = (line2.origin, line2.middle); | ------------ value moved here LL | line2.consume(); //[ast]~ ERROR use of partially moved value: `line2` [E0382] - | ^^^^^ value used here after move + | ^^^^^ value used here after partial move | = note: move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs index 95deb04fb01d5..6fd8e9cbc806b 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs @@ -3,11 +3,11 @@ // // This test is checking the count in an array expression. -// FIXME (#23926): the error output is not consistent between a -// self-hosted and a cross-compiled setup; therefore resorting to -// error-pattern for now. -// error-pattern: attempt to add with overflow + + + + #![allow(unused_imports)] @@ -18,6 +18,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_I : [u32; (i8::MAX as usize) + 1] = [0; (i8::MAX + 1) as usize]; +//~^ ERROR evaluation of constant value failed fn main() { foo(&A_I8_I[..]); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs index 5a6be0c9bd38b..d9b06370dff79 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs @@ -7,11 +7,11 @@ // types for the left- and right-hand sides of the addition do not // match (as well as overflow). -// FIXME (#23926): the error output is not consistent between a -// self-hosted and a cross-compiled setup; therefore resorting to -// error-pattern for now. -// error-pattern: mismatched types + + + + #![allow(unused_imports)] @@ -22,6 +22,8 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_I : [u32; (i8::MAX as usize) + 1] = [0; (i8::MAX + 1u8) as usize]; +//~^ ERROR mismatched types +//~| ERROR cannot add `u8` to `i8` fn main() { foo(&A_I8_I[..]); diff --git a/src/test/ui/consts/const-eval/ub-ref.rs b/src/test/ui/consts/const-eval/ub-ref.rs index 3b19f3b07753e..0d8f30159b316 100644 --- a/src/test/ui/consts/const-eval/ub-ref.rs +++ b/src/test/ui/consts/const-eval/ub-ref.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength #![feature(const_transmute)] #![allow(const_err)] // make sure we cannot allow away the errors tested here @@ -5,6 +6,7 @@ use std::mem; const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; //~^ ERROR it is undefined behavior to use this value +//~^^ type validation failed: encountered unaligned reference (required 2 byte alignment but found 1) const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index f8b5b2f50ce04..33535c235e3a3 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -1,13 +1,13 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:6:1 + --> $DIR/ub-ref.rs:7:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference (required 2 byte alignment but found 1) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:9:1 + --> $DIR/ub-ref.rs:11:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 @@ -15,7 +15,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:12:1 + --> $DIR/ub-ref.rs:14:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -23,7 +23,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:15:1 + --> $DIR/ub-ref.rs:17:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes @@ -31,7 +31,7 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:18:1 + --> $DIR/ub-ref.rs:20:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered integer pointer in non-ZST reference diff --git a/src/test/ui/huge-array-simple.rs b/src/test/ui/huge-array-simple.rs index 5fa874c1fa0d3..8b244a47232fa 100644 --- a/src/test/ui/huge-array-simple.rs +++ b/src/test/ui/huge-array-simple.rs @@ -1,11 +1,16 @@ -// FIXME (#23926): the error output is not consistent between a -// self-hosted and a cross-compiled setup. Skipping for now. - -// ignore-test FIXME(#23926) +// error-pattern: too big for the current architecture +// normalize-stderr-test "; \d+]" -> "; N]" #![allow(exceeding_bitshifts)] +#[cfg(target_pointer_width = "64")] fn main() { let _fat : [u8; (1<<61)+(1<<31)] = [0; (1u64<<61) as usize +(1u64<<31) as usize]; } + +#[cfg(target_pointer_width = "32")] +fn main() { + let _fat : [u8; (1<<31)+(1<<15)] = + [0; (1u32<<31) as usize +(1u32<<15) as usize]; +} diff --git a/src/test/ui/huge-array-simple.stderr b/src/test/ui/huge-array-simple.stderr new file mode 100644 index 0000000000000..3e9c86296cec2 --- /dev/null +++ b/src/test/ui/huge-array-simple.stderr @@ -0,0 +1,4 @@ +error: the type `[u8; N]` is too big for the current architecture + +error: aborting due to previous error + diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.nll.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.nll.stderr index 99550235f6969..5f0d2b42671de 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.nll.stderr +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.nll.stderr @@ -5,7 +5,7 @@ LL | Some(right) => consume(right), | ----- value moved here ... LL | consume(node) + r //~ ERROR use of partially moved value: `node` - | ^^^^ value used here after move + | ^^^^ value used here after partial move | = note: move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.nll.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.nll.stderr index 481c492e16469..6d523fc09c08b 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.nll.stderr +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.nll.stderr @@ -5,7 +5,7 @@ LL | Foo {f} => {} | - value moved here ... LL | touch(&x); //~ ERROR use of partially moved value: `x` - | ^^ value borrowed here after move + | ^^ value borrowed here after partial move | = note: move occurs because `x.f` has type `std::string::String`, which does not implement the `Copy` trait diff --git a/src/test/ui/nll/move-subpaths-moves-root.stderr b/src/test/ui/nll/move-subpaths-moves-root.stderr index 0dd396f855dc5..8b52cc113ccc5 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.stderr +++ b/src/test/ui/nll/move-subpaths-moves-root.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value: `x` LL | drop(x.0); | --- value moved here LL | drop(x); //~ ERROR use of moved value - | ^ value used here after move + | ^ value used here after partial move | = note: move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs index 5dcd41078c787..45f56836d18b5 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs @@ -15,5 +15,7 @@ fn main() { SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation. - SomeStruct:: { t: 22 }; //~ ERROR [u32] + SomeStruct:: { t: 22 }; // No lifetime bounds given. + + SomeStruct::<&'static u32> { t: &22 }; //~ ERROR [&ReStatic u32] } diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr index 123c26195d006..6e24da094e0d2 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr @@ -1,8 +1,8 @@ -error: user substs: UserSubsts { substs: [u32], user_self_ty: None } - --> $DIR/dump-adt-brace-struct.rs:18:5 +error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None } + --> $DIR/dump-adt-brace-struct.rs:20:5 | -LL | SomeStruct:: { t: 22 }; //~ ERROR [u32] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | SomeStruct::<&'static u32> { t: &22 }; //~ ERROR [&ReStatic u32] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.rs b/src/test/ui/nll/user-annotations/dump-fn-method.rs index 7551a9474dc08..b689f18c22593 100644 --- a/src/test/ui/nll/user-annotations/dump-fn-method.rs +++ b/src/test/ui/nll/user-annotations/dump-fn-method.rs @@ -11,7 +11,7 @@ trait Bazoom { fn method(&self, arg: T, arg2: U) { } } -impl Bazoom for T { +impl Bazoom for S { } fn foo<'a, T>(_: T) { } @@ -22,20 +22,29 @@ fn main() { let x = foo; x(22); - // Here: `u32` is given. - let x = foo::; //~ ERROR [u32] + // Here: `u32` is given, which doesn't contain any lifetimes, so we don't + // have any annotation. + let x = foo::; x(22); + let x = foo::<&'static u32>; //~ ERROR [&ReStatic u32] + x(&22); + // Here: we only want the `T` to be given, the rest should be variables. // // (`T` refers to the declaration of `Bazoom`) let x = <_ as Bazoom>::method::<_>; //~ ERROR [^0, u32, ^1] x(&22, 44, 66); - // Here: all are given - let x = >::method::; //~ ERROR [u8, u16, u32] + // Here: all are given and definitely contain no lifetimes, so we + // don't have any annotation. + let x = >::method::; x(&22, 44, 66); + // Here: all are given and we have a lifetime. + let x = >::method::; //~ ERROR [u8, &ReStatic u16, u32] + x(&22, &44, 66); + // Here: we want in particular that *only* the method `U` // annotation is given, the rest are variables. // diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr index a1a4e43e8a3e9..04ceb8e5f8495 100644 --- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr +++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr @@ -1,23 +1,23 @@ -error: user substs: UserSubsts { substs: [u32], user_self_ty: None } - --> $DIR/dump-fn-method.rs:26:13 +error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None } + --> $DIR/dump-fn-method.rs:30:13 | -LL | let x = foo::; //~ ERROR [u32] - | ^^^^^^^^^^ +LL | let x = foo::<&'static u32>; //~ ERROR [&ReStatic u32] + | ^^^^^^^^^^^^^^^^^^^ error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } - --> $DIR/dump-fn-method.rs:32:13 + --> $DIR/dump-fn-method.rs:36:13 | LL | let x = <_ as Bazoom>::method::<_>; //~ ERROR [^0, u32, ^1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } - --> $DIR/dump-fn-method.rs:36:13 +error: user substs: UserSubsts { substs: [u8, &ReStatic u16, u32], user_self_ty: None } + --> $DIR/dump-fn-method.rs:45:13 | -LL | let x = >::method::; //~ ERROR [u8, u16, u32] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = >::method::; //~ ERROR [u8, &ReStatic u16, u32] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } - --> $DIR/dump-fn-method.rs:44:5 + --> $DIR/dump-fn-method.rs:53:5 | LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32] | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/user-annotations/inherent-associated-constants.rs b/src/test/ui/nll/user-annotations/inherent-associated-constants.rs new file mode 100644 index 0000000000000..2490187605ac1 --- /dev/null +++ b/src/test/ui/nll/user-annotations/inherent-associated-constants.rs @@ -0,0 +1,17 @@ +#![feature(nll)] + +struct A<'a>(&'a ()); + +impl A<'static> { + const IC: i32 = 10; +} + +fn non_wf_associated_const<'a>(x: i32) { + A::<'a>::IC; //~ ERROR lifetime may not live long enough +} + +fn wf_associated_const<'a>(x: i32) { + A::<'static>::IC; +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr b/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr new file mode 100644 index 0000000000000..785b39ec887a0 --- /dev/null +++ b/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/inherent-associated-constants.rs:10:5 + | +LL | fn non_wf_associated_const<'a>(x: i32) { + | -- lifetime `'a` defined here +LL | A::<'a>::IC; //~ ERROR lifetime may not live long enough + | ^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/unicode-quote-chars.rs b/src/test/ui/parser/unicode-quote-chars.rs new file mode 100644 index 0000000000000..69644211b8a11 --- /dev/null +++ b/src/test/ui/parser/unicode-quote-chars.rs @@ -0,0 +1,7 @@ +// ignore-tidy-linelength + +fn main() { + println!(“hello world”); + //~^ ERROR unknown start of token: \u{201c} + //~^^ HELP Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '"' (Quotation Mark), but are not +} diff --git a/src/test/ui/parser/unicode-quote-chars.stderr b/src/test/ui/parser/unicode-quote-chars.stderr new file mode 100644 index 0000000000000..315e20cf854cd --- /dev/null +++ b/src/test/ui/parser/unicode-quote-chars.stderr @@ -0,0 +1,12 @@ +error: unknown start of token: /u{201c} + --> $DIR/unicode-quote-chars.rs:4:14 + | +LL | println!(“hello world”); + | ^ +help: Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '"' (Quotation Mark), but are not + | +LL | println!("hello world"); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/ref-suggestion.nll.stderr b/src/test/ui/ref-suggestion.nll.stderr index bef8dcca921e6..402f3c77cdb7b 100644 --- a/src/test/ui/ref-suggestion.nll.stderr +++ b/src/test/ui/ref-suggestion.nll.stderr @@ -25,7 +25,7 @@ LL | (Some(y), ()) => {}, | - value moved here ... LL | x; //~ ERROR use of partially moved value - | ^ value used here after move + | ^ value used here after partial move | = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait diff --git a/src/test/ui/unsized-locals/borrow-after-move.nll.stderr b/src/test/ui/unsized-locals/borrow-after-move.nll.stderr index 0e6a6f6369a15..010e182674b75 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.nll.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.nll.stderr @@ -5,7 +5,7 @@ LL | let y = *x; | -- value moved here LL | drop_unsized(y); LL | println!("{}", &x); - | ^^ value borrowed here after move + | ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -27,7 +27,7 @@ LL | let y = *x; | -- value moved here LL | y.foo(); LL | println!("{}", &x); - | ^^ value borrowed here after move + | ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -48,7 +48,7 @@ error[E0382]: borrow of moved value: `x` LL | x.foo(); | - value moved here LL | println!("{}", &x); - | ^^ value borrowed here after move + | ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait diff --git a/src/test/ui/unsized-locals/double-move.nll.stderr b/src/test/ui/unsized-locals/double-move.nll.stderr index e40289af5ad3d..c0c3e436f535b 100644 --- a/src/test/ui/unsized-locals/double-move.nll.stderr +++ b/src/test/ui/unsized-locals/double-move.nll.stderr @@ -14,7 +14,7 @@ error[E0382]: use of moved value: `x` LL | let _y = *x; | -- value moved here LL | drop_unsized(x); //~ERROR use of moved value - | ^ value used here after move + | ^ value used here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait