diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 8b8bda2e6b44f..9ebb317641875 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 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 + /// 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 = "69099")] + pub fn leak(orig: Ref<'b, T>) -> &'b T { + // 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 + } } #[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 = "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, + // making the current borrow the only reference for the remaining lifetime. + mem::forget(orig.borrow); + orig.value + } } struct BorrowRefMut<'b> { diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 43f8cfc0c473f..49ace698bbd0e 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 @@ -1525,7 +1526,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/lib.rs b/src/libcore/lib.rs index bca96b77812c8..7bd1d00e84ca1 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -267,6 +267,9 @@ mod bool; mod tuple; mod unit; +#[stable(feature = "core_primitive", since = "1.43.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..e20b2c5c9382a --- /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.43.0")] +pub use bool; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use char; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use f32; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use f64; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use i128; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use i16; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use i32; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use i64; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use i8; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use isize; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use str; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use u128; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use u16; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use u32; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use u64; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use u8; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use usize; diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 88b490a25d5dd..3d41a158b6d85 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")] @@ -392,6 +392,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; @@ -619,6 +623,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() @@ -712,6 +717,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() @@ -804,6 +810,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) } @@ -896,6 +903,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); } @@ -967,6 +975,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) } @@ -1035,6 +1044,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); } 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_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 2b223d92ff198..3431c1b8e9d42 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,14 +281,11 @@ 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()), - // 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 +321,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 +363,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) } @@ -819,7 +774,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_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_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_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)] 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. 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_hir/print.rs b/src/librustc_hir/print.rs index c9faa299d372e..3fde04c294ef2 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_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_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, 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, }, ); 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); } } } 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 5b2e5a9e454ea..d7d6fcd05b795 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/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index bbfbe9c20df94..d2a6f0b7fcf0c 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -35,61 +35,32 @@ 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() { - 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)))); - } - - // 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 { - return Ok(Some(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 { + // 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 + self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) + } 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; @@ -104,27 +75,49 @@ 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); + }; + Ok(Some(stmt)) + } + + 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); } - // 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)))) + 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 +138,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. @@ -167,12 +160,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> { @@ -372,36 +365,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(..) => { 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 diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 799585ffc0acf..7b3c702b929c0 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)] @@ -551,6 +551,9 @@ pub use core::{ trace_macros, }; +#[stable(feature = "core_primitive", since = "1.43.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/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/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::()); } 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() {} diff --git a/src/test/ui/resolve/resolve-primitive-fallback.stderr b/src/test/ui/resolve/resolve-primitive-fallback.stderr index 6d61d2f16cafa..9d381a8a94e3f 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 arguments but 1 argument 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() {}