From 14999dd74b38ca79b80772f4f33425574faff89a Mon Sep 17 00:00:00 2001 From: Andreas Molzer Date: Wed, 29 Jan 2020 21:26:16 +0100 Subject: [PATCH 01/18] Add methods to leak RefCell borrows to references Usually, references to the interior are only created by the `Deref` and `DerefMut` impl of the guards `Ref` and `RefMut`. Note that `RefCell` already has to cope with leaks of such guards which, when it occurs, effectively makes it impossible to ever acquire a mutable guard or any guard for `Ref` and `RefMut` respectively. It is already safe to use this to create a reference to the inner of the ref cell that lives as long as the reference to the `RefCell` itself, e.g. ```rust fn leak(r: &RefCell) -> Option<&usize> { let guard = r.try_borrow().ok()?; let leaked = Box::leak(Box::new(guard)); Some(&*leaked) } ``` The newly added methods allow the same reference conversion without an indirection over a leaked allocation and composing with both borrow and try_borrow without additional method combinations. --- src/libcore/cell.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index e7eecf7540ad7..b1d799953e710 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1245,6 +1245,38 @@ impl<'b, T: ?Sized> Ref<'b, T> { let borrow = orig.borrow.clone(); (Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow }) } + + /// Convert into a reference to the underlying data. + /// + /// The underlying `RefCell` can never be mutably borrowed from again and will always appear + /// already immutably borrowed. It can still be immutably borrowed until more than `isize::MAX` + /// `Ref`s of this `RefCell` have been leaked, through this function or another leak, in total. + /// + /// This is an associated function that needs to be used as + /// `Ref::leak(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_leak)] + /// use std::cell::{RefCell, Ref}; + /// let cell = RefCell::new(0); + /// + /// let value = Ref::leak(cell.borrow()); + /// assert_eq!(*value, 0); + /// + /// assert!(cell.try_borrow().is_ok()); + /// assert!(cell.try_borrow_mut().is_err()); + /// ``` + #[unstable(feature = "cell_leak", issue = "none")] + pub fn leak(orig: Ref<'b, T>) -> &'b T { + // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never + // goes back to UNUSED again. No further references can be created from the original cell, + // making the current borrow the only reference for the remaining lifetime. + mem::forget(orig.borrow); + orig.value + } } #[unstable(feature = "coerce_unsized", issue = "27732")] @@ -1330,6 +1362,37 @@ impl<'b, T: ?Sized> RefMut<'b, T> { let borrow = orig.borrow.clone(); (RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow }) } + + /// Convert into a mutable reference to the underlying data. + /// + /// The underlying `RefCell` can not be borrowed from again and will always appear already + /// mutably borrowed, making the returned reference the only to the interior. + /// + /// This is an associated function that needs to be used as + /// `RefMut::leak(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_leak)] + /// use std::cell::{RefCell, RefMut}; + /// let cell = RefCell::new(0); + /// + /// let value = RefMut::leak(cell.borrow_mut()); + /// assert_eq!(*value, 0); + /// *value = 1; + /// + /// assert!(cell.try_borrow_mut().is_err()); + /// ``` + #[unstable(feature = "cell_leak", issue = "none")] + pub fn leak(orig: RefMut<'b, T>) -> &'b mut T { + // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never + // goes back to UNUSED again. No further references can be created from the original cell, + // making the current borrow the only reference for the remaining lifetime. + mem::forget(orig.borrow); + orig.value + } } struct BorrowRefMut<'b> { From 178de46116b4fc8c1d9b30007f5e5ed24c809881 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 12:55:13 -0500 Subject: [PATCH 02/18] Add primitive module to libcore/std This re-exports the primitive types from libcore at `core::primitive` to allow macro authors to have a reliable location to use them from. --- src/libcore/lib.rs | 3 + src/libcore/primitive.rs | 67 +++++++++++++++++++ src/libstd/lib.rs | 5 +- .../resolve/resolve-primitive-fallback.stderr | 5 ++ src/test/ui/shadow-bool.rs | 18 +++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/libcore/primitive.rs create mode 100644 src/test/ui/shadow-bool.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1fd70e1a1b049..257a6d371b730 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -262,6 +262,9 @@ mod bool; mod tuple; mod unit; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub mod primitive; + // Pull in the `core_arch` crate directly into libcore. The contents of // `core_arch` are in a different repository: rust-lang/stdarch. // diff --git a/src/libcore/primitive.rs b/src/libcore/primitive.rs new file mode 100644 index 0000000000000..d37bbfaf5dfd4 --- /dev/null +++ b/src/libcore/primitive.rs @@ -0,0 +1,67 @@ +//! This module reexports the primitive types to allow usage that is not +//! possibly shadowed by other declared types. +//! +//! This is normally only useful in macro generated code. +//! +//! An example of this is when generating a new struct and an impl for it: +//! +//! ```rust,compile_fail +//! pub struct bool; +//! +//! impl QueryId for bool { +//! const SOME_PROPERTY: bool = true; +//! } +//! +//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; } +//! ``` +//! +//! Note that the `SOME_PROPERTY` associated constant would not compile, as its +//! type `bool` refers to the struct, rather than to the primitive bool type. +//! +//! A correct implementation could look like: +//! +//! ```rust +//! # #[allow(non_camel_case_types)] +//! pub struct bool; +//! +//! impl QueryId for bool { +//! const SOME_PROPERTY: core::primitive::bool = true; +//! } +//! +//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; } +//! ``` + +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use bool; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use char; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use f32; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use f64; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i128; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i16; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i32; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i64; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i8; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use isize; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use str; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u128; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u16; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u32; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u64; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u8; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use usize; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f9c9f224730da..2b54481ab5670 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -233,12 +233,12 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(atomic_mut_ptr)] #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] #![feature(assoc_int_consts)] #![feature(associated_type_bounds)] +#![feature(atomic_mut_ptr)] #![feature(box_syntax)] #![feature(c_variadic)] #![feature(cfg_target_has_atomic)] @@ -550,6 +550,9 @@ pub use core::{ trace_macros, }; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use core::primitive; + // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/test/ui/resolve/resolve-primitive-fallback.stderr b/src/test/ui/resolve/resolve-primitive-fallback.stderr index 92c2a03298381..72a854346fad0 100644 --- a/src/test/ui/resolve/resolve-primitive-fallback.stderr +++ b/src/test/ui/resolve/resolve-primitive-fallback.stderr @@ -9,6 +9,11 @@ error[E0412]: cannot find type `u8` in the crate root | LL | let _: ::u8; | ^^ not found in the crate root + | +help: possible candidate is found in another module, you can import it into scope + | +LL | use std::primitive::u8; + | error[E0061]: this function takes 0 parameters but 1 parameter was supplied --> $DIR/resolve-primitive-fallback.rs:3:5 diff --git a/src/test/ui/shadow-bool.rs b/src/test/ui/shadow-bool.rs new file mode 100644 index 0000000000000..f290a329eaac2 --- /dev/null +++ b/src/test/ui/shadow-bool.rs @@ -0,0 +1,18 @@ +// check-pass + +mod bar { + pub trait QueryId { + const SOME_PROPERTY: bool; + } +} + +use bar::QueryId; + +#[allow(non_camel_case_types)] +pub struct bool; + +impl QueryId for bool { + const SOME_PROPERTY: core::primitive::bool = true; +} + +fn main() {} From 99b4357f1763f7d98b9b78221207e09d075513b1 Mon Sep 17 00:00:00 2001 From: Andreas Molzer Date: Wed, 12 Feb 2020 16:56:09 +0100 Subject: [PATCH 03/18] Add tracking number, adjust documentation wording --- src/libcore/cell.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index b1d799953e710..17222b27b2d70 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1249,8 +1249,9 @@ impl<'b, T: ?Sized> Ref<'b, T> { /// Convert into a reference to the underlying data. /// /// The underlying `RefCell` can never be mutably borrowed from again and will always appear - /// already immutably borrowed. It can still be immutably borrowed until more than `isize::MAX` - /// `Ref`s of this `RefCell` have been leaked, through this function or another leak, in total. + /// already immutably borrowed. It is not a good idea to leak more than a constant number of + /// references. The `RefCell` can be immutably borrowed again if only a smaller number of leaks + /// have occurred in total. /// /// This is an associated function that needs to be used as /// `Ref::leak(...)`. A method would interfere with methods of the @@ -1269,7 +1270,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { /// assert!(cell.try_borrow().is_ok()); /// assert!(cell.try_borrow_mut().is_err()); /// ``` - #[unstable(feature = "cell_leak", issue = "none")] + #[unstable(feature = "cell_leak", issue = "69099")] pub fn leak(orig: Ref<'b, T>) -> &'b T { // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never // goes back to UNUSED again. No further references can be created from the original cell, @@ -1385,7 +1386,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> { /// /// assert!(cell.try_borrow_mut().is_err()); /// ``` - #[unstable(feature = "cell_leak", issue = "none")] + #[unstable(feature = "cell_leak", issue = "69099")] pub fn leak(orig: RefMut<'b, T>) -> &'b mut T { // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never // goes back to UNUSED again. No further references can be created from the original cell, From bec5d37ee19c33bec96ed235f0197317d3728e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 14:44:16 +0100 Subject: [PATCH 04/18] debug_assert a few more raw pointer methods --- src/libcore/intrinsics.rs | 9 +++++---- src/libcore/ptr/mod.rs | 12 +++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2cee23a5c752c..9a23b54dfa0a5 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1423,13 +1423,14 @@ pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { } /// Checks whether the regions of memory starting at `src` and `dst` of size -/// `count * size_of::()` overlap. -fn overlaps(src: *const T, dst: *const T, count: usize) -> bool { +/// `count * size_of::()` do *not* overlap. +pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) -> bool { let src_usize = src as usize; let dst_usize = dst as usize; let size = mem::size_of::().checked_mul(count).unwrap(); let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize }; - size > diff + let overlaps = size > diff; + !overlaps } /// Copies `count * size_of::()` bytes from `src` to `dst`. The source @@ -1524,7 +1525,7 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer"); debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer"); - debug_assert!(!overlaps(src, dst, count), "attempt to copy to overlapping memory"); + debug_assert!(is_nonoverlapping(src, dst, count), "attempt to copy to overlapping memory"); copy_nonoverlapping(src, dst, count) } diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 0ee50966f968c..ce21773165a6a 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -72,7 +72,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::hash; -use crate::intrinsics; +use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping}; use crate::mem::{self, MaybeUninit}; #[stable(feature = "rust1", since = "1.0.0")] @@ -389,6 +389,10 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { + debug_assert!(is_aligned_and_not_null(x), "attempt to swap unaligned or null pointer"); + debug_assert!(is_aligned_and_not_null(y), "attempt to swap unaligned or null pointer"); + debug_assert!(is_nonoverlapping(x, y, count), "attempt to swap overlapping memory"); + let x = x as *mut u8; let y = y as *mut u8; let len = mem::size_of::() * count; @@ -612,6 +616,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { + // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); tmp.assume_init() @@ -703,6 +708,7 @@ pub unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn read_unaligned(src: *const T) -> T { + // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); tmp.assume_init() @@ -795,6 +801,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { + debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); intrinsics::move_val_init(&mut *dst, src) } @@ -887,6 +894,7 @@ pub unsafe fn write(dst: *mut T, src: T) { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { + // `copy_nonoverlapping` takes care of debug_assert. copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::()); mem::forget(src); } @@ -956,6 +964,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn read_volatile(src: *const T) -> T { + debug_assert!(is_aligned_and_not_null(src), "attempt to read from unaligned or null pointer"); intrinsics::volatile_load(src) } @@ -1024,6 +1033,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn write_volatile(dst: *mut T, src: T) { + debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); intrinsics::volatile_store(dst, src); } From 7a6b451984fffee4eb4c8161989aaa3d20cb6855 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Feb 2020 21:43:51 +0100 Subject: [PATCH 05/18] increase slack for stack size test --- src/test/ui/issues/issue-40883.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/issues/issue-40883.rs b/src/test/ui/issues/issue-40883.rs index 37e61b1b0e603..5a51acc73e85c 100644 --- a/src/test/ui/issues/issue-40883.rs +++ b/src/test/ui/issues/issue-40883.rs @@ -78,8 +78,8 @@ fn verify_stack_usage(before_ptr: *mut Vec) { let stack_usage = isize::abs( (&mut stack_var as *mut _ as isize) - (before_ptr as isize)) as usize; - // give space for 2 copies of `Big` + 128 "misc" bytes. - if stack_usage > mem::size_of::() * 2 + 128 { + // give space for 2 copies of `Big` + 256 "misc" bytes. + if stack_usage > mem::size_of::() * 2 + 256 { panic!("used {} bytes of stack, but `struct Big` is only {} bytes", stack_usage, mem::size_of::()); } From e355a330772a7b605649651f7e670ea636e73a6e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 23 Feb 2020 01:29:36 +0300 Subject: [PATCH 06/18] Deduplicate identifier printing a bit --- src/librustc_ast_pretty/pprust.rs | 42 ++----------------- src/librustc_hir/print.rs | 6 +-- src/librustc_span/symbol.rs | 67 +++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 27cef8502a1d1..4e69253c34bf6 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -3,7 +3,7 @@ use crate::pp::{self, Breaks}; use rustc_span::edition::Edition; use rustc_span::source_map::{SourceMap, Spanned}; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::{kw, sym, IdentPrinter}; use rustc_span::{BytePos, FileName, Span}; use syntax::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use syntax::ast::{Attribute, GenericArg, MacArgs}; @@ -196,40 +196,6 @@ pub fn literal_to_string(lit: token::Lit) -> String { out } -/// Print an ident from AST, `$crate` is converted into its respective crate name. -pub fn ast_ident_to_string(ident: ast::Ident, is_raw: bool) -> String { - ident_to_string(ident.name, is_raw, Some(ident.span)) -} - -// AST pretty-printer is used as a fallback for turning AST structures into token streams for -// proc macros. Additionally, proc macros may stringify their input and expect it survive the -// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30). -// So we need to somehow pretty-print `$crate` in a way preserving at least some of its -// hygiene data, most importantly name of the crate it refers to. -// As a result we print `$crate` as `crate` if it refers to the local crate -// and as `::other_crate_name` if it refers to some other crate. -// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing, -// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents, -// so we should not perform this lossy conversion if the top level call to the pretty-printer was -// done for a token stream or a single token. -fn ident_to_string(name: ast::Name, is_raw: bool, convert_dollar_crate: Option) -> String { - if is_raw { - format!("r#{}", name) - } else { - if name == kw::DollarCrate { - if let Some(span) = convert_dollar_crate { - let converted = span.ctxt().dollar_crate_name(); - return if converted.is_path_segment_keyword() { - converted.to_string() - } else { - format!("::{}", converted) - }; - } - } - name.to_string() - } -} - /// Print the token kind precisely, without converting `$crate` into its respective crate name. pub fn token_kind_to_string(tok: &TokenKind) -> String { token_kind_to_string_ext(tok, None) @@ -280,7 +246,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) token::Literal(lit) => literal_to_string(lit), /* Name components */ - token::Ident(s, is_raw) => ident_to_string(s, is_raw, convert_dollar_crate), + token::Ident(s, is_raw) => IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string(), token::Lifetime(s) => s.to_string(), /* Other */ @@ -315,7 +281,7 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String { 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, is_raw) => ast_ident_to_string(e, is_raw), + token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(), token::NtLifetime(e) => e.to_string(), token::NtLiteral(ref e) => expr_to_string(e), token::NtTT(ref tree) => tt_to_string(tree.clone()), @@ -819,7 +785,7 @@ impl<'a> PrintState<'a> for State<'a> { } fn print_ident(&mut self, ident: ast::Ident) { - self.s.word(ast_ident_to_string(ident, ident.is_raw_guess())); + self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); self.ann.post(self, AnnNode::Ident(&ident)) } diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index e49f99fb717a3..92bd8b1ba5f84 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -1,8 +1,8 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; -use rustc_ast_pretty::pprust::{self, Comments, PrintState}; +use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_span::source_map::{SourceMap, Spanned}; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, IdentPrinter}; use rustc_span::{self, BytePos, FileName}; use rustc_target::spec::abi::Abi; use syntax::ast; @@ -126,7 +126,7 @@ impl<'a> PrintState<'a> for State<'a> { } fn print_ident(&mut self, ident: ast::Ident) { - self.s.word(pprust::ast_ident_to_string(ident, ident.is_raw_guess())); + self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); self.ann.post(self, AnnNode::Name(&ident.name)) } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 97708d91d7e2a..b8e5ea97f4e47 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -893,19 +893,17 @@ impl Hash for Ident { impl fmt::Debug for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.is_raw_guess() { - write!(f, "r#")?; - } - write!(f, "{}{:?}", self.name, self.span.ctxt()) + fmt::Display::fmt(self, f)?; + fmt::Debug::fmt(&self.span.ctxt(), f) } } +/// This implementation is supposed to be used in error messages, so it's expected to be identical +/// to printing the original identifier token written in source code (`token_to_string`), +/// except that AST identifiers don't keep the rawness flag, so we have to guess it. impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.is_raw_guess() { - write!(f, "r#")?; - } - fmt::Display::fmt(&self.name, f) + fmt::Display::fmt(&IdentPrinter::new(self.name, self.is_raw_guess(), None), f) } } @@ -929,6 +927,59 @@ impl UseSpecializedDecodable for Ident { } } +/// This is the most general way to print identifiers. +/// AST pretty-printer is used as a fallback for turning AST structures into token streams for +/// proc macros. Additionally, proc macros may stringify their input and expect it survive the +/// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30). +/// So we need to somehow pretty-print `$crate` in a way preserving at least some of its +/// hygiene data, most importantly name of the crate it refers to. +/// As a result we print `$crate` as `crate` if it refers to the local crate +/// and as `::other_crate_name` if it refers to some other crate. +/// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing, +/// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents, +/// so we should not perform this lossy conversion if the top level call to the pretty-printer was +/// done for a token stream or a single token. +pub struct IdentPrinter { + symbol: Symbol, + is_raw: bool, + /// Span used for retrieving the crate name to which `$crate` refers to, + /// if this field is `None` then the `$crate` conversion doesn't happen. + convert_dollar_crate: Option, +} + +impl IdentPrinter { + /// The most general `IdentPrinter` constructor. Do not use this. + pub fn new(symbol: Symbol, is_raw: bool, convert_dollar_crate: Option) -> IdentPrinter { + IdentPrinter { symbol, is_raw, convert_dollar_crate } + } + + /// This implementation is supposed to be used when printing identifiers + /// as a part of pretty-printing for larger AST pieces. + /// Do not use this either. + pub fn for_ast_ident(ident: Ident, is_raw: bool) -> IdentPrinter { + IdentPrinter::new(ident.name, is_raw, Some(ident.span)) + } +} + +impl fmt::Display for IdentPrinter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_raw { + f.write_str("r#")?; + } else { + if self.symbol == kw::DollarCrate { + if let Some(span) = self.convert_dollar_crate { + let converted = span.ctxt().dollar_crate_name(); + if !converted.is_path_segment_keyword() { + f.write_str("::")?; + } + return fmt::Display::fmt(&converted, f); + } + } + } + fmt::Display::fmt(&self.symbol, f) + } +} + /// An interned string. /// /// Internally, a `Symbol` is implemented as an index, and all operations From 9c3ee1bc351fcfabcfd47947dc44b0c020427181 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 23 Feb 2020 23:59:39 -0800 Subject: [PATCH 07/18] Bump core::primitive to 1.43 --- src/libcore/lib.rs | 2 +- src/libcore/primitive.rs | 34 +++++++++++++++++----------------- src/libstd/lib.rs | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 257a6d371b730..b939462afc767 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -262,7 +262,7 @@ mod bool; mod tuple; mod unit; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub mod primitive; // Pull in the `core_arch` crate directly into libcore. The contents of diff --git a/src/libcore/primitive.rs b/src/libcore/primitive.rs index d37bbfaf5dfd4..e20b2c5c9382a 100644 --- a/src/libcore/primitive.rs +++ b/src/libcore/primitive.rs @@ -31,37 +31,37 @@ //! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; } //! ``` -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use bool; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use char; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use f32; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use f64; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use i128; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use i16; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use i32; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use i64; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use i8; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use isize; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use str; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use u128; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use u16; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use u32; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use u64; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use u8; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use usize; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 2b54481ab5670..a495d29cc47c5 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -550,7 +550,7 @@ pub use core::{ trace_macros, }; -#[stable(feature = "core_primitive", since = "1.42.0")] +#[stable(feature = "core_primitive", since = "1.43.0")] pub use core::primitive; // Include a number of private modules that exist solely to provide From 329022dfad7199053cbe225e8d7d13ebbd5eb230 Mon Sep 17 00:00:00 2001 From: Andreas Molzer Date: Mon, 24 Feb 2020 11:23:47 +0100 Subject: [PATCH 08/18] Address method comments --- src/libcore/cell.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 17222b27b2d70..b6d5c6ae27db7 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1272,9 +1272,8 @@ impl<'b, T: ?Sized> Ref<'b, T> { /// ``` #[unstable(feature = "cell_leak", issue = "69099")] pub fn leak(orig: Ref<'b, T>) -> &'b T { - // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never - // goes back to UNUSED again. No further references can be created from the original cell, - // making the current borrow the only reference for the remaining lifetime. + // By forgetting this Ref we ensure that the borrow counter in the RefCell never goes back + // to UNUSED again. No further mutable references can be created from the original cell. mem::forget(orig.borrow); orig.value } From 5ae4500eff740b5935fc24b23e3c4be9789caf37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Mon, 24 Feb 2020 14:42:14 +0100 Subject: [PATCH 09/18] remove redundant clones in librustc_mir_build and librustc_data_structures --- src/librustc_data_structures/obligation_forest/mod.rs | 4 ++-- src/librustc_mir_build/build/matches/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 334daddba8820..6711a49b2b7c1 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -314,7 +314,7 @@ impl ObligationForest { return Ok(()); } - match self.active_cache.entry(obligation.as_cache_key().clone()) { + match self.active_cache.entry(obligation.as_cache_key()) { Entry::Occupied(o) => { let node = &mut self.nodes[*o.get()]; if let Some(parent_index) = parent { @@ -385,7 +385,7 @@ impl ObligationForest { self.error_cache .entry(node.obligation_tree_id) .or_default() - .insert(node.obligation.as_cache_key().clone()); + .insert(node.obligation.as_cache_key()); } /// Performs a pass through the obligation list. This must diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index f900ae45b94d6..7995125524314 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -649,7 +649,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } PatKind::Or { ref pats } => { - self.visit_bindings(&pats[0], pattern_user_ty.clone(), f); + self.visit_bindings(&pats[0], pattern_user_ty, f); } } } From d4a005bd03dd2ef229bb809d128f9b31c159c18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Mon, 24 Feb 2020 14:48:40 +0100 Subject: [PATCH 10/18] librustc{, codegen_ssa,infer,mir_build}: don't clone types that are copy --- src/librustc/ty/context.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/query/job.rs | 2 +- src/librustc_codegen_ssa/mir/constant.rs | 2 +- src/librustc_infer/infer/lexical_region_resolve/mod.rs | 2 +- src/librustc_mir_build/build/expr/into.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e59738d888608..c027d6f61b01f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1526,7 +1526,7 @@ impl<'tcx> GlobalCtxt<'tcx> { ty::tls::with_related_context(tcx, |icx| { let new_icx = ty::tls::ImplicitCtxt { tcx, - query: icx.query.clone(), + query: icx.query, diagnostics: icx.diagnostics, layout_depth: icx.layout_depth, task_deps: icx.task_deps, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a195c944ff28d..d17ef3a6c9a8c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1447,7 +1447,7 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { ty::Predicate::Trait( - ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }), self.constness, ) } diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index 8aae57e72cd52..3394fed840222 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -173,7 +173,7 @@ impl<'tcx> QueryLatch<'tcx> { return CycleError { usage, cycle }; } - current_job = info.job.parent.clone(); + current_job = info.job.parent; } panic!("did not find a cycle") diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 9ceb75a603bc4..4248627dccaf2 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -31,7 +31,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => { let val = self.eval_mir_constant(constant)?; let ty = self.monomorphize(&constant.literal.ty); - Ok(OperandRef::from_const(bx, val.clone(), ty)) + Ok(OperandRef::from_const(bx, val, ty)) } } } diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs index 0b5536219e566..fc9f3bb076745 100644 --- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs @@ -848,7 +848,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { for upper_bound in &upper_bounds { if let ty::RePlaceholder(p) = upper_bound.region { if node_universe.cannot_name(p.universe) { - let origin = self.var_infos[node_idx].origin.clone(); + let origin = self.var_infos[node_idx].origin; errors.push(RegionResolutionError::UpperBoundUniverseConflict( node_idx, origin, diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs index 51b0b5bc7cb0b..4583e244f493d 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/src/librustc_mir_build/build/expr/into.rs @@ -376,7 +376,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TerminatorKind::Yield { value, resume, - resume_arg: destination.clone(), + resume_arg: *destination, drop: cleanup, }, ); From 1892ff7aa6f7d82cbe18a531da3566fbd1939e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Mon, 24 Feb 2020 14:53:55 +0100 Subject: [PATCH 11/18] librustc_macros: remove redundant single component path import --- src/librustc_macros/src/hash_stable.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_macros/src/hash_stable.rs b/src/librustc_macros/src/hash_stable.rs index e6f457dd663c2..dc6ae961e5a6e 100644 --- a/src/librustc_macros/src/hash_stable.rs +++ b/src/librustc_macros/src/hash_stable.rs @@ -1,7 +1,6 @@ use proc_macro2::{self, Ident}; use quote::quote; use syn::{self, parse_quote, Meta, NestedMeta}; -use synstructure; struct Attributes { ignore: bool, From d134385823525255546deaa930af2d5b1eada0df Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 24 Feb 2020 12:06:45 +0300 Subject: [PATCH 12/18] syntax: Remove `Nt(Impl,Trait,Foreign)Item` --- src/librustc_ast_pretty/pprust.rs | 11 ---------- src/librustc_expand/expand.rs | 11 +++++++--- src/librustc_parse/lib.rs | 3 --- src/librustc_parse/parser/item.rs | 8 ------- src/libsyntax/ast.rs | 23 ++++++++++++++++++++ src/libsyntax/mut_visit.rs | 13 ----------- src/libsyntax/token.rs | 9 -------- src/test/ui/proc-macro/trait-fn-args-2015.rs | 14 ++++++++++++ 8 files changed, 45 insertions(+), 47 deletions(-) create mode 100644 src/test/ui/proc-macro/trait-fn-args-2015.rs diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 2b223d92ff198..802d5cfbfc442 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -319,10 +319,7 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String { token::NtLifetime(e) => e.to_string(), token::NtLiteral(ref e) => expr_to_string(e), token::NtTT(ref tree) => tt_to_string(tree.clone()), - // FIXME(Centril): merge these variants. - token::NtImplItem(ref e) | token::NtTraitItem(ref e) => assoc_item_to_string(e), token::NtVis(ref e) => vis_to_string(e), - token::NtForeignItem(ref e) => foreign_item_to_string(e), } } @@ -358,10 +355,6 @@ pub fn item_to_string(i: &ast::Item) -> String { to_string(|s| s.print_item(i)) } -fn assoc_item_to_string(i: &ast::AssocItem) -> String { - to_string(|s| s.print_assoc_item(i)) -} - pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String { to_string(|s| s.print_generic_params(generic_params)) } @@ -404,10 +397,6 @@ pub fn param_to_string(arg: &ast::Param) -> String { to_string(|s| s.print_param(arg, false)) } -fn foreign_item_to_string(arg: &ast::ForeignItem) -> String { - to_string(|s| s.print_foreign_item(arg)) -} - fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { format!("{}{}", to_string(|s| s.print_visibility(vis)), s) } diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index bbea066b048d2..8ed7bbf6e1276 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -669,12 +669,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); + // `Annotatable` can be converted into tokens directly, but we are packing it + // into a nonterminal as a piece of AST to make the produced token stream + // look nicer in pretty-printed form. This may be no longer necessary. let item_tok = TokenTree::token( token::Interpolated(Lrc::new(match item { Annotatable::Item(item) => token::NtItem(item), - Annotatable::TraitItem(item) => token::NtTraitItem(item), - Annotatable::ImplItem(item) => token::NtImplItem(item), - Annotatable::ForeignItem(item) => token::NtForeignItem(item), + Annotatable::TraitItem(item) + | Annotatable::ImplItem(item) + | Annotatable::ForeignItem(item) => { + token::NtItem(P(item.and_then(ast::AssocItem::into_item))) + } Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), Annotatable::Expr(expr) => token::NtExpr(expr), Annotatable::Arm(..) diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index a0b8415b3e17e..bd0b189d4fd4d 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -314,9 +314,6 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Nonterminal::NtItem(ref item) => { prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) } - Nonterminal::NtTraitItem(ref item) | Nonterminal::NtImplItem(ref item) => { - prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) - } Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d6da627054196..d9e28716c84c7 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -632,16 +632,10 @@ impl<'a> Parser<'a> { } pub fn parse_impl_item(&mut self) -> PResult<'a, Option>>> { - maybe_whole!(self, NtImplItem, |x| Some(Some(x))); self.parse_assoc_item(|_| true) } pub fn parse_trait_item(&mut self) -> PResult<'a, Option>>> { - maybe_whole!(self, NtTraitItem, |x| Some(Some(x))); - // This is somewhat dubious; We don't want to allow - // param names to be left off if there is a definition... - // - // We don't allow param names to be left off in edition 2018. self.parse_assoc_item(|t| t.span.rust_2018()) } @@ -834,8 +828,6 @@ impl<'a> Parser<'a> { /// Parses a foreign item (one in an `extern { ... }` block). pub fn parse_foreign_item(&mut self) -> PResult<'a, Option>>> { - maybe_whole!(self, NtForeignItem, |item| Some(Some(item))); - Ok(self.parse_item_(|_| true)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| { let kind = match kind { ItemKind::Mac(a) => ForeignItemKind::Macro(a), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 19c705fa99753..62ff4f5183a70 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2441,6 +2441,13 @@ impl Item { } } +impl Item { + pub fn into_item(self) -> Item { + let Item { attrs, id, span, vis, ident, kind, tokens } = self; + Item { attrs, id, span, vis, ident, kind: kind.into_item_kind(), tokens } + } +} + /// `extern` qualifier on a function item or function type. #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub enum Extern { @@ -2617,6 +2624,10 @@ impl ItemKind { } } +pub trait IntoItemKind { + fn into_item_kind(self) -> ItemKind; +} + // FIXME(Centril): These definitions should be unmerged; // see https://github.com/rust-lang/rust/pull/69194#discussion_r379899975 pub type ForeignItem = Item; @@ -2656,3 +2667,15 @@ impl AssocItemKind { } } } + +impl IntoItemKind for AssocItemKind { + fn into_item_kind(self) -> ItemKind { + match self { + AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c), + AssocItemKind::Static(a, b, c) => ItemKind::Static(a, b, c), + AssocItemKind::Fn(a, b, c, d) => ItemKind::Fn(a, b, c, d), + AssocItemKind::TyAlias(a, b, c, d) => ItemKind::TyAlias(a, b, c, d), + AssocItemKind::Macro(a) => ItemKind::Mac(a), + } + } +} diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 05bb07cd4b90a..b3abd4fc755e4 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -711,20 +711,7 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: } token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), - token::NtImplItem(item) => visit_clobber(item, |item| { - // See reasoning above. - vis.flat_map_impl_item(item).expect_one("expected visitor to produce exactly one item") - }), - token::NtTraitItem(item) => visit_clobber(item, |item| { - // See reasoning above. - vis.flat_map_trait_item(item).expect_one("expected visitor to produce exactly one item") - }), token::NtVis(visib) => vis.visit_vis(visib), - token::NtForeignItem(item) => visit_clobber(item, |item| { - // See reasoning above. - vis.flat_map_foreign_item(item) - .expect_one("expected visitor to produce exactly one item") - }), } } diff --git a/src/libsyntax/token.rs b/src/libsyntax/token.rs index 6eeee49881579..52bf50604fb30 100644 --- a/src/libsyntax/token.rs +++ b/src/libsyntax/token.rs @@ -712,12 +712,6 @@ pub enum Nonterminal { NtPath(ast::Path), NtVis(ast::Visibility), NtTT(TokenTree), - // Used only for passing items to proc macro attributes (they are not - // strictly necessary for that, `Annotatable` can be converted into - // tokens directly, but doing that naively regresses pretty-printing). - NtTraitItem(P), - NtImplItem(P), - NtForeignItem(P), } // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -755,9 +749,6 @@ impl fmt::Debug for Nonterminal { NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), NtTT(..) => f.pad("NtTT(..)"), - NtImplItem(..) => f.pad("NtImplItem(..)"), - NtTraitItem(..) => f.pad("NtTraitItem(..)"), - NtForeignItem(..) => f.pad("NtForeignItem(..)"), NtVis(..) => f.pad("NtVis(..)"), NtLifetime(..) => f.pad("NtLifetime(..)"), } diff --git a/src/test/ui/proc-macro/trait-fn-args-2015.rs b/src/test/ui/proc-macro/trait-fn-args-2015.rs new file mode 100644 index 0000000000000..3a448d4b2201d --- /dev/null +++ b/src/test/ui/proc-macro/trait-fn-args-2015.rs @@ -0,0 +1,14 @@ +// Unnamed arguments in trait functions can be passed through proc macros on 2015 edition. + +// check-pass +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +trait Tr { + #[identity_attr] + fn method(u8); +} + +fn main() {} From 245e15b4ac07e1e780921e3512ae2b9fb2a4a718 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 23 Feb 2020 13:49:19 +0100 Subject: [PATCH 13/18] parse: extract `parse_stmt_item` & `parse_stmt_path_start`. --- src/librustc_parse/parser/stmt.rs | 65 ++++++++++++++++--------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index bbfbe9c20df94..4d86836ff900a 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -58,33 +58,11 @@ impl<'a> Parser<'a> { // (1 token), but it fact not a path. Also, we avoid stealing syntax from `parse_item_`. if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_path_start_item() { - let path = self.parse_path(PathStyle::Expr)?; - - if self.eat(&token::Not) { - return self.parse_stmt_mac(lo, attrs.into(), path); - } - - let expr = if self.check(&token::OpenDelim(token::Brace)) { - self.parse_struct_expr(lo, path, AttrVec::new())? - } else { - let hi = self.prev_span; - self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new()) - }; - - let expr = self.with_res(Restrictions::STMT_EXPR, |this| { - let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; - this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) - })?; - return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr)))); + return self.parse_stmt_path_start(lo, attrs).map(Some); } - // FIXME: Bad copy of attrs - let old_directory_ownership = - mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); - let item = self.parse_item_common(attrs.clone(), false, true, |_| true)?; - self.directory.ownership = old_directory_ownership; - - if let Some(item) = item { + if let Some(item) = self.parse_stmt_item(attrs.clone())? { + // FIXME: Bad copy of attrs return Ok(Some(self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))))); } @@ -117,14 +95,37 @@ impl<'a> Parser<'a> { Ok(Some(self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)))) } + fn parse_stmt_item(&mut self, attrs: Vec) -> PResult<'a, Option> { + let old = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); + let item = self.parse_item_common(attrs.clone(), false, true, |_| true)?; + self.directory.ownership = old; + Ok(item) + } + + fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec) -> PResult<'a, Stmt> { + let path = self.parse_path(PathStyle::Expr)?; + + if self.eat(&token::Not) { + return self.parse_stmt_mac(lo, attrs.into(), path); + } + + let expr = if self.check(&token::OpenDelim(token::Brace)) { + self.parse_struct_expr(lo, path, AttrVec::new())? + } else { + let hi = self.prev_span; + self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new()) + }; + + let expr = self.with_res(Restrictions::STMT_EXPR, |this| { + let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; + this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) + })?; + Ok(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr))) + } + /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`. /// At this point, the `!` token after the path has already been eaten. - fn parse_stmt_mac( - &mut self, - lo: Span, - attrs: AttrVec, - path: ast::Path, - ) -> PResult<'a, Option> { + fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> { let args = self.parse_mac_args()?; let delim = args.delim(); let hi = self.prev_span; @@ -145,7 +146,7 @@ impl<'a> Parser<'a> { let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; - Ok(Some(self.mk_stmt(lo.to(hi), kind))) + Ok(self.mk_stmt(lo.to(hi), kind)) } /// Error on outer attributes in this context. From 32295aee6ef45e1602d8df6033be47e06225a319 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 23 Feb 2020 14:10:03 +0100 Subject: [PATCH 14/18] parse: simplify `parse_stmt_without_recovery`. --- src/librustc_parse/parser/stmt.rs | 65 ++++++++++++++----------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index 4d86836ff900a..a1078a59239c7 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -35,39 +35,33 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - if self.eat_keyword(kw::Let) { - return self.parse_local_mk(lo, attrs.into()).map(Some); - } - if self.is_kw_followed_by_ident(kw::Mut) { - return self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut"); - } - if self.is_kw_followed_by_ident(kw::Auto) { + let stmt = if self.eat_keyword(kw::Let) { + self.parse_local_mk(lo, attrs.into())? + } else if self.is_kw_followed_by_ident(kw::Mut) { + self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")? + } else if self.is_kw_followed_by_ident(kw::Auto) { self.bump(); // `auto` let msg = "write `let` instead of `auto` to introduce a new variable"; - return self.recover_stmt_local(lo, attrs.into(), msg, "let"); - } - if self.is_kw_followed_by_ident(sym::var) { + self.recover_stmt_local(lo, attrs.into(), msg, "let")? + } else if self.is_kw_followed_by_ident(sym::var) { self.bump(); // `var` let msg = "write `let` instead of `var` to introduce a new variable"; - return self.recover_stmt_local(lo, attrs.into(), msg, "let"); - } - - // Starts like a simple path, being careful to avoid contextual keywords, - // e.g., `union`, items with `crate` visibility, or `auto trait` items. - // We aim to parse an arbitrary path `a::b` but not something that starts like a path - // (1 token), but it fact not a path. Also, we avoid stealing syntax from `parse_item_`. - if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_path_start_item() + self.recover_stmt_local(lo, attrs.into(), msg, "let")? + } else if self.token.is_path_start() + && !self.token.is_qpath_start() + && !self.is_path_start_item() { - return self.parse_stmt_path_start(lo, attrs).map(Some); - } - - if let Some(item) = self.parse_stmt_item(attrs.clone())? { + // We have avoided contextual keywords like `union`, items with `crate` visibility, + // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something + // that starts like a path (1 token), but it fact not a path. + // Also, we avoid stealing syntax from `parse_item_`. + self.parse_stmt_path_start(lo, attrs)? + } else if let Some(item) = self.parse_stmt_item(attrs.clone())? { // FIXME: Bad copy of attrs - return Ok(Some(self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))))); + self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) } - // Do not attempt to parse an expression if we're done here. - if self.token == token::Semi { + else if self.token == token::Semi { self.error_outer_attrs(&attrs); self.bump(); let mut last_semi = lo; @@ -82,17 +76,16 @@ impl<'a> Parser<'a> { ExprKind::Tup(Vec::new()), AttrVec::new(), )); - return Ok(Some(self.mk_stmt(lo.to(last_semi), kind))); - } - - if self.token == token::CloseDelim(token::Brace) { + self.mk_stmt(lo.to(last_semi), kind) + } else if self.token != token::CloseDelim(token::Brace) { + // Remainder are line-expr stmts. + let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; + self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) + } else { self.error_outer_attrs(&attrs); return Ok(None); - } - - // Remainder are line-expr stmts. - let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; - Ok(Some(self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)))) + }; + Ok(Some(stmt)) } fn parse_stmt_item(&mut self, attrs: Vec) -> PResult<'a, Option> { @@ -168,12 +161,12 @@ impl<'a> Parser<'a> { attrs: AttrVec, msg: &str, sugg: &str, - ) -> PResult<'a, Option> { + ) -> PResult<'a, Stmt> { let stmt = self.parse_local_mk(lo, attrs)?; self.struct_span_err(lo, "invalid variable declaration") .span_suggestion(lo, msg, sugg.to_string(), Applicability::MachineApplicable) .emit(); - Ok(Some(stmt)) + Ok(stmt) } fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> { From 1eb0844f5d4321a7769238af740e6d93d3e966e4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 25 Feb 2020 00:59:39 +0100 Subject: [PATCH 15/18] parse: move condition into guard --- src/librustc_parse/parser/stmt.rs | 56 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index a1078a59239c7..b7bf99e6e1603 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -366,36 +366,36 @@ impl<'a> Parser<'a> { let mut eat_semi = true; match stmt.kind { - StmtKind::Expr(ref expr) if self.token != token::Eof => { - // expression without semicolon - if classify::expr_requires_semi_to_be_stmt(expr) { - // Just check for errors and recover; do not eat semicolon yet. - if let Err(mut e) = - self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)]) - { - if let TokenKind::DocComment(..) = self.token.kind { - if let Ok(snippet) = self.span_to_snippet(self.token.span) { - let sp = self.token.span; - let marker = &snippet[..3]; - let (comment_marker, doc_comment_marker) = marker.split_at(2); - - e.span_suggestion( - sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), - &format!( - "add a space before `{}` to use a regular comment", - doc_comment_marker, - ), - format!("{} {}", comment_marker, doc_comment_marker), - Applicability::MaybeIncorrect, - ); - } + // Expression without semicolon. + StmtKind::Expr(ref expr) + if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => + { + // Just check for errors and recover; do not eat semicolon yet. + if let Err(mut e) = + self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)]) + { + if let TokenKind::DocComment(..) = self.token.kind { + if let Ok(snippet) = self.span_to_snippet(self.token.span) { + let sp = self.token.span; + let marker = &snippet[..3]; + let (comment_marker, doc_comment_marker) = marker.split_at(2); + + e.span_suggestion( + sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), + &format!( + "add a space before `{}` to use a regular comment", + doc_comment_marker, + ), + format!("{} {}", comment_marker, doc_comment_marker), + Applicability::MaybeIncorrect, + ); } - e.emit(); - self.recover_stmt(); - // Don't complain about type errors in body tail after parse error (#57383). - let sp = expr.span.to(self.prev_span); - stmt.kind = StmtKind::Expr(self.mk_expr_err(sp)); } + e.emit(); + self.recover_stmt(); + // Don't complain about type errors in body tail after parse error (#57383). + let sp = expr.span.to(self.prev_span); + stmt.kind = StmtKind::Expr(self.mk_expr_err(sp)); } } StmtKind::Local(..) => { From 7876711b9be1673631c4aaea63c289a984afbb0b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 25 Feb 2020 06:00:47 +0100 Subject: [PATCH 16/18] parse: address nitpick --- src/librustc_parse/parser/stmt.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index b7bf99e6e1603..d2a6f0b7fcf0c 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -59,9 +59,8 @@ impl<'a> Parser<'a> { } else if let Some(item) = self.parse_stmt_item(attrs.clone())? { // FIXME: Bad copy of attrs self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) - } - // Do not attempt to parse an expression if we're done here. - else if self.token == token::Semi { + } else if self.token == token::Semi { + // Do not attempt to parse an expression if we're done here. self.error_outer_attrs(&attrs); self.bump(); let mut last_semi = lo; From f56042fb3c9821309fc4e8f311a8396bea83d137 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 25 Feb 2020 13:28:40 +0100 Subject: [PATCH 17/18] Clean up E0370 explanation --- src/librustc_error_codes/error_codes/E0370.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0370.md b/src/librustc_error_codes/error_codes/E0370.md index a3d280fc6dccc..14e954722a250 100644 --- a/src/librustc_error_codes/error_codes/E0370.md +++ b/src/librustc_error_codes/error_codes/E0370.md @@ -1,5 +1,7 @@ The maximum value of an enum was reached, so it cannot be automatically -set in the next enum value. Erroneous code example: +set in the next enum value. + +Erroneous code example: ```compile_fail,E0370 #[repr(i64)] From d6f83c541d3bfc6116971249e907889e22129514 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 25 Feb 2020 13:28:47 +0100 Subject: [PATCH 18/18] Clean up E0371 explanation --- src/librustc_error_codes/error_codes/E0371.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0371.md b/src/librustc_error_codes/error_codes/E0371.md index 9363cddb1dd47..a44721346e20d 100644 --- a/src/librustc_error_codes/error_codes/E0371.md +++ b/src/librustc_error_codes/error_codes/E0371.md @@ -1,9 +1,6 @@ -When `Trait2` is a subtrait of `Trait1` (for example, when `Trait2` has a -definition like `trait Trait2: Trait1 { ... }`), it is not allowed to implement -`Trait1` for `Trait2`. This is because `Trait2` already implements `Trait1` by -definition, so it is not useful to do this. +A trait was implemented on another which already automatically implemented it. -Example: +Erroneous code examples: ```compile_fail,E0371 trait Foo { fn foo(&self) { } } @@ -15,3 +12,8 @@ impl Foo for Baz { } // error, `Baz` implements `Bar` which implements `Foo` impl Baz for Baz { } // error, `Baz` (trivially) implements `Baz` impl Baz for Bar { } // Note: This is OK ``` + +When `Trait2` is a subtrait of `Trait1` (for example, when `Trait2` has a +definition like `trait Trait2: Trait1 { ... }`), it is not allowed to implement +`Trait1` for `Trait2`. This is because `Trait2` already implements `Trait1` by +definition, so it is not useful to do this.